2006-09-19 21:28:00 +04:00
/*
* QLogic iSCSI HBA Driver
2010-12-03 09:12:51 +03:00
* Copyright ( c ) 2003 - 2010 QLogic Corporation
2006-09-19 21:28:00 +04:00
*
* See LICENSE . qla4xxx for copyright and licensing details .
*/
2007-12-13 21:43:29 +03:00
# include <scsi/iscsi_if.h>
2006-09-19 21:28:00 +04:00
# include "ql4_def.h"
2007-05-24 04:55:40 +04:00
# include "ql4_glbl.h"
# include "ql4_dbg.h"
# include "ql4_inline.h"
2006-09-19 21:28:00 +04:00
2010-07-28 14:23:44 +04:00
static struct ddb_entry * qla4xxx_alloc_ddb ( struct scsi_qla_host * ha ,
uint32_t fw_ddb_index ) ;
2006-09-19 21:28:00 +04: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
*
* This routine deallocates and unlinks the specified ddb_entry from the
* adapter ' s
* */
2010-07-28 14:23:44 +04:00
void qla4xxx_free_ddb ( struct scsi_qla_host * ha ,
struct ddb_entry * ddb_entry )
2006-09-19 21:28:00 +04:00
{
/* Remove device entry from list */
list_del_init ( & ddb_entry - > list ) ;
/* 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 - - ;
/* Free memory and scsi-ml struct for device entry */
qla4xxx_destroy_sess ( ddb_entry ) ;
}
/**
* qla4xxx_free_ddb_list - deallocate all ddbs
* @ ha : pointer to host adapter structure .
*
* This routine deallocates and removes all devices on the sppecified adapter .
* */
void qla4xxx_free_ddb_list ( struct scsi_qla_host * ha )
{
struct list_head * ptr ;
struct ddb_entry * ddb_entry ;
while ( ! list_empty ( & ha - > ddb_list ) ) {
ptr = ha - > ddb_list . next ;
/* Free memory for device entry and remove */
ddb_entry = list_entry ( ptr , struct ddb_entry , list ) ;
qla4xxx_free_ddb ( ha , ddb_entry ) ;
}
}
2010-07-28 14:23:44 +04:00
/**
* 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 21:28:00 +04: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 ;
/* 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 14:23:44 +04:00
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 21:28:00 +04:00
2010-07-28 14:23:44 +04:00
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 21:28:00 +04:00
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
return QLA_SUCCESS ;
}
/**
2010-07-28 14:23:44 +04:00
* qla4xxx_get_sys_info - validate adapter MAC address ( es )
2006-09-19 21:28:00 +04:00
* @ ha : pointer to host adapter structure .
*
* */
2010-07-28 14:23:44 +04:00
int qla4xxx_get_sys_info ( struct scsi_qla_host * ha )
2006-09-19 21:28:00 +04: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 14:23:44 +04:00
goto exit_get_sys_info_no_free ;
2006-09-19 21:28:00 +04: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 14:23:44 +04:00
goto exit_get_sys_info ;
2006-09-19 21:28:00 +04: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 14:23:44 +04:00
exit_get_sys_info :
2006-09-19 21:28:00 +04:00
dma_free_coherent ( & ha - > pdev - > dev , sizeof ( * sys_info ) , sys_info ,
sys_info_dma ) ;
2010-07-28 14:23:44 +04:00
exit_get_sys_info_no_free :
2006-09-19 21:28:00 +04: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 14:17:00 +04:00
/* Initialize aen queue */
2006-09-19 21:28:00 +04:00
ha - > aen_q_count = MAX_AEN_ENTRIES ;
return qla4xxx_get_firmware_status ( ha ) ;
}
2010-04-28 10:07:07 +04:00
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 ;
}
if ( ( ( ha - > ipv6_addl_options &
IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE ) ! = 0 ) & &
( ( ha - > ipv6_link_local_state = = IP_ADDRSTATE_ACQUIRING ) | |
( ha - > ipv6_addr0_state = = IP_ADDRSTATE_ACQUIRING ) | |
( ha - > ipv6_addr1_state = = IP_ADDRSTATE_ACQUIRING ) ) ) {
ipv6_wait = 1 ;
if ( ( ha - > ipv6_link_local_state = =
IP_ADDRSTATE_PREFERRED ) | |
( ha - > ipv6_addr0_state = = IP_ADDRSTATE_PREFERRED ) | |
( ha - > ipv6_addr1_state = = IP_ADDRSTATE_PREFERRED ) ) {
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: "
" Preferred IP configured. "
" Don't wait! \n " , ha - > host_no ,
__func__ ) ) ;
ipv6_wait = 0 ;
}
if ( memcmp ( & ha - > ipv6_default_router_addr , ip_address ,
IPv6_ADDR_LEN ) = = 0 ) {
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: "
" No Router configured. "
" Don't wait! \n " , ha - > host_no ,
__func__ ) ) ;
ipv6_wait = 0 ;
}
if ( ( ha - > ipv6_default_router_state = =
IPV6_RTRSTATE_MANUAL ) & &
( ha - > ipv6_link_local_state = =
IP_ADDRSTATE_TENTATIVE ) & &
( memcmp ( & ha - > ipv6_link_local_addr ,
& ha - > ipv6_default_router_addr , 4 ) = = 0 ) ) {
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 " ) ) ;
if ( ha - > ipv6_link_local_state = = IP_ADDRSTATE_ACQUIRING )
DEBUG2 ( printk ( " IPv6LinkLocal " ) ) ;
if ( ha - > ipv6_addr0_state = = IP_ADDRSTATE_ACQUIRING )
DEBUG2 ( printk ( " IPv6Addr0 " ) ) ;
if ( ha - > ipv6_addr1_state = = IP_ADDRSTATE_ACQUIRING )
DEBUG2 ( printk ( " IPv6Addr1 " ) ) ;
DEBUG2 ( printk ( " \" \n " ) ) ;
}
}
return ipv4_wait | ipv6_wait ;
}
2006-09-19 21:28:00 +04:00
static int qla4xxx_fw_ready ( struct scsi_qla_host * ha )
{
uint32_t timeout_count ;
int ready = 0 ;
2010-07-10 13:21:02 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Waiting for Firmware Ready.. \n " ) ) ;
2006-09-19 21:28:00 +04: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 10:07:07 +04:00
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 21:28:00 +04:00
if ( ha - > firmware_state = = FW_STATE_READY ) {
2010-04-28 10:07:07 +04:00
/* 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 13:21:02 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" Firmware Ready.. \n " ) ) ;
2010-04-28 10:07:07 +04:00
/* The firmware is ready to process SCSI
commands . */
2010-07-10 13:21:02 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
2010-04-28 10:07:07 +04:00
" 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 13:21:02 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
2010-04-28 10:07:07 +04:00
" 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 13:21:02 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
2010-04-28 10:07:07 +04:00
" scsi%ld: %s: LINK %s \n " ,
ha - > host_no , __func__ ,
( ha - > addl_fw_state &
FW_ADDSTATE_LINK_UP ) ! = 0 ?
" UP " : " DOWN " ) ) ;
2010-07-10 13:21:02 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
2010-04-28 10:07:07 +04:00
" 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 21:28:00 +04: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-16 04:38:40 +03:00
if ( is_qla4032 ( ha ) & &
! ( ha - > addl_fw_state & FW_ADDSTATE_LINK_UP ) & &
( timeout_count < ADAPTER_INIT_TOV - 5 ) ) {
break ;
}
2006-09-19 21:28:00 +04:00
msleep ( 1000 ) ;
} /* end of for */
2010-04-28 10:07:07 +04:00
if ( timeout_count < = 0 )
2006-09-19 21:28:00 +04:00
DEBUG2 ( printk ( " scsi%ld: %s: FW Initialization timed out! \n " ,
ha - > host_no , __func__ ) ) ;
2010-04-28 10:07:07 +04:00
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 21:28:00 +04:00
ready = 1 ;
2010-04-28 10:07:07 +04:00
} 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 13:19:19 +04:00
ready = 1 ;
2006-09-19 21:28:00 +04: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 13:08:47 +04:00
if ( is_aer_supported ( ha ) & &
test_bit ( AF_PCI_CHANNEL_IO_PERM_FAILURE , & ha - > flags ) )
return status ;
2010-07-30 12:56:31 +04:00
/* 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 13:21:02 +04:00
ql4_printk ( KERN_INFO , ha , " Initializing firmware.. \n " ) ;
2006-09-19 21:28:00 +04: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 ) ;
}
static struct ddb_entry * qla4xxx_get_ddb_entry ( struct scsi_qla_host * ha ,
2007-05-24 04:55:40 +04:00
uint32_t fw_ddb_index ,
uint32_t * new_tgt )
2006-09-19 21:28:00 +04:00
{
struct dev_db_entry * fw_ddb_entry = NULL ;
dma_addr_t fw_ddb_entry_dma ;
struct ddb_entry * ddb_entry = NULL ;
int found = 0 ;
uint32_t device_state ;
2007-05-24 04:55:40 +04:00
* new_tgt = 0 ;
2006-09-19 21:28:00 +04:00
/* Make sure the dma buffer is valid */
fw_ddb_entry = dma_alloc_coherent ( & ha - > pdev - > dev ,
sizeof ( * fw_ddb_entry ) ,
& fw_ddb_entry_dma , GFP_KERNEL ) ;
if ( fw_ddb_entry = = NULL ) {
DEBUG2 ( printk ( " scsi%ld: %s: Unable to allocate dma buffer. \n " ,
ha - > host_no , __func__ ) ) ;
2010-07-10 13:19:38 +04:00
goto exit_get_ddb_entry_no_free ;
2006-09-19 21:28:00 +04:00
}
if ( qla4xxx_get_fwddb_entry ( ha , fw_ddb_index , fw_ddb_entry ,
fw_ddb_entry_dma , NULL , NULL ,
& device_state , NULL , NULL , NULL ) = =
2010-07-10 13:19:38 +04:00
QLA_ERROR ) {
2006-09-19 21:28:00 +04:00
DEBUG2 ( printk ( " scsi%ld: %s: failed get_ddb_entry for "
" fw_ddb_index %d \n " , ha - > host_no , __func__ ,
fw_ddb_index ) ) ;
2010-07-10 13:19:38 +04:00
goto exit_get_ddb_entry ;
2006-09-19 21:28:00 +04:00
}
/* Allocate DDB if not already allocated. */
DEBUG2 ( printk ( " scsi%ld: %s: Looking for ddb[%d] \n " , ha - > host_no ,
__func__ , fw_ddb_index ) ) ;
list_for_each_entry ( ddb_entry , & ha - > ddb_list , list ) {
2009-01-16 21:36:52 +03:00
if ( ( memcmp ( ddb_entry - > iscsi_name , fw_ddb_entry - > iscsi_name ,
ISCSI_NAME_SIZE ) = = 0 ) & &
( ddb_entry - > tpgt = =
le32_to_cpu ( fw_ddb_entry - > tgt_portal_grp ) ) & &
( memcmp ( ddb_entry - > isid , fw_ddb_entry - > isid ,
sizeof ( ddb_entry - > isid ) ) = = 0 ) ) {
2006-09-19 21:28:00 +04:00
found + + ;
break ;
}
}
2010-07-10 13:19:38 +04:00
/* if not found allocate new ddb */
2006-09-19 21:28:00 +04:00
if ( ! found ) {
DEBUG2 ( printk ( " scsi%ld: %s: ddb[%d] not found - allocating "
" new ddb \n " , ha - > host_no , __func__ ,
fw_ddb_index ) ) ;
2007-05-24 04:55:40 +04:00
* new_tgt = 1 ;
2006-09-19 21:28:00 +04:00
ddb_entry = qla4xxx_alloc_ddb ( ha , fw_ddb_index ) ;
}
2010-07-10 13:19:38 +04:00
exit_get_ddb_entry :
2006-09-19 21:28:00 +04:00
dma_free_coherent ( & ha - > pdev - > dev , sizeof ( * fw_ddb_entry ) , fw_ddb_entry ,
fw_ddb_entry_dma ) ;
2010-07-10 13:19:38 +04:00
exit_get_ddb_entry_no_free :
2006-09-19 21:28:00 +04:00
return ddb_entry ;
}
/**
* qla4xxx_update_ddb_entry - update driver ' s internal ddb
* @ ha : pointer to host adapter structure .
* @ ddb_entry : pointer to device database structure to be filled
* @ fw_ddb_index : index of the ddb entry in fw ddb table
*
* This routine updates the driver ' s internal device database entry
* with information retrieved from the firmware ' s device database
* entry for the specified device . The ddb_entry - > fw_ddb_index field
* must be initialized prior to calling this routine
*
* */
2007-04-26 11:35:16 +04:00
static int qla4xxx_update_ddb_entry ( struct scsi_qla_host * ha ,
struct ddb_entry * ddb_entry ,
uint32_t fw_ddb_index )
2006-09-19 21:28:00 +04:00
{
struct dev_db_entry * fw_ddb_entry = NULL ;
dma_addr_t fw_ddb_entry_dma ;
int status = QLA_ERROR ;
2010-04-28 10:11:21 +04:00
uint32_t conn_err ;
2006-09-19 21:28:00 +04:00
if ( ddb_entry = = NULL ) {
DEBUG2 ( printk ( " scsi%ld: %s: ddb_entry is NULL \n " , ha - > host_no ,
__func__ ) ) ;
2010-07-10 13:19:38 +04:00
goto exit_update_ddb_no_free ;
2006-09-19 21:28:00 +04:00
}
/* Make sure the dma buffer is valid */
fw_ddb_entry = dma_alloc_coherent ( & ha - > pdev - > dev ,
sizeof ( * fw_ddb_entry ) ,
& fw_ddb_entry_dma , GFP_KERNEL ) ;
if ( fw_ddb_entry = = NULL ) {
DEBUG2 ( printk ( " scsi%ld: %s: Unable to allocate dma buffer. \n " ,
ha - > host_no , __func__ ) ) ;
2010-07-10 13:19:38 +04:00
goto exit_update_ddb_no_free ;
2006-09-19 21:28:00 +04:00
}
if ( qla4xxx_get_fwddb_entry ( ha , fw_ddb_index , fw_ddb_entry ,
fw_ddb_entry_dma , NULL , NULL ,
2010-04-28 10:11:21 +04:00
& ddb_entry - > fw_ddb_device_state , & conn_err ,
2006-09-19 21:28:00 +04:00
& ddb_entry - > tcp_source_port_num ,
& ddb_entry - > connection_id ) = =
2010-07-10 13:19:38 +04:00
QLA_ERROR ) {
2006-09-19 21:28:00 +04:00
DEBUG2 ( printk ( " scsi%ld: %s: failed get_ddb_entry for "
" fw_ddb_index %d \n " , ha - > host_no , __func__ ,
fw_ddb_index ) ) ;
goto exit_update_ddb ;
}
status = QLA_SUCCESS ;
2010-04-28 10:07:07 +04:00
ddb_entry - > options = le16_to_cpu ( fw_ddb_entry - > options ) ;
2007-05-24 04:55:40 +04:00
ddb_entry - > target_session_id = le16_to_cpu ( fw_ddb_entry - > tsid ) ;
2006-09-19 21:28:00 +04:00
ddb_entry - > task_mgmt_timeout =
2007-05-24 04:55:40 +04:00
le16_to_cpu ( fw_ddb_entry - > def_timeout ) ;
2006-09-19 21:28:00 +04:00
ddb_entry - > CmdSn = 0 ;
2007-05-24 04:55:40 +04:00
ddb_entry - > exe_throttle = le16_to_cpu ( fw_ddb_entry - > exec_throttle ) ;
2006-09-19 21:28:00 +04:00
ddb_entry - > default_relogin_timeout =
2007-05-24 04:55:40 +04:00
le16_to_cpu ( fw_ddb_entry - > def_timeout ) ;
ddb_entry - > default_time2wait = le16_to_cpu ( fw_ddb_entry - > iscsi_def_time2wait ) ;
2006-09-19 21:28:00 +04:00
/* Update index in case it changed */
ddb_entry - > fw_ddb_index = fw_ddb_index ;
ha - > fw_ddb_index_map [ fw_ddb_index ] = ddb_entry ;
2007-05-24 04:55:40 +04:00
ddb_entry - > port = le16_to_cpu ( fw_ddb_entry - > port ) ;
ddb_entry - > tpgt = le32_to_cpu ( fw_ddb_entry - > tgt_portal_grp ) ;
2009-01-16 21:36:52 +03:00
memcpy ( ddb_entry - > isid , fw_ddb_entry - > isid , sizeof ( ddb_entry - > isid ) ) ;
2007-05-24 04:55:40 +04:00
memcpy ( & ddb_entry - > iscsi_name [ 0 ] , & fw_ddb_entry - > iscsi_name [ 0 ] ,
2006-09-19 21:28:00 +04:00
min ( sizeof ( ddb_entry - > iscsi_name ) ,
2007-05-24 04:55:40 +04:00
sizeof ( fw_ddb_entry - > iscsi_name ) ) ) ;
2010-07-10 13:21:30 +04:00
memcpy ( & ddb_entry - > iscsi_alias [ 0 ] , & fw_ddb_entry - > iscsi_alias [ 0 ] ,
min ( sizeof ( ddb_entry - > iscsi_alias ) ,
sizeof ( fw_ddb_entry - > iscsi_alias ) ) ) ;
2007-05-24 04:55:40 +04:00
memcpy ( & ddb_entry - > ip_addr [ 0 ] , & fw_ddb_entry - > ip_addr [ 0 ] ,
min ( sizeof ( ddb_entry - > ip_addr ) , sizeof ( fw_ddb_entry - > ip_addr ) ) ) ;
2006-09-19 21:28:00 +04:00
2010-04-28 10:07:07 +04:00
ddb_entry - > iscsi_max_burst_len = fw_ddb_entry - > iscsi_max_burst_len ;
ddb_entry - > iscsi_max_outsnd_r2t = fw_ddb_entry - > iscsi_max_outsnd_r2t ;
ddb_entry - > iscsi_first_burst_len = fw_ddb_entry - > iscsi_first_burst_len ;
ddb_entry - > iscsi_max_rcv_data_seg_len =
fw_ddb_entry - > iscsi_max_rcv_data_seg_len ;
ddb_entry - > iscsi_max_snd_data_seg_len =
fw_ddb_entry - > iscsi_max_snd_data_seg_len ;
if ( ddb_entry - > options & DDB_OPT_IPV6_DEVICE ) {
memcpy ( & ddb_entry - > remote_ipv6_addr ,
fw_ddb_entry - > ip_addr ,
min ( sizeof ( ddb_entry - > remote_ipv6_addr ) ,
sizeof ( fw_ddb_entry - > ip_addr ) ) ) ;
memcpy ( & ddb_entry - > link_local_ipv6_addr ,
fw_ddb_entry - > link_local_ipv6_addr ,
min ( sizeof ( ddb_entry - > link_local_ipv6_addr ) ,
sizeof ( fw_ddb_entry - > link_local_ipv6_addr ) ) ) ;
2006-09-19 21:28:00 +04:00
2010-07-28 14:23:44 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " %s: DDB[%d] State %04x "
" ConnErr %08x IP %pI6 "
2010-04-28 10:11:21 +04:00
" :%04d \" %s \" \n " ,
__func__ , fw_ddb_index ,
ddb_entry - > fw_ddb_device_state ,
conn_err , fw_ddb_entry - > ip_addr ,
le16_to_cpu ( fw_ddb_entry - > port ) ,
fw_ddb_entry - > iscsi_name ) ) ;
} else
2010-07-28 14:23:44 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " %s: DDB[%d] State %04x "
" ConnErr %08x IP %pI4 "
2010-04-28 10:11:21 +04:00
" :%04d \" %s \" \n " ,
__func__ , fw_ddb_index ,
ddb_entry - > fw_ddb_device_state ,
conn_err , fw_ddb_entry - > ip_addr ,
le16_to_cpu ( fw_ddb_entry - > port ) ,
fw_ddb_entry - > iscsi_name ) ) ;
2010-04-28 10:07:07 +04:00
exit_update_ddb :
2006-09-19 21:28:00 +04:00
if ( fw_ddb_entry )
dma_free_coherent ( & ha - > pdev - > dev , sizeof ( * fw_ddb_entry ) ,
fw_ddb_entry , fw_ddb_entry_dma ) ;
2010-07-10 13:19:38 +04:00
exit_update_ddb_no_free :
2006-09-19 21:28:00 +04:00
return status ;
}
/**
* qla4xxx_alloc_ddb - allocate device database entry
* @ ha : Pointer to host adapter structure .
* @ fw_ddb_index : Firmware ' s device database index
*
* This routine allocates a ddb_entry , ititializes some values , and
* inserts it into the ddb list .
* */
2007-04-26 11:35:16 +04:00
static struct ddb_entry * qla4xxx_alloc_ddb ( struct scsi_qla_host * ha ,
uint32_t fw_ddb_index )
2006-09-19 21:28:00 +04:00
{
struct ddb_entry * ddb_entry ;
DEBUG2 ( printk ( " scsi%ld: %s: fw_ddb_index [%d] \n " , ha - > host_no ,
__func__ , fw_ddb_index ) ) ;
ddb_entry = qla4xxx_alloc_sess ( ha ) ;
if ( ddb_entry = = NULL ) {
DEBUG2 ( printk ( " scsi%ld: %s: Unable to allocate memory "
" to add fw_ddb_index [%d] \n " ,
ha - > host_no , __func__ , fw_ddb_index ) ) ;
return ddb_entry ;
}
ddb_entry - > fw_ddb_index = fw_ddb_index ;
atomic_set ( & ddb_entry - > retry_relogin_timer , INVALID_ENTRY ) ;
atomic_set ( & ddb_entry - > relogin_timer , 0 ) ;
atomic_set ( & ddb_entry - > relogin_retry_count , 0 ) ;
atomic_set ( & ddb_entry - > state , DDB_STATE_ONLINE ) ;
list_add_tail ( & ddb_entry - > list , & ha - > ddb_list ) ;
ha - > fw_ddb_index_map [ fw_ddb_index ] = ddb_entry ;
ha - > tot_ddbs + + ;
return ddb_entry ;
}
2010-04-28 10:11:21 +04:00
/**
* qla4_is_relogin_allowed - Are we allowed to login ?
* @ ha : Pointer to host adapter structure .
* @ conn_err : Last connection error associated with the ddb
*
* This routine tests the given connection error to determine if
* we are allowed to login .
* */
int qla4_is_relogin_allowed ( struct scsi_qla_host * ha , uint32_t conn_err )
{
uint32_t err_code , login_rsp_sts_class ;
int relogin = 1 ;
err_code = ( ( conn_err & 0x00ff0000 ) > > 16 ) ;
login_rsp_sts_class = ( ( conn_err & 0x0000ff00 ) > > 8 ) ;
if ( err_code = = 0x1c | | err_code = = 0x06 ) {
2010-07-10 13:21:02 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" : conn_err=0x%08x, send target completed "
" or access denied failure \n " , conn_err ) ) ;
2010-04-28 10:11:21 +04:00
relogin = 0 ;
}
if ( ( err_code = = 0x08 ) & & ( login_rsp_sts_class = = 0x02 ) ) {
/* Login Response PDU returned an error.
Login Response Status in Error Code Detail
indicates login should not be retried . */
2010-07-10 13:21:02 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" : conn_err=0x%08x, do not retry relogin \n " ,
conn_err ) ) ;
2010-04-28 10:11:21 +04:00
relogin = 0 ;
}
return relogin ;
}
2011-03-21 13:34:27 +03:00
static void qla4xxx_flush_AENS ( struct scsi_qla_host * ha )
{
unsigned long wtime ;
/* Flush the 0x8014 AEN from the firmware as a result of
* Auto connect . We are basically doing get_firmware_ddb ( )
* to determine whether we need to log back in or not .
* Trying to do a set ddb before we have processed 0x8014
* will result in another set_ddb ( ) for the same ddb . In other
* words there will be stale entries in the aen_q .
*/
wtime = jiffies + ( 2 * HZ ) ;
do {
if ( qla4xxx_get_firmware_state ( ha ) = = QLA_SUCCESS )
if ( ha - > firmware_state & ( BIT_2 | BIT_0 ) )
return ;
if ( test_and_clear_bit ( DPC_AEN , & ha - > dpc_flags ) )
qla4xxx_process_aen ( ha , FLUSH_DDB_CHANGED_AENS ) ;
msleep ( 1000 ) ;
} while ( ! time_after_eq ( jiffies , wtime ) ) ;
}
2006-09-19 21:28:00 +04:00
/**
2011-03-21 13:34:27 +03:00
* qla4xxx_build_ddb_list - builds driver ddb list
2006-09-19 21:28:00 +04:00
* @ ha : Pointer to host adapter structure .
*
* This routine searches for all valid firmware ddb entries and builds
* an internal ddb list . Ddbs that are considered valid are those with
* a device state of SESSION_ACTIVE .
2011-03-21 13:34:27 +03:00
* A relogin ( set_ddb ) is issued for DDBs that are not online .
2006-09-19 21:28:00 +04:00
* */
static int qla4xxx_build_ddb_list ( struct scsi_qla_host * ha )
{
2010-07-10 13:19:38 +04:00
int status = QLA_ERROR ;
2006-09-19 21:28:00 +04:00
uint32_t fw_ddb_index = 0 ;
uint32_t next_fw_ddb_index = 0 ;
uint32_t ddb_state ;
2010-04-28 10:11:21 +04:00
uint32_t conn_err ;
2006-09-19 21:28:00 +04:00
struct ddb_entry * ddb_entry ;
2010-04-28 10:11:21 +04:00
struct dev_db_entry * fw_ddb_entry = NULL ;
dma_addr_t fw_ddb_entry_dma ;
uint32_t ipv6_device ;
2007-05-24 04:55:40 +04:00
uint32_t new_tgt ;
2006-09-19 21:28:00 +04:00
2011-03-21 13:34:27 +03:00
qla4xxx_flush_AENS ( ha ) ;
2010-04-28 10:11:21 +04:00
fw_ddb_entry = dma_alloc_coherent ( & ha - > pdev - > dev , sizeof ( * fw_ddb_entry ) ,
& fw_ddb_entry_dma , GFP_KERNEL ) ;
if ( fw_ddb_entry = = NULL ) {
2010-07-10 13:21:02 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " %s: DMA alloc failed \n " ,
2010-04-28 10:11:21 +04:00
__func__ ) ) ;
2010-07-10 13:19:38 +04:00
goto exit_build_ddb_list_no_free ;
2010-04-28 10:11:21 +04:00
}
2010-07-10 13:21:02 +04:00
ql4_printk ( KERN_INFO , ha , " Initializing DDBs ... \n " ) ;
2006-09-19 21:28:00 +04:00
for ( fw_ddb_index = 0 ; fw_ddb_index < MAX_DDB_ENTRIES ;
fw_ddb_index = next_fw_ddb_index ) {
/* First, let's see if a device exists here */
2010-04-28 10:11:21 +04:00
if ( qla4xxx_get_fwddb_entry ( ha , fw_ddb_index , fw_ddb_entry ,
0 , NULL , & next_fw_ddb_index ,
& ddb_state , & conn_err ,
NULL , NULL ) = =
QLA_ERROR ) {
2006-09-19 21:28:00 +04:00
DEBUG2 ( printk ( " scsi%ld: %s: get_ddb_entry, "
" fw_ddb_index %d failed " , ha - > host_no ,
__func__ , fw_ddb_index ) ) ;
2010-07-10 13:19:38 +04:00
goto exit_build_ddb_list ;
2006-09-19 21:28:00 +04:00
}
DEBUG2 ( printk ( " scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, "
" next_fw_ddb_index=%d. \n " , ha - > host_no , __func__ ,
fw_ddb_index , ddb_state , next_fw_ddb_index ) ) ;
/* Issue relogin, if necessary. */
if ( ddb_state = = DDB_DS_SESSION_FAILED | |
ddb_state = = DDB_DS_NO_CONNECTION_ACTIVE ) {
/* Try and login to device */
DEBUG2 ( printk ( " scsi%ld: %s: Login to DDB[%d] \n " ,
ha - > host_no , __func__ , fw_ddb_index ) ) ;
2010-04-28 10:11:21 +04:00
ipv6_device = le16_to_cpu ( fw_ddb_entry - > options ) &
DDB_OPT_IPV6_DEVICE ;
if ( qla4_is_relogin_allowed ( ha , conn_err ) & &
( ( ! ipv6_device & &
* ( ( uint32_t * ) fw_ddb_entry - > ip_addr ) )
| | ipv6_device ) ) {
2006-09-19 21:28:00 +04:00
qla4xxx_set_ddb_entry ( ha , fw_ddb_index , 0 ) ;
2007-05-24 04:55:40 +04:00
if ( qla4xxx_get_fwddb_entry ( ha , fw_ddb_index ,
2010-04-28 10:11:21 +04:00
NULL , 0 , NULL ,
& next_fw_ddb_index ,
& ddb_state , & conn_err ,
NULL , NULL )
= = QLA_ERROR ) {
2007-05-24 04:55:40 +04:00
DEBUG2 ( printk ( " scsi%ld: %s: "
" get_ddb_entry %d failed \n " ,
ha - > host_no ,
__func__ , fw_ddb_index ) ) ;
2010-07-10 13:19:38 +04:00
goto exit_build_ddb_list ;
2007-05-24 04:55:40 +04:00
}
}
2006-09-19 21:28:00 +04:00
}
if ( ddb_state ! = DDB_DS_SESSION_ACTIVE )
goto next_one ;
/*
* if fw_ddb with session active state found ,
* add to ddb_list
*/
DEBUG2 ( printk ( " scsi%ld: %s: DDB[%d] added to list \n " ,
ha - > host_no , __func__ , fw_ddb_index ) ) ;
/* Add DDB to internal our ddb list. */
2007-05-24 04:55:40 +04:00
ddb_entry = qla4xxx_get_ddb_entry ( ha , fw_ddb_index , & new_tgt ) ;
2006-09-19 21:28:00 +04:00
if ( ddb_entry = = NULL ) {
DEBUG2 ( printk ( " scsi%ld: %s: Unable to allocate memory "
" for device at fw_ddb_index %d \n " ,
ha - > host_no , __func__ , fw_ddb_index ) ) ;
2010-07-10 13:19:38 +04:00
goto exit_build_ddb_list ;
2006-09-19 21:28:00 +04:00
}
/* Fill in the device structure */
if ( qla4xxx_update_ddb_entry ( ha , ddb_entry , fw_ddb_index ) = =
QLA_ERROR ) {
ha - > fw_ddb_index_map [ fw_ddb_index ] =
( struct ddb_entry * ) INVALID_ENTRY ;
DEBUG2 ( printk ( " scsi%ld: %s: update_ddb_entry failed "
" for fw_ddb_index %d. \n " ,
ha - > host_no , __func__ , fw_ddb_index ) ) ;
2010-07-10 13:19:38 +04:00
goto exit_build_ddb_list ;
2006-09-19 21:28:00 +04:00
}
next_one :
/* We know we've reached the last device when
* next_fw_ddb_index is 0 */
if ( next_fw_ddb_index = = 0 )
break ;
}
2010-07-10 13:19:38 +04:00
status = QLA_SUCCESS ;
2010-07-10 13:21:02 +04:00
ql4_printk ( KERN_INFO , ha , " DDB list done.. \n " ) ;
2006-09-19 21:28:00 +04:00
2010-07-10 13:19:38 +04:00
exit_build_ddb_list :
dma_free_coherent ( & ha - > pdev - > dev , sizeof ( * fw_ddb_entry ) , fw_ddb_entry ,
fw_ddb_entry_dma ) ;
exit_build_ddb_list_no_free :
2006-09-19 21:28:00 +04:00
return status ;
}
static int qla4xxx_initialize_ddb_list ( struct scsi_qla_host * ha )
{
uint16_t fw_ddb_index ;
int status = QLA_SUCCESS ;
/* free the ddb list if is not empty */
if ( ! list_empty ( & ha - > ddb_list ) )
qla4xxx_free_ddb_list ( ha ) ;
for ( fw_ddb_index = 0 ; fw_ddb_index < MAX_DDB_ENTRIES ; fw_ddb_index + + )
ha - > fw_ddb_index_map [ fw_ddb_index ] =
2011-03-21 13:34:27 +03:00
( struct ddb_entry * ) INVALID_ENTRY ;
2006-09-19 21:28:00 +04:00
ha - > tot_ddbs = 0 ;
2011-03-21 13:34:27 +03:00
/* Perform device discovery and build ddb list. */
status = qla4xxx_build_ddb_list ( ha ) ;
2006-09-19 21:28:00 +04:00
return status ;
}
/**
2010-07-28 14:23:44 +04:00
* qla4xxx_reinitialize_ddb_list - update the driver ddb list
2006-09-19 21:28:00 +04:00
* @ ha : pointer to host adapter structure .
*
* This routine obtains device information from the F / W database after
* firmware or adapter resets . The device table is preserved .
* */
int qla4xxx_reinitialize_ddb_list ( struct scsi_qla_host * ha )
{
int status = QLA_SUCCESS ;
struct ddb_entry * ddb_entry , * detemp ;
/* Update the device information for all devices. */
list_for_each_entry_safe ( ddb_entry , detemp , & ha - > ddb_list , list ) {
qla4xxx_update_ddb_entry ( ha , ddb_entry ,
ddb_entry - > fw_ddb_index ) ;
if ( ddb_entry - > fw_ddb_device_state = = DDB_DS_SESSION_ACTIVE ) {
atomic_set ( & ddb_entry - > state , DDB_STATE_ONLINE ) ;
DEBUG2 ( printk ( " scsi%ld: %s: ddb index [%d] marked "
" ONLINE \n " , ha - > host_no , __func__ ,
ddb_entry - > fw_ddb_index ) ) ;
2010-07-10 13:19:01 +04:00
iscsi_unblock_session ( ddb_entry - > sess ) ;
2006-09-19 21:28:00 +04:00
} else if ( atomic_read ( & ddb_entry - > state ) = = DDB_STATE_ONLINE )
qla4xxx_mark_device_missing ( ha , ddb_entry ) ;
}
return status ;
}
/**
* qla4xxx_relogin_device - re - establish session
* @ ha : Pointer to host adapter structure .
* @ ddb_entry : Pointer to device database entry
*
* This routine does a session relogin with the specified device .
* The ddb entry must be assigned prior to making this call .
* */
int qla4xxx_relogin_device ( struct scsi_qla_host * ha ,
struct ddb_entry * ddb_entry )
{
uint16_t relogin_timer ;
relogin_timer = max ( ddb_entry - > default_relogin_timeout ,
( uint16_t ) RELOGIN_TOV ) ;
atomic_set ( & ddb_entry - > relogin_timer , relogin_timer ) ;
2010-07-28 14:23:44 +04:00
DEBUG2 ( printk ( " scsi%ld: Relogin ddb [%d]. TOV=%d \n " , ha - > host_no ,
2006-09-19 21:28:00 +04:00
ddb_entry - > fw_ddb_index , relogin_timer ) ) ;
qla4xxx_set_ddb_entry ( ha , ddb_entry - > fw_ddb_index , 0 ) ;
return QLA_SUCCESS ;
}
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-11 01:51:48 +03:00
return QLA_ERROR ;
2006-09-19 21:28:00 +04:00
if ( ql4xxx_lock_nvram ( ha ) ! = QLA_SUCCESS ) {
ql4xxx_unlock_flash ( ha ) ;
2010-02-11 01:51:48 +03:00
return QLA_ERROR ;
2006-09-19 21:28:00 +04:00
}
/* Get EEPRom Parameters from NVRAM and validate */
2010-07-10 13:21:02 +04:00
ql4_printk ( KERN_INFO , ha , " Configuring NVRAM ... \n " ) ;
2006-09-19 21:28:00 +04: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 13:21:02 +04:00
ql4_printk ( KERN_WARNING , ha ,
" scsi%ld: %s: EEProm checksum invalid. "
" Please update your EEPROM \n " , ha - > host_no ,
__func__ ) ;
2006-09-19 21:28:00 +04:00
2010-02-11 01:51:48 +03:00
/* Attempt to set defaults */
2006-09-19 21:28:00 +04:00
if ( is_qla4010 ( ha ) )
extHwConfig . Asuint32_t = 0x1912 ;
2006-11-16 04:38:40 +03:00
else if ( is_qla4022 ( ha ) | is_qla4032 ( ha ) )
2006-09-19 21:28:00 +04:00
extHwConfig . Asuint32_t = 0x0023 ;
2010-02-11 01:51:48 +03:00
else
return QLA_ERROR ;
2006-09-19 21:28:00 +04: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-11 01:51:48 +03:00
return QLA_SUCCESS ;
2006-09-19 21:28:00 +04:00
}
2010-07-28 14:23:44 +04:00
/**
* 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 21:28:00 +04:00
{
2007-05-24 04:55:40 +04:00
uint16_t w ;
2007-06-09 04:37:16 +04:00
int status ;
2006-09-19 21:28:00 +04:00
2010-07-10 13:21:02 +04:00
ql4_printk ( KERN_INFO , ha , " Configuring PCI space... \n " ) ;
2006-09-19 21:28:00 +04:00
pci_set_master ( ha - > pdev ) ;
2007-06-09 04:37:16 +04:00
status = pci_set_mwi ( ha - > pdev ) ;
2006-09-19 21:28:00 +04: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-24 04:55:40 +04:00
w | = PCI_COMMAND_PARITY | PCI_COMMAND_SERR ;
2006-09-19 21:28:00 +04: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 10:10:37 +04:00
unsigned long max_wait_time ;
2006-09-19 21:28:00 +04:00
unsigned long flags ;
uint32_t mbox_status ;
2010-07-10 13:21:02 +04:00
ql4_printk ( KERN_INFO , ha , " Starting firmware ... \n " ) ;
2006-09-19 21:28:00 +04: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-16 04:38:40 +03:00
if ( is_qla4022 ( ha ) | is_qla4032 ( ha ) )
2006-09-19 21:28:00 +04:00
writel ( set_rmask ( NVR_WRITE_ENABLE ) ,
& ha - > reg - > u1 . isp4022 . nvram ) ;
2007-05-24 04:55:40 +04:00
writel ( 2 , & ha - > reg - > mailbox [ 6 ] ) ;
readl ( & ha - > reg - > mailbox [ 6 ] ) ;
2006-09-19 21:28:00 +04: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 10:10:37 +04:00
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 21:28:00 +04: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 10:10:37 +04:00
DEBUG2 ( printk ( KERN_INFO " scsi%ld: %s: Waiting for boot "
2010-10-07 09:47:48 +04:00
" firmware to complete... ctrl_sts=0x%x, remaining=%ld \n " ,
ha - > host_no , __func__ , ctrl_status , max_wait_time ) ) ;
2006-09-19 21:28:00 +04:00
2010-04-28 10:10:37 +04:00
msleep_interruptible ( 250 ) ;
} while ( ! time_after_eq ( jiffies , max_wait_time ) ) ;
2006-09-19 21:28:00 +04:00
if ( mbox_status = = MBOX_STS_COMMAND_COMPLETE ) {
2010-04-28 10:10:37 +04:00
DEBUG ( printk ( KERN_INFO " scsi%ld: %s: Firmware has started \n " ,
2006-09-19 21:28:00 +04: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-24 04:55:40 +04:00
int ql4xxx_lock_drvr_wait ( struct scsi_qla_host * a )
2006-09-19 21:28:00 +04:00
{
2007-05-24 04:55:40 +04:00
# define QL4_LOCK_DRVR_WAIT 60
2007-01-22 23:26:11 +03:00
# define QL4_LOCK_DRVR_SLEEP 1
2006-09-19 21:28:00 +04:00
int drvr_wait = QL4_LOCK_DRVR_WAIT ;
while ( drvr_wait ) {
2007-05-24 04:55:40 +04:00
if ( ql4xxx_lock_drvr ( a ) = = 0 ) {
2007-01-22 23:26:11 +03:00
ssleep ( QL4_LOCK_DRVR_SLEEP ) ;
2006-09-19 21:28:00 +04:00
if ( drvr_wait ) {
DEBUG2 ( printk ( " scsi%ld: %s: Waiting for "
2007-05-24 04:55:40 +04:00
" Global Init Semaphore(%d)... \n " ,
a - > host_no ,
2007-01-22 23:26:11 +03:00
__func__ , drvr_wait ) ) ;
2006-09-19 21:28:00 +04:00
}
drvr_wait - = QL4_LOCK_DRVR_SLEEP ;
} else {
DEBUG2 ( printk ( " scsi%ld: %s: Global Init Semaphore "
2007-05-24 04:55:40 +04:00
" acquired \n " , a - > host_no , __func__ ) ) ;
2006-09-19 21:28:00 +04:00
return QLA_SUCCESS ;
}
}
return QLA_ERROR ;
}
/**
* qla4xxx_start_firmware - starts qla4xxx firmware
* @ ha : Pointer to host adapter structure .
*
2007-10-20 01:10:43 +04:00
* This routine performs the necessary steps to start the firmware for
2006-09-19 21:28:00 +04:00
* the QLA4010 adapter .
* */
2010-07-28 14:23:44 +04:00
int qla4xxx_start_firmware ( struct scsi_qla_host * ha )
2006-09-19 21:28:00 +04:00
{
unsigned long flags = 0 ;
uint32_t mbox_status ;
int status = QLA_ERROR ;
int soft_reset = 1 ;
int config_chip = 0 ;
2006-11-16 04:38:40 +03:00
if ( is_qla4022 ( ha ) | is_qla4032 ( ha ) )
2006-09-19 21:28:00 +04: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 ) ;
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 14:23:44 +04:00
status = qla4xxx_soft_reset ( ha ) ; /* NOTE: acquires drvr
* lock again , but ok */
2006-09-19 21:28:00 +04: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 18:28:22 +03:00
/* Reset clears the semaphore, so acquire again */
2006-09-19 21:28:00 +04: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 ;
}
/**
* qla4xxx_initialize_adapter - initiailizes hba
* @ ha : Pointer to host adapter structure .
* @ renew_ddb_list : Indicates what to do with the adapter ' s ddb list
* after adapter recovery has completed .
* 0 = preserve ddb list , 1 = destroy and rebuild ddb list
*
* This routine parforms all of the steps necessary to initialize the adapter .
*
* */
int qla4xxx_initialize_adapter ( struct scsi_qla_host * ha ,
uint8_t renew_ddb_list )
{
int status = QLA_ERROR ;
int8_t ip_address [ IP_ADDR_LEN ] = { 0 } ;
ha - > eeprom_cmd_data = 0 ;
2010-07-28 14:23:44 +04:00
ql4_printk ( KERN_INFO , ha , " Configuring PCI space... \n " ) ;
ha - > isp_ops - > pci_config ( ha ) ;
2006-09-19 21:28:00 +04:00
2010-07-28 14:23:44 +04:00
ha - > isp_ops - > disable_intrs ( ha ) ;
2006-09-19 21:28:00 +04:00
/* Initialize the Host adapter request/response queues and firmware */
2010-07-28 14:23:44 +04:00
if ( ha - > isp_ops - > start_firmware ( ha ) = = QLA_ERROR )
goto exit_init_hba ;
if ( qla4xxx_get_fw_version ( ha ) = = QLA_ERROR )
2007-06-09 04:37:16 +04:00
goto exit_init_hba ;
2006-09-19 21:28:00 +04:00
2010-07-28 14:23:44 +04:00
if ( ha - > isp_ops - > get_sys_info ( ha ) = = QLA_ERROR )
2007-06-09 04:37:16 +04:00
goto exit_init_hba ;
2006-09-19 21:28:00 +04:00
if ( qla4xxx_init_local_data ( ha ) = = QLA_ERROR )
2007-06-09 04:37:16 +04:00
goto exit_init_hba ;
2006-09-19 21:28:00 +04:00
status = qla4xxx_init_firmware ( ha ) ;
if ( status = = QLA_ERROR )
2007-06-09 04:37:16 +04:00
goto exit_init_hba ;
2006-09-19 21:28:00 +04:00
/*
* FW is waiting to get an IP address from DHCP server : Skip building
* the ddb_list and wait for DHCP lease acquired aen to come in
* followed by 0x8014 aen " to trigger the tgt discovery process.
*/
2010-04-28 10:07:07 +04:00
if ( ha - > firmware_state & FW_STATE_CONFIGURING_IP )
2007-06-09 04:37:16 +04:00
goto exit_init_online ;
2006-09-19 21:28:00 +04:00
/* Skip device discovery if ip and subnet is zero */
if ( memcmp ( ha - > ip_address , ip_address , IP_ADDR_LEN ) = = 0 | |
memcmp ( ha - > subnet_mask , ip_address , IP_ADDR_LEN ) = = 0 )
2007-06-09 04:37:16 +04:00
goto exit_init_online ;
2006-09-19 21:28:00 +04:00
if ( renew_ddb_list = = PRESERVE_DDB_LIST ) {
/*
* We want to preserve lun states ( i . e . suspended , etc . )
* for recovery initiated by the driver . So just update
* the device states for the existing ddb_list .
*/
qla4xxx_reinitialize_ddb_list ( ha ) ;
} else if ( renew_ddb_list = = REBUILD_DDB_LIST ) {
/*
* We want to build the ddb_list from scratch during
* driver initialization and recovery initiated by the
* INT_HBA_RESET IOCTL .
*/
status = qla4xxx_initialize_ddb_list ( ha ) ;
if ( status = = QLA_ERROR ) {
DEBUG2 ( printk ( " %s(%ld) Error occurred during build "
" ddb list \n " , __func__ , ha - > host_no ) ) ;
goto exit_init_hba ;
}
}
if ( ! ha - > tot_ddbs ) {
DEBUG2 ( printk ( " scsi%ld: Failed to initialize devices or none "
" present in Firmware device database \n " ,
ha - > host_no ) ) ;
}
2007-06-09 04:37:16 +04:00
exit_init_online :
2007-05-24 04:55:40 +04:00
set_bit ( AF_ONLINE , & ha - > flags ) ;
2007-06-09 04:37:16 +04:00
exit_init_hba :
2010-10-07 09:49:08 +04: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 14:23:44 +04:00
DEBUG2 ( printk ( " scsi%ld: initialize adapter: %s \n " , ha - > host_no ,
status = = QLA_ERROR ? " FAILED " : " SUCCEDED " ) ) ;
2006-09-19 21:28:00 +04:00
return status ;
}
/**
* qla4xxx_add_device_dynamically - ddb addition due to an AEN
* @ ha : Pointer to host adapter structure .
* @ fw_ddb_index : Firmware ' s device database index
*
* This routine processes adds a device as a result of an 8014 h AEN .
* */
static void qla4xxx_add_device_dynamically ( struct scsi_qla_host * ha ,
uint32_t fw_ddb_index )
{
struct ddb_entry * ddb_entry ;
2007-05-24 04:55:40 +04:00
uint32_t new_tgt ;
2006-09-19 21:28:00 +04:00
/* First allocate a device structure */
2007-05-24 04:55:40 +04:00
ddb_entry = qla4xxx_get_ddb_entry ( ha , fw_ddb_index , & new_tgt ) ;
2006-09-19 21:28:00 +04:00
if ( ddb_entry = = NULL ) {
DEBUG2 ( printk ( KERN_WARNING
" scsi%ld: Unable to allocate memory to add "
" fw_ddb_index %d \n " , ha - > host_no , fw_ddb_index ) ) ;
return ;
}
2007-05-24 04:55:40 +04:00
if ( ! new_tgt & & ( ddb_entry - > fw_ddb_index ! = fw_ddb_index ) ) {
/* Target has been bound to a new fw_ddb_index */
qla4xxx_free_ddb ( ha , ddb_entry ) ;
ddb_entry = qla4xxx_alloc_ddb ( ha , fw_ddb_index ) ;
if ( ddb_entry = = NULL ) {
DEBUG2 ( printk ( KERN_WARNING
" scsi%ld: Unable to allocate memory "
" to add fw_ddb_index %d \n " ,
ha - > host_no , fw_ddb_index ) ) ;
return ;
}
}
2006-09-19 21:28:00 +04:00
if ( qla4xxx_update_ddb_entry ( ha , ddb_entry , fw_ddb_index ) = =
QLA_ERROR ) {
ha - > fw_ddb_index_map [ fw_ddb_index ] =
( struct ddb_entry * ) INVALID_ENTRY ;
DEBUG2 ( printk ( KERN_WARNING
" scsi%ld: failed to add new device at index "
" [%d] \n Unable to retrieve fw ddb entry \n " ,
ha - > host_no , fw_ddb_index ) ) ;
qla4xxx_free_ddb ( ha , ddb_entry ) ;
return ;
}
if ( qla4xxx_add_sess ( ddb_entry ) ) {
DEBUG2 ( printk ( KERN_WARNING
" scsi%ld: failed to add new device at index "
" [%d] \n Unable to add connection and session \n " ,
ha - > host_no , fw_ddb_index ) ) ;
qla4xxx_free_ddb ( ha , ddb_entry ) ;
}
}
/**
* 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 .
* */
2010-04-28 10:11:21 +04:00
int qla4xxx_process_ddb_changed ( struct scsi_qla_host * ha , uint32_t fw_ddb_index ,
uint32_t state , uint32_t conn_err )
2006-09-19 21:28:00 +04:00
{
struct ddb_entry * ddb_entry ;
uint32_t old_fw_ddb_device_state ;
/* check for out of range index */
if ( fw_ddb_index > = MAX_DDB_ENTRIES )
return QLA_ERROR ;
/* 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 ) {
if ( state = = DDB_DS_SESSION_ACTIVE )
qla4xxx_add_device_dynamically ( ha , fw_ddb_index ) ;
return QLA_SUCCESS ;
}
/* Device already exists in our database. */
old_fw_ddb_device_state = ddb_entry - > fw_ddb_device_state ;
DEBUG2 ( printk ( " scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for "
" index [%d] \n " , ha - > host_no , __func__ ,
ddb_entry - > fw_ddb_device_state , state , fw_ddb_index ) ) ;
if ( old_fw_ddb_device_state = = state & &
state = = DDB_DS_SESSION_ACTIVE ) {
2010-07-10 13:18:36 +04:00
if ( atomic_read ( & ddb_entry - > state ) ! = DDB_STATE_ONLINE ) {
atomic_set ( & ddb_entry - > state , DDB_STATE_ONLINE ) ;
iscsi_unblock_session ( ddb_entry - > sess ) ;
}
2006-09-19 21:28:00 +04:00
return QLA_SUCCESS ;
}
ddb_entry - > fw_ddb_device_state = state ;
/* Device is back online. */
if ( ddb_entry - > fw_ddb_device_state = = DDB_DS_SESSION_ACTIVE ) {
2008-03-04 22:26:53 +03:00
atomic_set ( & ddb_entry - > state , DDB_STATE_ONLINE ) ;
2006-09-19 21:28:00 +04:00
atomic_set ( & ddb_entry - > relogin_retry_count , 0 ) ;
atomic_set ( & ddb_entry - > relogin_timer , 0 ) ;
clear_bit ( DF_RELOGIN , & ddb_entry - > flags ) ;
clear_bit ( DF_NO_RELOGIN , & ddb_entry - > flags ) ;
2008-01-31 22:36:44 +03:00
iscsi_unblock_session ( ddb_entry - > sess ) ;
2007-12-13 21:43:29 +03:00
iscsi_session_event ( ddb_entry - > sess ,
ISCSI_KEVENT_CREATE_SESSION ) ;
2006-09-19 21:28:00 +04:00
/*
* Change the lun state to READY in case the lun TIMEOUT before
* the device came back .
*/
} else {
2010-04-28 10:08:11 +04:00
/* Device went away, mark device missing */
if ( atomic_read ( & ddb_entry - > state ) = = DDB_STATE_ONLINE ) {
2010-07-10 13:21:02 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " %s mark missing "
2010-04-28 10:08:11 +04:00
" ddb_entry 0x%p sess 0x%p conn 0x%p \n " ,
__func__ , ddb_entry ,
ddb_entry - > sess , ddb_entry - > conn ) ) ;
2006-09-19 21:28:00 +04:00
qla4xxx_mark_device_missing ( ha , ddb_entry ) ;
2010-04-28 10:08:11 +04:00
}
2006-09-19 21:28:00 +04:00
/*
* Relogin if device state changed to a not active state .
2010-04-28 10:11:21 +04:00
* However , do not relogin if a RELOGIN is in process , or
* we are not allowed to relogin to this DDB .
2006-09-19 21:28:00 +04:00
*/
if ( ddb_entry - > fw_ddb_device_state = = DDB_DS_SESSION_FAILED & &
! test_bit ( DF_RELOGIN , & ddb_entry - > flags ) & &
! test_bit ( DF_NO_RELOGIN , & ddb_entry - > flags ) & &
2010-04-28 10:11:21 +04:00
qla4_is_relogin_allowed ( ha , conn_err ) ) {
2006-09-19 21:28:00 +04:00
/*
* 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 .
*/
2010-04-28 10:11:21 +04:00
/* Firmware pads this timeout: (time2wait +1).
2006-09-19 21:28:00 +04:00
* 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 ) ;
2010-07-28 14:23:44 +04:00
DEBUG ( printk ( " scsi%ld: %s: ddb[%d] "
" initiate relogin after %d seconds \n " ,
ha - > host_no , __func__ ,
ddb_entry - > fw_ddb_index ,
ddb_entry - > default_time2wait + 4 ) ) ;
} else {
DEBUG ( printk ( " scsi%ld: %s: ddb[%d] "
" relogin not initiated, state = %d, "
" ddb_entry->flags = 0x%lx \n " ,
ha - > host_no , __func__ ,
ddb_entry - > fw_ddb_index ,
ddb_entry - > fw_ddb_device_state ,
ddb_entry - > flags ) ) ;
2006-09-19 21:28:00 +04:00
}
}
return QLA_SUCCESS ;
}