qla4xxx: driver initialization routines
Subsystems (2)
RFC PATCH 2/7 qla4xxx: driver initialization routines
qla4xxx driver initialization routines.
Signed-off-by Ravi Anand <[email protected]>
Signed-off-by David Somayajulu <[email protected]>
Signed-off-by Doug Maxey <[email protected]>
Signed-off-by Mike Christie <[email protected]>
---
drivers/scsi/qla4xxx/ql4_init.c new file +1602 -0
@@ -0,0 +1,1602 @@ +/* +* QLogic iSCSI HBA Driver +* Copyright (c) 2003-2006 QLogic Corporation +* +* See LICENSE.qla4xxx for copyright and licensing details. +*/ + +#include "ql4_def.h" + +/* +* QLogic ISP4xxx Hardware Support Function Prototypes. +*/ + +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 +* This routine deallocates and unlinks the specified ddb_entry from the +* adapter's +* +* Input: +* ha - Pointer to host adapter structure. +* ddb_entry - Pointer to device database entry +* +* Returns: +* None +**************************************************************************/ +void qla4xxx_free_ddb (struct scsi_qla_host *ha,struct ddb_entry *ddb_entry) +{ +/* 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 +* This routine deallocates and removes all devices on the sppecified +* adapter. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* None +**************************************************************************/ +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); + } +} + +/* +* qla4xxx_init_rings +* This routine initializes the internal queues for the specified adapter. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Remarks: +* The QLA4010 requires us to restart the queues at index 0. +* The QLA4000 doesn't care, so just default to QLA4010's requirement. +* Returns: +* QLA_SUCCESS - Always return success. +*/ +int qla4xxx_init_rings (struct scsi_qla_host *ha) +{ +uint16_t i; +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]; + +/* +* 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 (); + +writel (0 , &ha->reg->req_q_in); +writel (0 , &ha->reg->rsp_q_out); +readl (&ha->reg->rsp_q_out); + +/* Initialize active array */ +for (i =0 ; i <MAX_SRBS ; i++) + ha->active_srb_array[i] =NULL ; + +spin_unlock_irqrestore (&ha->hardware_lock, flags); + +return QLA_SUCCESS ; +} + +/************************************************************************** +* qla4xxx_validate_mac_address +* This routine validates the M.A.C. Address(es) of the adapter +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* QLA_SUCCESS - Successfully validated M.A.C. address +* QLA_ERROR - Failed to validate M.A.C. address +**************************************************************************/ +static int qla4xxx_validate_mac_address (struct scsi_qla_host *ha) +{ +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__)); + + goto exit_validate_mac_no_free; + } +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__)); + + goto exit_validate_mac; + } + +/* 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 ; + + exit_validate_mac: +dma_free_coherent (&ha->pdev->dev,sizeof (*sys_info), sys_info, + sys_info_dma); + + exit_validate_mac_no_free: +return status; +} + +/* +* qla4xxx_init_local_data +* This routine initializes the local data for the specified adapter. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* QLA_SUCCESS - Successfully initialized local data +* QLA_ERROR - Failed to initialize local data +*/ +static int qla4xxx_init_local_data (struct scsi_qla_host *ha) +{ +int i; + +/* Initialize passthru PDU list */ +for (i =0 ; i < (MAX_PDU_ENTRIES -1 ); i++) + ha->pdu_queue[i].Next = &ha->pdu_queue[i +1 ]; + ha->free_pdu_top = &ha->pdu_queue[0 ]; + ha->free_pdu_bottom = &ha->pdu_queue[MAX_PDU_ENTRIES -1 ]; + ha->free_pdu_bottom->Next =NULL ; + ha->pdu_active =0 ; + +/* Initilize aen queue */ + ha->aen_q_count =MAX_AEN_ENTRIES ; + +return qla4xxx_get_firmware_status (ha); +} + +static int qla4xxx_fw_ready (struct scsi_qla_host *ha) +{ +uint32_t timeout_count; +int ready =0 ; + +DEBUG2 (ql4_printk (KERN_INFO , ha,"Waiting for Firmware Ready..\n" )); +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 ; + } + +if (ha->firmware_state ==FW_STATE_READY ) { +DEBUG2 (ql4_printk (KERN_INFO , ha, +"Firmware Ready..\n" )); +/* The firmware is ready to process SCSI commands. */ +DEBUG2 (ql4_printk (KERN_INFO , ha, +"scsi%ld: %s: MEDIA TYPE - %s\n" , + ha->host_no, + __func__, (ha->addl_fw_state & +FW_ADDSTATE_OPTICAL_MEDIA ) + !=0 ?"OPTICAL" :"COPPER" )); +DEBUG2 (ql4_printk (KERN_INFO , ha, +"scsi%ld: %s: DHCP STATE Enabled " +"%s\n" , + ha->host_no, __func__, + (ha->addl_fw_state & +FW_ADDSTATE_DHCP_ENABLED ) !=0 ? +"YES" :"NO" )); +DEBUG2 (ql4_printk (KERN_INFO , ha, +"scsi%ld: %s: LINK %s\n" , + ha->host_no, __func__, + (ha->addl_fw_state & +FW_ADDSTATE_LINK_UP ) !=0 ? +"UP" :"DOWN" )); +DEBUG2 (ql4_printk (KERN_INFO , ha, +"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 ; + } +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)); +msleep (1000 ); + }/* end of for */ + +if (timeout_count <=0 ) +DEBUG2 (printk ("scsi%ld: %s: FW Initialization timed out!\n" , + ha->host_no, __func__)); + +if (ha->firmware_state &FW_STATE_DHCP_IN_PROGRESS ) { +DEBUG2 (printk ("scsi%ld: %s: FW is reporting its waiting to" +" grab an IP address from DHCP server\n" , + ha->host_no, __func__)); + ready =1 ; + } + +return ready; +} + +/* +* qla4xxx_init_firmware +* This routine initializes the firmware. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* QLA_SUCCESS - Successfully initialized firmware +* QLA_ERROR - Failed to initialize firmware +*/ +static int qla4xxx_init_firmware (struct scsi_qla_host *ha) +{ +int status =QLA_ERROR ; + +ql4_printk (KERN_INFO , ha,"Initializing firmware..\n" ); +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; + +set_bit (AF_ONLINE , &ha->flags); +return qla4xxx_get_firmware_status (ha); +} + +static struct ddb_entry *qla4xxx_get_ddb_entry (struct scsi_qla_host *ha, +uint32_t fw_ddb_index) +{ +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; + +/* 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__)); +return NULL ; + } + +if (qla4xxx_get_fwddb_entry (ha, fw_ddb_index, fw_ddb_entry, + fw_ddb_entry_dma,NULL ,NULL , + &device_state,NULL ,NULL ,NULL ) == +QLA_ERROR ) { +DEBUG2 (printk ("scsi%ld: %s: failed get_ddb_entry for " +"fw_ddb_index %d\n" , ha->host_no, __func__, + fw_ddb_index)); +return NULL ; + } + +/* 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) { +if (memcmp (ddb_entry->iscsi_name, fw_ddb_entry->iscsiName, +ISCSI_NAME_SIZE ) ==0 ) { + found++; +break ; + } + } + +if (!found) { +DEBUG2 (printk ("scsi%ld: %s: ddb[%d] not found - allocating " +"new ddb\n" , ha->host_no, __func__, + fw_ddb_index)); + ddb_entry =qla4xxx_alloc_ddb (ha, fw_ddb_index); + } + +/* if not found allocate new ddb */ +dma_free_coherent (&ha->pdev->dev,sizeof (*fw_ddb_entry), fw_ddb_entry, + fw_ddb_entry_dma); + +return ddb_entry; +} + +/************************************************************************** +* qla4xxx_update_ddb_entry +* This routine updates the driver's internal device database entry +* with information retrieved from the firmware's device database +* entry for the specified device. +* +* Input: +* ha - Pointer to host adapter structure. +* ddb_entry - Pointer to device database entry +* +* Output: +* ddb_entry - Structure filled in. +* +* Remarks: +* The ddb_entry->fw_ddb_index field must be initialized prior to +* calling this routine +* +* Returns: +* QLA_SUCCESS - Successfully update ddb_entry +* QLA_ERROR - Failed to update ddb_entry +**************************************************************************/ +int qla4xxx_update_ddb_entry (struct scsi_qla_host *ha, +struct ddb_entry *ddb_entry, +uint32_t fw_ddb_index) +{ +struct dev_db_entry *fw_ddb_entry =NULL ; +dma_addr_t fw_ddb_entry_dma; +int status =QLA_ERROR ; + +if (ddb_entry ==NULL ) { +DEBUG2 (printk ("scsi%ld: %s: ddb_entry is NULL\n" , ha->host_no, + __func__)); + goto exit_update_ddb; + } + +/* 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__)); + + goto exit_update_ddb; + } + +if (qla4xxx_get_fwddb_entry (ha, fw_ddb_index, fw_ddb_entry, + fw_ddb_entry_dma,NULL ,NULL , + &ddb_entry->fw_ddb_device_state,NULL , + &ddb_entry->tcp_source_port_num, + &ddb_entry->connection_id) == +QLA_ERROR ) { +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 ; + ddb_entry->target_session_id =le16_to_cpu (fw_ddb_entry->TSID); + ddb_entry->task_mgmt_timeout = +le16_to_cpu (fw_ddb_entry->taskMngmntTimeout); + ddb_entry->CmdSn =0 ; + ddb_entry->exe_throttle =le16_to_cpu (fw_ddb_entry->exeThrottle); + ddb_entry->default_relogin_timeout = +le16_to_cpu (fw_ddb_entry->taskMngmntTimeout); + ddb_entry->default_time2wait =le16_to_cpu (fw_ddb_entry->minTime2Wait); + +/* Update index in case it changed */ + ddb_entry->fw_ddb_index = fw_ddb_index; + ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; + + ddb_entry->port =le16_to_cpu (fw_ddb_entry->portNumber); + ddb_entry->tpgt =le32_to_cpu (fw_ddb_entry->TargetPortalGroup); +memcpy (&ddb_entry->iscsi_name[0 ], &fw_ddb_entry->iscsiName[0 ], +min (sizeof (ddb_entry->iscsi_name), +sizeof (fw_ddb_entry->iscsiName))); +memcpy (&ddb_entry->ip_addr[0 ], &fw_ddb_entry->ipAddr[0 ], +min (sizeof (ddb_entry->ip_addr),sizeof (fw_ddb_entry->ipAddr))); + +DEBUG2 (printk ("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n" , + ha->host_no, __func__, fw_ddb_index, + ddb_entry->fw_ddb_device_state, status)); + + exit_update_ddb: +if (fw_ddb_entry) +dma_free_coherent (&ha->pdev->dev,sizeof (*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); + +return status; +} + +/************************************************************************** +* qla4xxx_alloc_ddb +* This routine allocates a ddb_entry, ititializes some values, and +* inserts it into the ddb list. +* +* Input: +* ha - Pointer to host adapter structure. +* fw_ddb_index - Firmware's device database index +* +* Returns: +* Pointer to internal device database structure +**************************************************************************/ +struct ddb_entry *qla4xxx_alloc_ddb (struct scsi_qla_host *ha, +uint32_t fw_ddb_index) +{ +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->port_down_timer, ha->port_down_retry_count); +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; +} + +/************************************************************************** +* qla4xxx_configure_ddbs +* This routine searches for all valid firmware ddb entries and builds +* an internal ddb list. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Remarks: +* Ddbs that are considered valid are those with a device state of +* SESSION_ACTIVE. +* +* Returns: +* QLA_SUCCESS - Successfully built internal ddb list, if targets available +* QLA_ERROR - Error on a mailbox command +**************************************************************************/ +static int qla4xxx_build_ddb_list (struct scsi_qla_host *ha) +{ +int status =QLA_SUCCESS ; +uint32_t fw_ddb_index =0 ; +uint32_t next_fw_ddb_index =0 ; +uint32_t ddb_state; +uint32_t conn_err, err_code; +struct ddb_entry *ddb_entry; + +ql4_printk (KERN_INFO , ha,"Initializing DDBs ...\n" ); +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 */ +if (qla4xxx_get_fwddb_entry (ha, fw_ddb_index,NULL ,0 ,NULL , + &next_fw_ddb_index, &ddb_state, + &conn_err,NULL ,NULL ) == +QLA_ERROR ) { +DEBUG2 (printk ("scsi%ld: %s: get_ddb_entry, " +"fw_ddb_index %d failed" , ha->host_no, + __func__, fw_ddb_index)); +return QLA_ERROR ; + } + +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)); + err_code = ((conn_err &0x00ff0000 ) >>16 ); +if (err_code ==0x1c || err_code ==0x06 ) { +DEBUG2 (printk ("scsi%ld: %s send target " +"completed " +"or access denied failure\n" , + ha->host_no, __func__)); + }else +qla4xxx_set_ddb_entry (ha, fw_ddb_index,0 ); + } + +if (ddb_state !=DDB_DS_SESSION_ACTIVE ) +continue ; +/* +* 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. */ + ddb_entry =qla4xxx_get_ddb_entry (ha, fw_ddb_index); +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)); +return QLA_ERROR ; + } +/* 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)); +return QLA_ERROR ; + } + +/* We know we've reached the last device when +* next_fw_ddb_index is 0 */ +if (next_fw_ddb_index ==0 ) +break ; + } + +ql4_printk (KERN_INFO , ha,"DDB list done..\n" ); + +return status; +} + +struct qla4_relog_scan { +int halt_wait; +uint32_t conn_err; +uint32_t err_code; +uint32_t fw_ddb_index; +uint32_t next_fw_ddb_index; +uint32_t fw_ddb_device_state; +}; + +static int qla4_test_rdy (struct scsi_qla_host *ha,struct qla4_relog_scan *rs) +{ +struct ddb_entry *ddb_entry; + +/* +* Don't want to do a relogin if connection +* error is 0x1c. +*/ + rs->err_code = ((rs->conn_err &0x00ff0000 ) >>16 ); +if (rs->err_code ==0x1c || rs->err_code ==0x06 ) { +DEBUG2 (printk ( +"scsi%ld: %s send target" +" completed or " +"access denied failure\n" , + ha->host_no, __func__)); + }else { +/* We either have a device that is in +* the process of relogging in or a +* device that is waiting to be +* relogged in */ + rs->halt_wait =0 ; + + ddb_entry =qla4xxx_lookup_ddb_by_fw_index (ha, + rs->fw_ddb_index); +if (ddb_entry ==NULL ) +return QLA_ERROR ; + +if (ddb_entry->dev_scan_wait_to_start_relogin !=0 + &&time_after_eq (jiffies, + ddb_entry-> + dev_scan_wait_to_start_relogin)) + { + ddb_entry->dev_scan_wait_to_start_relogin =0 ; +qla4xxx_set_ddb_entry (ha, rs->fw_ddb_index,0 ); + } + } +return QLA_SUCCESS ; +} + +static int qla4_scan_for_relogin (struct scsi_qla_host *ha, +struct qla4_relog_scan *rs) +{ +int error; + +/* scan for relogins +* ----------------- */ +for (rs->fw_ddb_index =0 ; rs->fw_ddb_index <MAX_DDB_ENTRIES ; + rs->fw_ddb_index = rs->next_fw_ddb_index) { +if (qla4xxx_get_fwddb_entry (ha, rs->fw_ddb_index,NULL ,0 , +NULL , &rs->next_fw_ddb_index, + &rs->fw_ddb_device_state, + &rs->conn_err,NULL ,NULL ) + ==QLA_ERROR ) +return QLA_ERROR ; + +if (rs->fw_ddb_device_state ==DDB_DS_LOGIN_IN_PROCESS ) + rs->halt_wait =0 ; + +if (rs->fw_ddb_device_state ==DDB_DS_SESSION_FAILED || + rs->fw_ddb_device_state ==DDB_DS_NO_CONNECTION_ACTIVE ) { + error =qla4_test_rdy (ha, rs); +if (error) +return error; + } + +/* We know we've reached the last device when +* next_fw_ddb_index is 0 */ +if (rs->next_fw_ddb_index ==0 ) +break ; + } +return QLA_SUCCESS ; +} + +/************************************************************************** +* qla4xxx_devices_ready +* This routine waits up to ql4xdiscoverywait seconds +* F/W database during driver load time. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* QLA_SUCCESS - Successfully (re)built internal ddb list +* QLA_ERROR - Failed to (re)build internal ddb list +**************************************************************************/ +static int qla4xxx_devices_ready (struct scsi_qla_host *ha) +{ +int error; +unsigned long discovery_wtime; +struct qla4_relog_scan rs; + + discovery_wtime = jiffies + (ql4xdiscoverywait *HZ ); + +DEBUG (printk ("Waiting (%d) for devices ...\n" , ql4xdiscoverywait)); +do { +/* poll for AEN. */ +qla4xxx_get_firmware_state (ha); +if (test_and_clear_bit (DPC_AEN , &ha->dpc_flags)) { +/* Set time-between-relogin timer */ +qla4xxx_process_aen (ha,RELOGIN_DDB_CHANGED_AENS ); + } + +/* if no relogins active or needed, halt discvery wait */ + rs.halt_wait =1 ; + + error =qla4_scan_for_relogin (ha, &rs); + +if (rs.halt_wait) { +DEBUG2 (printk ("scsi%ld: %s: Delay halted. Devices " +"Ready.\n" , ha->host_no, __func__)); +return QLA_SUCCESS ; + } + +msleep (2000 ); + }while (!time_after_eq (jiffies, discovery_wtime)); + +DEBUG3 (qla4xxx_get_conn_event_log (ha)); + +return QLA_SUCCESS ; +} + +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)); + +} + +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] = + (struct ddb_entry *)INVALID_ENTRY ; + + ha->tot_ddbs =0 ; + +qla4xxx_flush_AENS (ha); + +/* +* First perform device discovery for active +* fw ddb indexes and build +* ddb list. +*/ +if ((status =qla4xxx_build_ddb_list (ha)) ==QLA_ERROR ) +return status; + +/* Wait for an AEN */ +qla4xxx_devices_ready (ha); + +/* +* Targets can come online after the inital discovery, so processing +* the aens here will catch them. +*/ +if (test_and_clear_bit (DPC_AEN , &ha->dpc_flags)) +qla4xxx_process_aen (ha,PROCESS_ALL_AENS ); + +return status; +} + +/* +* qla4xxx_update_ddb_list +* This routine obtains device information from the F/W database after +* firmware or adapter resets. The device table is preserved. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* QLA_SUCCESS - Successfully updated internal ddb list +* QLA_ERROR - Failed to update internal ddb list +*/ +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)); + }else if (atomic_read (&ddb_entry->state) ==DDB_STATE_ONLINE ) +qla4xxx_mark_device_missing (ha, ddb_entry); + } +return status; +} + +/************************************************************************** +* qla4xxx_relogin_device +* This routine does a session relogin with the specified device. +* The ddb entry must be assigned prior to making this call. +* +* Input: +* ha - Pointer to host adapter structure. +* ddb_entry - Pointer to device database entry +* +* Returns: +* QLA_SUCCESS = Successfully relogged in device +* QLA_ERROR = Failed to relogin device +**************************************************************************/ +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); + +DEBUG2 (printk ("scsi%ld: Relogin index [%d]. TOV=%d\n" , ha->host_no, + ddb_entry->fw_ddb_index, relogin_timer)); + +qla4xxx_set_ddb_entry (ha, ddb_entry->fw_ddb_index,0 ); + +return QLA_SUCCESS ; +} + +/************************************************************************** +* qla4010_topcat_soft_reset +* This routine determines if the QLA4040 TopCat chip is present. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* None. +**************************************************************************/ +static void qla4010_get_topcat_presence (struct scsi_qla_host *ha) +{ +unsigned long flags; +uint16_t topcat; + +ql4xxx_lock_nvram (ha); +spin_lock_irqsave (&ha->hardware_lock, flags); + topcat =rd_nvram_word (ha, offsetof(struct eeprom_data , + isp4010.topcat)); +spin_unlock_irqrestore (&ha->hardware_lock, flags); + +if ((topcat &TOPCAT_MASK ) ==TOPCAT_PRESENT ) +set_bit (AF_TOPCAT_CHIP_PRESENT , &ha->flags); +else +clear_bit (AF_TOPCAT_CHIP_PRESENT , &ha->flags); +ql4xxx_unlock_nvram (ha); +} + + +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__)); +ql4xxx_lock_flash (ha); +ql4xxx_lock_nvram (ha); + +/* Get EEPRom Parameters from NVRAM and validate */ +ql4_printk (KERN_INFO , ha,"Configuring NVRAM ...\n" ); +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 { +/* +* QLogic adapters should always have a valid NVRAM. +* If not valid, do not load. +*/ +ql4_printk (KERN_WARNING , ha, +"scsi%ld: %s: EEProm checksum invalid. " +"Please update your EEPROM\n" , ha->host_no, + __func__); + +/* set defaults */ +if (is_qla4010 (ha)) + extHwConfig.Asuint32_t =0x1912 ; +else if (is_qla4022 (ha)) + extHwConfig.Asuint32_t =0x0023 ; + } +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); + +return 1 ; +} + +static void qla4x00_pci_config (struct scsi_qla_host *ha) +{ +uint16_t w, mwi; + +ql4_printk (KERN_INFO , ha,"Configuring PCI space...\n" ); + +pci_set_master (ha->pdev); + mwi =0 ; +if (pci_set_mwi (ha->pdev)) + mwi =PCI_COMMAND_INVALIDATE ; +/* +* 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); + w |= mwi | (PCI_COMMAND_PARITY |PCI_COMMAND_SERR ); + 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 ; +uint32_t max_wait_time; +unsigned long flags; +uint32_t mbox_status; + +ql4_printk (KERN_INFO , ha,"Starting firmware ...\n" ); + +/* +* 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 ]); +if (is_qla4022 (ha)) +writel (set_rmask (NVR_WRITE_ENABLE ), + &ha->reg->u1.isp4022.nvram); + +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. */ + max_wait_time =FIRMWARE_UP_TOV *4 ; +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 ; + +DEBUG2 (printk ("scsi%ld: %s: Waiting for boot firmware to " +"complete... ctrl_sts=0x%x, remaining=%d\n" , + ha->host_no, __func__, ctrl_status, + max_wait_time)); + +msleep (250 ); + }while ((max_wait_time--)); + +if (mbox_status ==MBOX_STS_COMMAND_COMPLETE ) { +DEBUG (printk ("scsi%ld: %s: Firmware has started\n" , + 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; +} + +static void ql4xxx_lock_drvr_wait (struct scsi_qla_host *a) +{ +int i =0 ; +while (1 ) { +if (ql4xxx_lock_drvr (a) ==0 ) { +msleep (10 ); +if (!i) { +DEBUG2 (printk ("scsi%ld: %s: Waiting for " +"Global Init Semaphore...n" , + a->host_no, + __func__)); + i++; + } + }else { +DEBUG2 (printk ("scsi%ld: %s: Global Init Semaphore " +"acquired.n" , a->host_no, __func__)); +break ; + } + } +} + +/************************************************************************** +* qla4xxx_start_firmware +* This routine performs the neccessary steps to start the firmware for +* the QLA4010 adapter. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* QLA_SUCCESS - Successfully started QLA4xxx firmware +* QLA_ERROR - Failed to start QLA4xxx firmware +**************************************************************************/ +static int qla4xxx_start_firmware (struct scsi_qla_host *ha) +{ +unsigned long flags =0 ; +uint32_t mbox_status; +int status =QLA_ERROR ; +int soft_reset =1 ; +int config_chip =0 ; + +if (is_qla4010 (ha)) +qla4010_get_topcat_presence (ha); + +if (is_qla4022 (ha)) +ql4xxx_set_mac_number (ha); + +ql4xxx_lock_drvr_wait (ha); + +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__)); + status =qla4xxx_soft_reset (ha); +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 ; + +/* Reset clears the semaphore, so aquire again */ +ql4xxx_lock_drvr_wait (ha); + } + +if (config_chip) { +if (qla4xxx_config_nvram (ha)) + status =qla4xxx_start_firmware_from_flash (ha); + } + +ql4xxx_unlock_drvr (ha); +if (status ==QLA_SUCCESS ) { +qla4xxx_get_fw_version (ha); +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 +* This routine parforms all of the steps necessary to initialize the +* adapter. +* +* Input: +* 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 +* +* Returns: +* QLA_SUCCESS - Successfully initialized adapter +* QLA_ERROR - Failed to initialize 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 ; + +qla4x00_pci_config (ha); + +qla4xxx_disable_intrs (ha); + +/* Initialize the Host adapter request/response queues and firmware */ +if (qla4xxx_start_firmware (ha) ==QLA_ERROR ) +return status; + +if (qla4xxx_validate_mac_address (ha) ==QLA_ERROR ) +return status; + +if (qla4xxx_init_local_data (ha) ==QLA_ERROR ) +return status; + + status =qla4xxx_init_firmware (ha); +if (status ==QLA_ERROR ) +return status; + +/* +* 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. +*/ +if (ha->firmware_state &FW_STATE_DHCP_IN_PROGRESS ) +return status; + +/* 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 ) +return status; + +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)); + } + + exit_init_hba: +return status; + +} + +/************************************************************************** +* qla4xxx_add_device_dynamically +* This routine processes adds a device as a result of an 8014h AEN. +* +* Input: +* ha - Pointer to host adapter structure. +* fw_ddb_index - Firmware's device database index +* +* Returns: +* None +**************************************************************************/ +static void qla4xxx_add_device_dynamically (struct scsi_qla_host *ha, +uint32_t fw_ddb_index) +{ +struct ddb_entry * ddb_entry; + +/* First allocate a device structure */ + ddb_entry =qla4xxx_get_ddb_entry (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 ; + } + +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 +* This routine processes a Decive Database Changed AEN Event. +* +* Input: +* ha - Pointer to host adapter structure. +* fw_ddb_index - Firmware's device database index +* state - Device state +* +* Returns: +* QLA_SUCCESS - Successfully processed ddb_changed aen +* QLA_ERROR - Failed to process ddb_changed aen +**************************************************************************/ +int qla4xxx_process_ddb_changed (struct scsi_qla_host *ha, +uint32_t fw_ddb_index,uint32_t state) +{ +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 ) { +/* Do nothing, state not changed. */ +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 ) { +atomic_set (&ddb_entry->port_down_timer, + ha->port_down_retry_count); +atomic_set (&ddb_entry->state,DDB_STATE_ONLINE ); +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); +iscsi_if_create_session_done (ddb_entry->conn); +/* +* Change the lun state to READY in case the lun TIMEOUT before +* the device came back. +*/ + }else { +/* Device went away, try to relogin. */ +/* Mark device missing */ +if (atomic_read (&ddb_entry->state) ==DDB_STATE_ONLINE ) +qla4xxx_mark_device_missing (ha, ddb_entry); +/* +* Relogin if device state changed to a not active state. +* However, do not relogin if this aen is a result of an IOCTL +* logout (DF_NO_RELOGIN) or if this is a discovered device. +*/ +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) && + !test_bit (DF_ISNS_DISCOVERED , &ddb_entry->flags)) { +/* +* 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 padds 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 ); + } + } + +return QLA_SUCCESS ; +} + +/************************************************************************** +* qla4xxx_login_device +* This routine is called by the login IOCTL to log in the specified +* device. +* +* Input: +* ha - Pointer to host adapter structure. +* fw_ddb_index - Index of the device to login +* connection_id - Connection ID of the device to login +* +* Returns: +* QLA_SUCCESS - Successfully logged in device +* QLA_ERROR - Failed to login device +**************************************************************************/ +int qla4xxx_login_device (struct scsi_qla_host *ha,uint16_t fw_ddb_index, +uint16_t connection_id) +{ +struct ddb_entry * ddb_entry; +int status =QLA_ERROR ; + + ddb_entry =qla4xxx_lookup_ddb_by_fw_index (ha, fw_ddb_index); +if (ddb_entry ==NULL ) + goto exit_login_device; + +if (qla4xxx_get_fwddb_entry (ha, fw_ddb_index,NULL ,0 ,NULL ,NULL , + &ddb_entry->fw_ddb_device_state,NULL , +NULL ,NULL ) ==QLA_ERROR ) + goto exit_login_device; + +if (ddb_entry->fw_ddb_device_state ==DDB_DS_SESSION_ACTIVE ) { + status =QLA_SUCCESS ; + goto exit_login_device; + } + +if (qla4xxx_conn_close_sess_logout (ha, fw_ddb_index, connection_id, +LOGOUT_OPTION_RELOGIN ) + !=QLA_SUCCESS ) + goto exit_login_device; + + status =QLA_SUCCESS ; + +exit_login_device: +return status; +} + +/************************************************************************** +* qla4xxx_logout_device +* This support routine is called by the logout IOCTL to log out +* the specified device. +* +* Input: +* ha - Pointer to host adapter structure. +* fw_ddb_index - Index of the device to logout +* connection_id - Connection ID of the device to logout +* +* Returns: +* QLA_SUCCESS - Successfully logged out device +* QLA_ERROR - Failed to logout device +**************************************************************************/ +int qla4xxx_logout_device (struct scsi_qla_host *ha,uint16_t fw_ddb_index, +uint16_t connection_id) +{ +int status =QLA_ERROR ; +struct ddb_entry * ddb_entry; +uint32_t old_fw_ddb_device_state; + + ddb_entry =qla4xxx_lookup_ddb_by_fw_index (ha, fw_ddb_index); +if (ddb_entry ==NULL ) + goto exit_logout_device; + +if (qla4xxx_get_fwddb_entry (ha, fw_ddb_index,NULL ,0 ,NULL ,NULL , + &old_fw_ddb_device_state,NULL ,NULL , +NULL ) !=QLA_SUCCESS ) + goto exit_logout_device; + +set_bit (DF_NO_RELOGIN , &ddb_entry->flags); +if (qla4xxx_conn_close_sess_logout (ha, fw_ddb_index, connection_id, +LOGOUT_OPTION_CLOSE_SESSION ) + !=QLA_SUCCESS ) + goto exit_logout_device; + + status =QLA_SUCCESS ; + +exit_logout_device: +return status; +} + +/* +* qla4xxx_delete_device +* This routine is called by the logout IOCTL to delete the specified +* device. Send the LOGOUT and DELETE_DDB commands for the specified +* target, even if it's not in our internal database. +* +* Input: +* ha - Pointer to host adapter structure. +* fw_ddb_index - Index of the device to delete +* connection_id - Connection ID of the device to delete +* +* Returns: +* QLA_SUCCESS - Successfully deleted device +* QLA_ERROR - Failed to delete device +*/ +int qla4xxx_delete_device (struct scsi_qla_host *ha,uint16_t fw_ddb_index, +uint16_t connection_id) +{ +int status =QLA_ERROR ; +uint32_t fw_ddb_device_state =0xFFFF ; +u_long wait_count; +struct ddb_entry * ddb_entry; + +/* If the device is in our internal tables, set the NO_RELOGIN bit. */ + ddb_entry =qla4xxx_lookup_ddb_by_fw_index (ha, fw_ddb_index); +if (ddb_entry !=NULL ) +set_bit (DF_NO_RELOGIN , &ddb_entry->flags); + +/* +* If the device state is already one that we can delete, bypass the +* logout command. +*/ +qla4xxx_get_fwddb_entry (ha, fw_ddb_index,NULL ,0 ,NULL ,NULL , + &fw_ddb_device_state,NULL ,NULL ,NULL ); +if (fw_ddb_device_state ==DDB_DS_UNASSIGNED || + fw_ddb_device_state ==DDB_DS_NO_CONNECTION_ACTIVE || + fw_ddb_device_state ==DDB_DS_SESSION_FAILED ) + goto delete_ddb; + +/* First logout index */ +if (qla4xxx_conn_close_sess_logout (ha, fw_ddb_index, connection_id, +LOGOUT_OPTION_CLOSE_SESSION ) != +QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: LOGOUT_OPTION_CLOSE_SESSION " +"failed index [%d]\n" , ha->host_no, __func__, + fw_ddb_index)); + goto exit_delete_ddb; + } + +/* Wait enough time to complete logout */ + wait_count = jiffies +LOGOUT_TOV *HZ ; +while (qla4xxx_get_fwddb_entry (ha, fw_ddb_index,NULL ,0 ,NULL ,NULL , + &fw_ddb_device_state,NULL ,NULL ,NULL ) + ==QLA_SUCCESS ) { +if (time_after_eq (jiffies, wait_count)) + goto exit_delete_ddb; +if (fw_ddb_device_state ==DDB_DS_UNASSIGNED || + fw_ddb_device_state ==DDB_DS_NO_CONNECTION_ACTIVE || + fw_ddb_device_state ==DDB_DS_SESSION_FAILED ) +break ; +udelay (50 ); + } + +delete_ddb: +/* Now delete index */ +if (qla4xxx_clear_database_entry (ha, fw_ddb_index) ==QLA_SUCCESS ) { + status =QLA_SUCCESS ; + +if (!ddb_entry) + goto exit_delete_ddb; + +atomic_set (&ddb_entry->state,DDB_STATE_DEAD ); +DEBUG (printk ("scsi%ld: %s: removing index %d.\n" , ha->host_no, + __func__, fw_ddb_index)); + ha->fw_ddb_index_map[fw_ddb_index] = + (struct ddb_entry *)INVALID_ENTRY ; + } + +exit_delete_ddb: +return status; + +}
drivers/scsi/qla4xxx/ql4_iocb.c new file +592 -0
592 lines not on this page · raw message
RFC PATCH 3/7 qla4xxx: driver OS interface files
qla4xxx driver OS files.
Signed-off-by Ravi Anand <[email protected]>
Signed-off-by David Somayajulu <[email protected]>
Signed-off-by Doug Maxey <[email protected]>
Signed-off-by Mike Christie <[email protected]>
---
drivers/scsi/Kconfig +1 -0
@@ -1352,6 +1352,7 @@ config SCSI_QLOGICPTI module will be called qlogicpti. source "drivers/scsi/qla2xxx/Kconfig" +source "drivers/scsi/qla4xxx/Kconfig" config SCSI_LPFC tristate "Emulex LightPulse Fibre Channel Support"
drivers/scsi/Makefile +1 -0
@@ -81,6 +81,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicf obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/ +obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/ obj-$(CONFIG_SCSI_LPFC) += lpfc/ obj-$(CONFIG_SCSI_PAS16) += pas16.o obj-$(CONFIG_SCSI_SEAGATE) += seagate.o
drivers/scsi/qla4xxx/Kconfig new file +5 -0
@@ -0,0 +1,5 @@ +config SCSI_QLA_ISCSI + tristate "QLogic ISP4XXX host adapter family support" + depends on PCI && SCSI + ---help--- + This driver supports the QLogic 40xx (ISP4XXX) host adapter family.
drivers/scsi/qla4xxx/Makefile new file +5 -0
@@ -0,0 +1,5 @@ +qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \ + ql4_nvram.o ql4_dbg.o + +obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o +
drivers/scsi/qla4xxx/ql4_os.c new file +2006 -0
2,006 lines not on this page · raw message
RFC PATCH 4/7 qla4xxx: driver ISR routines
qla4xxx driver ISR routines.
Signed-off-by Ravi Anand <[email protected]>
Signed-off-by David Somayajulu <[email protected]>
Signed-off-by Doug Maxey <[email protected]>
Signed-off-by Mike Christie <[email protected]>
---
drivers/scsi/qla4xxx/ql4_isr.c new file +989 -0
@@ -0,0 +1,989 @@ +/* +* QLogic iSCSI HBA Driver +* Copyright (c) 2003-2006 QLogic Corporation +* +* See LICENSE.qla4xxx for copyright and licensing details. +*/ + +#include "ql4_def.h" + +/** +* qla2x00_process_completed_request() - Process a Fast Post response. +* @ha: SCSI driver HA context +* @index: SRB index +*/ +static void qla4xxx_process_completed_request (struct scsi_qla_host *ha, +uint32_t index) +{ +struct srb *srb; + + srb =del_from_active_array (ha, index); +if (srb) { +/* Save ISP completion status */ + srb->cmd->result =DID_OK <<16 ; +qla4xxx_srb_compl (ha, srb); + }else { +DEBUG2 (printk ("scsi%ld: Invalid ISP SCSI completion handle = " +"%d\n" , ha->host_no, index)); +set_bit (DPC_RESET_HA , &ha->dpc_flags); + } +} + +/************************************************************************** +* qla4xxx_status_entry +* This routine processes Status IOCBs +* +* Input: +* ha - Pointer to host adapter structure. +* sts_entry - Pointer to status entry structure. +* +* Returns: +* None +* +* Context: +* Interrupt context. +**************************************************************************/ +static void qla4xxx_status_entry (struct scsi_qla_host *ha, +struct status_entry *sts_entry) +{ +uint8_t scsi_status; +struct scsi_cmnd *cmd; +struct srb *srb; +struct ddb_entry *ddb_entry; +uint32_t residual; +uint16_t sensebytecnt; + +if (sts_entry->completionStatus ==SCS_COMPLETE && + sts_entry->scsiStatus ==0 ) { +qla4xxx_process_completed_request (ha, +le32_to_cpu (sts_entry-> + handle)); +return ; + } + + srb =del_from_active_array (ha,le32_to_cpu (sts_entry->handle)); +if (!srb) { +/* FIXMEdg: Don't we need to reset ISP in this case??? */ +DEBUG2 (printk (KERN_WARNING "scsi%ld: %s: Status Entry invalid " +"handle 0x%x, sp=%p. This cmd may have already " +"been completed.\n" , ha->host_no, __func__, +le32_to_cpu (sts_entry->handle), srb)); + } + + cmd = srb->cmd; +if (cmd ==NULL ) { +DEBUG2 (printk ("scsi%ld: %s: Command already returned back to " +"OS pkt->handle=%d srb=%p srb->state:%d\n" , + ha->host_no, __func__, sts_entry->handle, + srb, srb->state)); +ql4_printk (KERN_WARNING , ha, +"Command is NULL: already returned to OS " +"(srb=%p)\n" , srb); +return ; + } + + ddb_entry = srb->ddb; +if (ddb_entry ==NULL ) { + cmd->result =DID_NO_CONNECT <<16 ; + goto status_entry_exit; + } + + residual =le32_to_cpu (sts_entry->residualByteCnt); + +/* Translate ISP error to a Linux SCSI error. */ + scsi_status = sts_entry->scsiStatus; +switch (sts_entry->completionStatus) { +case SCS_COMPLETE : +if (scsi_status ==0 ) { + cmd->result =DID_OK <<16 ; +break ; + } + +if (sts_entry->iscsiFlags & + (ISCSI_FLAG_RESIDUAL_OVER |ISCSI_FLAG_RESIDUAL_UNDER )) + cmd->resid = residual; + + cmd->result =DID_OK <<16 | scsi_status; + +if (scsi_status !=SCSI_CHECK_CONDITION ) +break ; + +/* Copy Sense Data into sense buffer. */ +memset (cmd->sense_buffer,0 ,sizeof (cmd->sense_buffer)); + + sensebytecnt =le16_to_cpu (sts_entry->senseDataByteCnt); +if (sensebytecnt ==0 ) +break ; + +memcpy (cmd->sense_buffer, sts_entry->senseData, +min (sensebytecnt, + (uint16_t )sizeof (cmd->sense_buffer))); + +DEBUG2 (printk ("scsi%ld:%d:%d:%d: %s: sense key = %x, " +"ASC/ASCQ = %02x/%02x\n" , ha->host_no, + cmd->device->channel, cmd->device->id, + cmd->device->lun, __func__, + sts_entry->senseData[2 ] &0x0f , + sts_entry->senseData[12 ], + sts_entry->senseData[13 ])); + + srb->flags |=SRB_GOT_SENSE ; +break ; + +case SCS_INCOMPLETE : +/* Always set the status to DID_ERROR, since +* all conditions result in that status anyway */ + cmd->result =DID_ERROR <<16 ; +break ; + +case SCS_RESET_OCCURRED : +DEBUG2 (printk ("scsi%ld:%d:%d:%d: %s: Device RESET occurred\n" , + ha->host_no, cmd->device->channel, + cmd->device->id, cmd->device->lun, __func__)); + + cmd->result =DID_RESET <<16 ; +break ; + +case SCS_ABORTED : +DEBUG2 (printk ("scsi%ld:%d:%d:%d: %s: Abort occurred\n" , + ha->host_no, cmd->device->channel, + cmd->device->id, cmd->device->lun, __func__)); + + cmd->result =DID_RESET <<16 ; +break ; + +case SCS_TIMEOUT : +DEBUG2 (printk (KERN_INFO "scsi%ld:%d:%d:%d: Timeout\n" , + ha->host_no, cmd->device->channel, + cmd->device->id, cmd->device->lun)); + + cmd->result =DID_BUS_BUSY <<16 ; + +/* +* Mark device missing so that we won't continue to send +* I/O to this device. We should get a ddb state change +* AEN soon. +*/ +if (atomic_read (&ddb_entry->state) ==DDB_STATE_ONLINE ) +qla4xxx_mark_device_missing (ha, ddb_entry); +break ; + +case SCS_DATA_UNDERRUN : +case SCS_DATA_OVERRUN : +if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_OVER ) { +DEBUG2 (printk ("scsi%ld:%d:%d:%d: %s: " "Data overrun, " +"residual = 0x%x\n" , ha->host_no, + cmd->device->channel, cmd->device->id, + cmd->device->lun, __func__, residual)); + + cmd->result =DID_ERROR <<16 ; +break ; + } + +if ((sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER ) ==0 ) { +/* +* Firmware detected a SCSI transport underrun +* condition +*/ + cmd->resid = residual; +DEBUG2 (printk ("scsi%ld:%d:%d:%d: %s: UNDERRUN status " +"detected, xferlen = 0x%x, residual = " +"0x%x\n" , + ha->host_no, cmd->device->channel, + cmd->device->id, + cmd->device->lun, __func__, + cmd->request_bufflen, + residual)); + } + +/* +* If there is scsi_status, it takes precedense over +* underflow condition. +*/ +if (scsi_status !=0 ) { + cmd->result =DID_OK <<16 | scsi_status; + +if (scsi_status !=SCSI_CHECK_CONDITION ) +break ; + +/* Copy Sense Data into sense buffer. */ +memset (cmd->sense_buffer,0 , +sizeof (cmd->sense_buffer)); + + sensebytecnt = +le16_to_cpu (sts_entry->senseDataByteCnt); +if (sensebytecnt ==0 ) +break ; + +memcpy (cmd->sense_buffer, sts_entry->senseData, +min (sensebytecnt, + (uint16_t )sizeof (cmd->sense_buffer))); + +DEBUG2 (printk ("scsi%ld:%d:%d:%d: %s: sense key = %x, " +"ASC/ASCQ = %02x/%02x\n" , ha->host_no, + cmd->device->channel, cmd->device->id, + cmd->device->lun, __func__, + sts_entry->senseData[2 ] &0x0f , + sts_entry->senseData[12 ], + sts_entry->senseData[13 ])); + }else { +/* +* If RISC reports underrun and target does not +* report it then we must have a lost frame, so +* tell upper layer to retry it by reporting a +* bus busy. +*/ +if ((sts_entry->iscsiFlags & +ISCSI_FLAG_RESIDUAL_UNDER ) ==0 ) { + cmd->result =DID_BUS_BUSY <<16 ; + }else if ((cmd->request_bufflen - residual) < + cmd->underflow) { +/* +* Handle mid-layer underflow??? +* +* For kernels less than 2.4, the driver must +* return an error if an underflow is detected. +* For kernels equal-to and above 2.4, the +* mid-layer will appearantly handle the +* underflow by detecting the residual count -- +* unfortunately, we do not see where this is +* actually being done. In the interim, we +* will return DID_ERROR. +*/ +DEBUG2 (printk ("scsi%ld:%d:%d:%d: %s: " +"Mid-layer Data underrun, " +"xferlen = 0x%x, " +"residual = 0x%x\n" , ha->host_no, + cmd->device->channel, + cmd->device->id, + cmd->device->lun, __func__, + cmd->request_bufflen, residual)); + + cmd->result =DID_ERROR <<16 ; + }else { + cmd->result =DID_OK <<16 ; + } + } +break ; + +case SCS_DEVICE_LOGGED_OUT : +case SCS_DEVICE_UNAVAILABLE : +/* +* Mark device missing so that we won't continue to +* send I/O to this device. We should get a ddb +* state change AEN soon. +*/ +if (atomic_read (&ddb_entry->state) ==DDB_STATE_ONLINE ) +qla4xxx_mark_device_missing (ha, ddb_entry); + +if ((srb->flags &SRB_TAPE ) || +atomic_read (&ddb_entry->state) ==DDB_STATE_MISSING ) + cmd->result =DID_BUS_BUSY <<16 ; +else + cmd->result =DID_ERROR <<16 ; +break ; + +case SCS_QUEUE_FULL : +/* +* SCSI Mid-Layer handles device queue full +*/ + cmd->result =DID_OK <<16 | sts_entry->scsiStatus; +DEBUG2 (printk ("scsi%ld:%d:%d: %s: QUEUE FULL detected " +"compl=%02x, scsi=%02x, state=%02x, iFlags=%02x," +" iResp=%02x\n" , ha->host_no, cmd->device->id, + cmd->device->lun, __func__, + sts_entry->completionStatus, + sts_entry->scsiStatus, sts_entry->state_flags, + sts_entry->iscsiFlags, + sts_entry->iscsiResponse)); +break ; + +default : + cmd->result =DID_ERROR <<16 ; +break ; + } + +status_entry_exit: + +/* complete the request */ + srb->cc_stat = sts_entry->completionStatus; +qla4xxx_srb_compl (ha, srb); +} + +/************************************************************************** +* qla4xxx_process_response_queue +* This routine handles the Response Queue Completion. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Output: +* None +* +* Remarks: +* hardware_lock locked upon entry +* +* Returns: +* QLA_SUCCESS - Successfully processed response queue +* QLA_ERROR - Failed to process response queue +* +* Context: +* Interrupt context. +**************************************************************************/ +static void qla4xxx_process_response_queue (struct scsi_qla_host * ha) +{ +uint32_t count =0 ; +struct srb *srb =NULL ; +struct status_entry *sts_entry; + +/* Process all responses from response queue */ +while ((ha->response_in = + (uint16_t )le32_to_cpu (ha->shadow_regs->rsp_q_in)) != + ha->response_out) { + sts_entry = (struct status_entry *) ha->response_ptr; + count++; + +/* Advance pointers for next entry */ +if (ha->response_out == (RESPONSE_QUEUE_DEPTH -1 )) { + ha->response_out =0 ; + ha->response_ptr = ha->response_ring; + }else { + ha->response_out++; + ha->response_ptr++; + } + +/* process entry */ +switch (sts_entry->hdr.entryType) { +case ET_STATUS : +/* +* Common status - Single completion posted in single +* IOSB. +*/ +qla4xxx_status_entry (ha, sts_entry); +break ; + +case ET_PASSTHRU_STATUS : +qla4xxx_isns_process_response (ha, + (struct +passthru_status *) + sts_entry); +break ; + +case ET_STATUS_CONTINUATION : +/* Just throw away the status continuation entries */ +DEBUG2 (printk ("scsi%ld: %s: Status Continuation entry " +"- ignoring\n" , ha->host_no, __func__)); +break ; + +case ET_COMMAND : +/* ISP device queue is full. Command not +* accepted by ISP. Queue command for +* later */ + + srb =del_from_active_array (ha, +le32_to_cpu (sts_entry-> + handle)); +if (srb ==NULL ) + goto exit_prq_invalid_handle; + +DEBUG2 (printk ("scsi%ld: %s: FW device queue full, " +"srb %p\n" , ha->host_no, __func__, srb)); + +/* ETRY normally by sending it back with +* DID_BUS_BUSY */ + srb->cmd->result =DID_BUS_BUSY <<16 ; +qla4xxx_srb_compl (ha, srb); +break ; + +case ET_CONTINUE : +/* Just throw away the continuation entries */ +DEBUG2 (printk ("scsi%ld: %s: Continuation entry - " +"ignoring\n" , ha->host_no, __func__)); +break ; + +default : +/* +* Invalid entry in response queue, reset RISC +* firmware. +*/ +DEBUG2 (printk ("scsi%ld: %s: Invalid entry %x in " +"response queue \n" , ha->host_no, + __func__, + sts_entry->hdr.entryType)); + goto exit_prq_error; + } + } + +/* +* Done with responses, update the ISP For QLA4010, this also clears +* the interrupt. +*/ +writel (ha->response_out, &ha->reg->rsp_q_out); +readl (&ha->reg->rsp_q_out); + +return ; + +exit_prq_invalid_handle: +DEBUG2 (printk ("scsi%ld: %s: Invalid handle(srb)=%p type=%x IOCS=%x\n" , + ha->host_no, __func__, srb, sts_entry->hdr.entryType, + sts_entry->completionStatus)); + +exit_prq_error: +writel (ha->response_out, &ha->reg->rsp_q_out); +readl (&ha->reg->rsp_q_out); + +set_bit (DPC_RESET_HA , &ha->dpc_flags); +} + +/************************************************************************** +* qla4xxx_isr_decode_mailbox +* This routine decodes the mailbox status during the ISR. +* +* Input: +* ha - Pointer to host adapter structure. +* mailbox_status - Mailbox status. +* +* Remarks: +* hardware_lock locked upon entry +* +* Returns: +* None. +* +* Context: +* Interrupt context. +**************************************************************************/ +static void qla4xxx_isr_decode_mailbox (struct scsi_qla_host * ha, +uint32_t mbox_status) +{ +int i; +static uint32_t mbox_sts[MBOX_REG_COUNT ]; + +if ((mbox_status ==MBOX_STS_BUSY ) || + (mbox_status ==MBOX_STS_INTERMEDIATE_COMPLETION ) || + (mbox_status >>12 ==MBOX_COMPLETION_STATUS )) { + ha->mbox_status[0 ] = mbox_status; + +if (test_bit (AF_MBOX_COMMAND , &ha->flags)) { +/* +* Copy all mailbox registers to a temporary +* location and set mailbox command done flag +*/ +for (i =1 ; i < ha->mbox_status_count; i++) + ha->mbox_status[i] = +readl (&ha->reg->mailbox[i]); + +set_bit (AF_MBOX_COMMAND_DONE , &ha->flags); +wake_up (&ha->mailbox_wait_queue); + } + }else if (mbox_status >>12 ==MBOX_ASYNC_EVENT_STATUS ) { +/* Immediately process the AENs that don't require much work. +* Only queue the database_changed AENs */ +switch (mbox_status) { +case MBOX_ASTS_SYSTEM_ERROR : +/* Log Mailbox registers */ +if (ql4xdontresethba) { +DEBUG2 (printk ("%s:Dont Reset HBA\n" , + __func__)); + }else { +set_bit (AF_GET_CRASH_RECORD , &ha->flags); +set_bit (DPC_RESET_HA , &ha->dpc_flags); + } +break ; + +case MBOX_ASTS_REQUEST_TRANSFER_ERROR : +case MBOX_ASTS_RESPONSE_TRANSFER_ERROR : +case MBOX_ASTS_NVRAM_INVALID : +case MBOX_ASTS_IP_ADDRESS_CHANGED : +case MBOX_ASTS_DHCP_LEASE_EXPIRED : +DEBUG2 (printk ("scsi%ld: AEN %04x, ERROR Status, " +"Reset HA\n" , ha->host_no, mbox_status)); +set_bit (DPC_RESET_HA , &ha->dpc_flags); +break ; + +case MBOX_ASTS_LINK_UP : +DEBUG2 (printk ("scsi%ld: AEN %04x Adapter LINK UP\n" , + ha->host_no, mbox_status)); +set_bit (AF_LINK_UP , &ha->flags); +break ; + +case MBOX_ASTS_LINK_DOWN : +DEBUG2 (printk ("scsi%ld: AEN %04x Adapter LINK DOWN\n" , + ha->host_no, mbox_status)); +clear_bit (AF_LINK_UP , &ha->flags); +break ; + +case MBOX_ASTS_HEARTBEAT : + ha->seconds_since_last_heartbeat =0 ; +break ; + +case MBOX_ASTS_DHCP_LEASE_ACQUIRED : +DEBUG2 (printk ("scsi%ld: AEN %04x DHCP LEASE " +"ACQUIRED\n" , ha->host_no, mbox_status)); +set_bit (DPC_GET_DHCP_IP_ADDR , &ha->dpc_flags); +break ; + +case MBOX_ASTS_PROTOCOL_STATISTIC_ALARM : +case MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED :/* Target +* mode +* only */ +case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED :/* Connection mode */ +case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR : +case MBOX_ASTS_SUBNET_STATE_CHANGE : +/* No action */ +DEBUG2 (printk ("scsi%ld: AEN %04x\n" , ha->host_no, + mbox_status)); +break ; + +case MBOX_ASTS_MAC_ADDRESS_CHANGED : +case MBOX_ASTS_DNS : +/* No action */ +DEBUG2 (printk (KERN_INFO "scsi%ld: AEN %04x, " +"mbox_sts[1]=%04x, mbox_sts[2]=%04x\n" , + ha->host_no, mbox_status, +readl (&ha->reg->mailbox[1 ]), +readl (&ha->reg->mailbox[2 ]))); +break ; + +case MBOX_ASTS_SELF_TEST_FAILED : +case MBOX_ASTS_LOGIN_FAILED : +/* No action */ +DEBUG2 (printk ("scsi%ld: AEN %04x, mbox_sts[1]=%04x, " +"mbox_sts[2]=%04x, mbox_sts[3]=%04x\n" , + ha->host_no, mbox_status, +readl (&ha->reg->mailbox[1 ]), +readl (&ha->reg->mailbox[2 ]), +readl (&ha->reg->mailbox[3 ]))); +break ; + +case MBOX_ASTS_DATABASE_CHANGED : +/* Queue AEN information and process it in the DPC +* routine */ +if (ha->aen_q_count >0 ) { +/* advance pointer */ +if (ha->aen_in == (MAX_AEN_ENTRIES -1 )) + ha->aen_in =0 ; +else + ha->aen_in++; + +/* decrement available counter */ + ha->aen_q_count--; + +for (i =1 ; i <MBOX_AEN_REG_COUNT ; i++) + ha->aen_q[ha->aen_in].mbox_sts[i] = +readl (&ha->reg->mailbox[i]); + + ha->aen_q[ha->aen_in].mbox_sts[0 ] = mbox_status; + +/* print debug message */ +DEBUG2 (printk ("scsi%ld: AEN[%d] %04x queued" +" mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n" , + ha->host_no, ha->aen_in, + mbox_status, + ha->aen_q[ha->aen_in].mbox_sts[1 ], + ha->aen_q[ha->aen_in].mbox_sts[2 ], + ha->aen_q[ha->aen_in].mbox_sts[3 ], + ha->aen_q[ha->aen_in]. mbox_sts[4 ])); + +/* The DPC routine will process the aen */ +set_bit (DPC_AEN , &ha->dpc_flags); + }else { +DEBUG2 (printk ("scsi%ld: %s: aen %04x, queue " +"overflowed! AEN LOST!!\n" , + ha->host_no, __func__, + mbox_status)); + +DEBUG2 (printk ("scsi%ld: DUMP AEN QUEUE\n" , + ha->host_no)); + +for (i =0 ; i <MAX_AEN_ENTRIES ; i++) { +DEBUG2 (printk ("AEN[%d] %04x %04x %04x " +"%04x\n" , i, + ha->aen_q[i].mbox_sts[0 ], + ha->aen_q[i].mbox_sts[1 ], + ha->aen_q[i].mbox_sts[2 ], + ha->aen_q[i].mbox_sts[3 ])); + } + } +break ; + +case MBOX_ASTS_ISNS_UNSOLICITED_PDU_RECEIVED : +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_sts[0 ] = mbox_status; + mbox_sts[1 ] =readl (&ha->reg->mailbox[1 ]); + mbox_sts[2 ] =readl (&ha->reg->mailbox[2 ]); + mbox_sts[3 ] =readl (&ha->reg->mailbox[3 ]); + mbox_sts[4 ] =readl (&ha->reg->mailbox[4 ]); + mbox_sts[5 ] =readl (&ha->reg->mailbox[5 ]); + +if (mbox_sts[1 ] ==ISNS_EVENT_DATA_RECEIVED ) { +DEBUG2 (printk ("scsi%d: AEN %04x, mbox_sts[1]=" +"%04x, " +"mbox_sts[2]=%04x," +"mbox_sts[3]=%04x, " +"mbox_sts[4]=%04x\n" , + (int )ha->host_no, mbox_status, + mbox_sts[1 ], mbox_sts[2 ], + mbox_sts[3 ], mbox_sts[4 ])); + +if (qla4xxx_isns_get_server_request (ha, + mbox_sts[3 ], + mbox_sts[2 ]) + !=QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%d: %s: AEN %04x, " +"isns_get_server_request" +" FAILED!!\n" , + (int )ha->host_no, + __func__, mbox_status)); + } + } +else if (mbox_sts[1 ] ==ISNS_EVENT_CONNECTION_OPENED ) { +DEBUG2 (printk ("scsi%d: AEN %04x, iSNS Service " +"Connection Opened!\n" +"mbox_sts[2]=%08x, mbox_sts[3]=" +"%08x, " +"mbox_sts[4]=%08x, " +"mbox_sts[5]=%08x\n" , + (int )ha->host_no, mbox_status, + mbox_sts[2 ], mbox_sts[3 ], + mbox_sts[4 ], mbox_sts[5 ])); + + ha->isns_rsp.conn_id = + (uint16_t )(mbox_sts[2 ] &0xFFFF ); + ha->isns_rsp.scn_conn_id = + (uint16_t )(mbox_sts[3 ] &0xFFFF ); + ha->isns_rsp.esi_conn_id = + (uint16_t )(mbox_sts[4 ] &0xFFFF ); + + ha->isns_rsp.conn_port = + (uint16_t )(mbox_sts[2 ] >>16 ); + ha->isns_rsp.scn_port = + (uint16_t )(mbox_sts[3 ] >>16 ); + ha->isns_rsp.esi_port = + (uint16_t )(mbox_sts[4 ] >>16 ); + +set_bit (AF_ISNS_CMD_DONE , &ha->flags); + + } +else if (mbox_sts[1 ] ==ISNS_EVENT_CONNECTION_FAILED ) { +DEBUG2 (printk ("scsi%d: AEN %04x, iSNS Service" +" Connection FAILED! " +"reason %04x\n" , + (int )ha->host_no, mbox_status, + mbox_sts[2 ])); + } +break ; +default : +DEBUG2 (printk (KERN_WARNING +"scsi%ld: AEN %04x UNKNOWN\n" , + ha->host_no, mbox_status)); +break ; + } + }else { +DEBUG2 (printk ("scsi%ld: Unknown mailbox status %08X\n" , + ha->host_no, mbox_status)); + + ha->mbox_status[0 ] = mbox_status; + } +} + +/************************************************************************** +* qla4xxx_interrupt_service_routine +* This routine services the interrupt +* +* Input: +* ha - Pointer to host adapter structure. +* +* Remarks: +* hardware_lock locked upon entry +* +* Returns: +* QLA_SUCCESS - success, An interrupt was found and processed +* QLA_ERROR - failure, The adapter was not interrupting +* +* Context: +* Interrupt context. +**************************************************************************/ +void qla4xxx_interrupt_service_routine (struct scsi_qla_host * ha, +uint32_t intr_status) +{ +/* Process response queue interrupt. */ +if (intr_status &CSR_SCSI_COMPLETION_INTR ) +qla4xxx_process_response_queue (ha); + +/* Process mailbox/asynch event interrupt.*/ +if (intr_status &CSR_SCSI_PROCESSOR_INTR ) { +qla4xxx_isr_decode_mailbox (ha, +readl (&ha->reg->mailbox[0 ])); + +/* Clear Mailbox Interrupt */ +writel (set_rmask (CSR_SCSI_PROCESSOR_INTR ), + &ha->reg->ctrl_status); +readl (&ha->reg->ctrl_status); + } +} + +/************************************************************************** +* qla4xxx_intr_handler +* This routine handles the H/W interrupt +* +* Input: +* irq - Unused +* dev_id - Pointer to host adapter structure +* regs - Unused +* +* Returns: +* None +* +* Context: +* Interrupt context. +**************************************************************************/ +irqreturn_t qla4xxx_intr_handler (int irq,void *dev_id,struct pt_regs *regs) +{ +struct scsi_qla_host *ha; +uint32_t intr_status; +unsigned long flags =0 ; +uint8_t reqs_count =0 ; + + ha = (struct scsi_qla_host *) dev_id; +if (!ha) { +DEBUG2 (printk (KERN_INFO +"qla4xxx: Interrupt with NULL host ptr\n" )); +return IRQ_NONE ; + } + +spin_lock_irqsave (&ha->hardware_lock, flags); + +/* +* Repeatedly service interrupts up to a maximum of +* MAX_REQS_SERVICED_PER_INTR +*/ +while (1 ) { +/* +* Read interrupt status +*/ +if (le32_to_cpu (ha->shadow_regs->rsp_q_in) != + ha->response_out) + intr_status =CSR_SCSI_COMPLETION_INTR ; +else + intr_status =readl (&ha->reg->ctrl_status); + +if ((intr_status & + (CSR_SCSI_RESET_INTR |CSR_FATAL_ERROR |INTR_PENDING )) == +0 ) { +if (reqs_count ==0 ) + ha->spurious_int_count++; +break ; + } + +if (intr_status &CSR_FATAL_ERROR ) { +DEBUG2 (printk (KERN_INFO "scsi%ld: Fatal Error, " +"Status 0x%04x\n" , ha->host_no, +readl (isp_port_error_status (ha)))); + +/* Issue Soft Reset to clear this error condition. +* This will prevent the RISC from repeatedly +* interrupting the driver; thus, allowing the DPC to +* get scheduled to continue error recovery. +* NOTE: Disabling RISC interrupts does not work in +* this case, as CSR_FATAL_ERROR overrides +* CSR_SCSI_INTR_ENABLE */ +if ((readl (&ha->reg->ctrl_status) & +CSR_SCSI_RESET_INTR ) ==0 ) { +writel (set_rmask (CSR_SOFT_RESET ), + &ha->reg->ctrl_status); +readl (&ha->reg->ctrl_status); + } + +writel (set_rmask (CSR_FATAL_ERROR ), + &ha->reg->ctrl_status); +readl (&ha->reg->ctrl_status); + +__qla4xxx_disable_intrs (ha); + +set_bit (DPC_RESET_HA , &ha->dpc_flags); + +break ; + }else if (intr_status &CSR_SCSI_RESET_INTR ) { +clear_bit (AF_ONLINE , &ha->flags); +__qla4xxx_disable_intrs (ha); + +writel (set_rmask (CSR_SCSI_RESET_INTR ), + &ha->reg->ctrl_status); +readl (&ha->reg->ctrl_status); + +set_bit (DPC_RESET_HA_INTR , &ha->dpc_flags); + +break ; + }else if (intr_status &INTR_PENDING ) { +qla4xxx_interrupt_service_routine (ha, intr_status); + ha->total_io_count++; +if (++reqs_count ==MAX_REQS_SERVICED_PER_INTR ) +break ; + + intr_status =0 ; + } + } + +spin_unlock_irqrestore (&ha->hardware_lock, flags); + +return IRQ_HANDLED ; +} + +/************************************************************************** +* qla4xxx_process_aen +* This routine processes Asynchronous Events received from the firmware. +* +* Input: +* ha - Pointer to host adapter structure. +* process_aen - +* PROCESS_ALL_AENS 0 +* FLUSH_DDB_CHANGED_AENS 1 +* RELOGIN_DDB_CHANGED_AENS 2 +* +* Returns: +* None +**************************************************************************/ +void qla4xxx_process_aen (struct scsi_qla_host * ha,uint8_t process_aen) +{ +uint32_t mbox_sts[MBOX_AEN_REG_COUNT ]; +struct aen *aen; +int i; +unsigned long flags; + +spin_lock_irqsave (&ha->hardware_lock, flags); +while (ha->aen_out != ha->aen_in) { +/* Advance pointers for next entry */ +if (ha->aen_out == (MAX_AEN_ENTRIES -1 )) + ha->aen_out =0 ; +else + ha->aen_out++; + + ha->aen_q_count++; + aen = &ha->aen_q[ha->aen_out]; + +/* copy aen information to local structure */ +for (i =0 ; i <MBOX_AEN_REG_COUNT ; i++) + mbox_sts[i] = aen->mbox_sts[i]; + +spin_unlock_irqrestore (&ha->hardware_lock, flags); + +DEBUG (printk ("scsi%ld: AEN[%d] %04x, index [%d] state=%04x " +"mod=%x conerr=%08x \n" , ha->host_no, ha->aen_out, + mbox_sts[0 ], mbox_sts[2 ], mbox_sts[3 ], + mbox_sts[1 ], mbox_sts[4 ])); + +switch (mbox_sts[0 ]) { +case MBOX_ASTS_DATABASE_CHANGED : +if (process_aen ==FLUSH_DDB_CHANGED_AENS ) { +DEBUG2 (printk ("scsi%ld: AEN[%d] %04x, index " +"[%d] state=%04x FLUSHED!\n" , + ha->host_no, ha->aen_out, + mbox_sts[0 ], mbox_sts[2 ], + mbox_sts[3 ])); +break ; + }else if (process_aen ==RELOGIN_DDB_CHANGED_AENS ) { +/* for use during init time, we only want to +* relogin non-active ddbs */ +struct ddb_entry *ddb_entry; + + ddb_entry = +/* FIXME: name length? */ +qla4xxx_lookup_ddb_by_fw_index (ha, + mbox_sts[2 ]); +if (!ddb_entry) +break ; + + ddb_entry->dev_scan_wait_to_complete_relogin = +0 ; + ddb_entry->dev_scan_wait_to_start_relogin = + jiffies + + ((ddb_entry->default_time2wait + +4 ) *HZ ); + +DEBUG2 (printk ("scsi%ld: ddb index [%d] initate" +" RELOGIN after %d seconds\n" , + ha->host_no, + ddb_entry->fw_ddb_index, + ddb_entry->default_time2wait + +4 )); +break ; + } + +if (mbox_sts[1 ] ==0 ) {/* Global DB change. */ +qla4xxx_reinitialize_ddb_list (ha); + }else if (mbox_sts[1 ] ==1 ) {/* Specific device. */ +qla4xxx_process_ddb_changed (ha, mbox_sts[2 ], + mbox_sts[3 ]); + } +break ; + } +spin_lock_irqsave (&ha->hardware_lock, flags); + } +spin_unlock_irqrestore (&ha->hardware_lock, flags); + +} + +uint8_t qla4xxx_isns_process_response (struct scsi_qla_host *ha, +struct passthru_status *sts_entry) +{ +uint32_t handle =le32_to_cpu (sts_entry->handle); +uint32_t inResidual =le32_to_cpu (sts_entry->inResidual); +struct pdu_entry *pdu_entry = (struct pdu_entry *) &ha->pdu_queue[ +iocb_isns_pt_pdu_index (handle)]; +uint32_t pdu_type =iocb_isns_pt_pdu_type (handle); +uint8_t status =QLA_SUCCESS ; +struct iscsi_hdr hdr;/* dummy header */ + +DEBUG2 (printk ("qla4xxx_passthru_status_entry" )); + +DEBUG2 (printk ("scsi%d: %s to=0x%x " +"IOCS=0x%02x OutResidual/Len=0x%x/0x%x " +"InResidual/Len=0x%x/0x%x\n" , + (int )ha->host_no, __func__, +le16_to_cpu (sts_entry->timeout), + sts_entry->completionStatus, +le32_to_cpu (sts_entry->outResidual), + pdu_entry->SendBuffLen, + inResidual, + pdu_entry->RecvBuffLen)); + +if (sts_entry->completionStatus !=PASSTHRU_STATUS_COMPLETE ) { + +qla4xxx_free_pdu (ha, pdu_entry); +set_bit (DPC_ISNS_RESTART , &ha->dpc_flags); +/* FIXME: should this set error? */ + goto exit_pt_sts; + } + +switch (pdu_type) { +case ISNS_ASYNCH_RSP_PDU : +qla4xxx_free_pdu (ha, pdu_entry); +break ; + +case ISNS_ASYNCH_REQ_PDU : +case ISNS_REQ_RSP_PDU : + pdu_entry->RecvBuffLen -= inResidual; + +DEBUG2 (printk ("scsi%d: %s %s PDU Buff=%p, PDU RecvLen=0x%X\n" , + (int )ha->host_no, __func__, + ((pdu_type ==ISNS_ASYNCH_REQ_PDU ) ? +"ISNS_ASYNCH_REQ_PDU" :"ISNS_REQ_RSP_PDU" ), + pdu_entry->Buff, pdu_entry->RecvBuffLen)); + + + (void )iscsi_recv_pdu (ha->isns_conn, &hdr, pdu_entry->Buff, + pdu_entry->RecvBuffLen); + + +qla4xxx_free_pdu (ha, pdu_entry); +break ; +default : +DEBUG2 (printk ("scsi%d: %s iSNS handle 0x%x invalid\n" , + (int )ha->host_no, __func__, handle)); + status =QLA_ERROR ; +break ; + } + +exit_pt_sts: +return status; +}
RFC PATCH 5/7 qla4xxx: driver mailbox routines
qla4xxx driver Mailbox routines.
Signed-off-by Ravi Anand <[email protected]>
Signed-off-by David Somayajulu <[email protected]>
Signed-off-by Doug Maxey <[email protected]>
Signed-off-by Mike Christie <[email protected]>
---
drivers/scsi/qla4xxx/ql4_mbx.c new file +1092 -0
@@ -0,0 +1,1092 @@ +/* +* QLogic iSCSI HBA Driver +* Copyright (c) 2003-2006 QLogic Corporation +* +* See LICENSE.qla4xxx for copyright and licensing details. +*/ + +#include "ql4_def.h" + + +/************************************************************************** +* qla4xxx_mailbox_command +* This routine sssue mailbox commands and waits for completion. +* +* Input: +* ha - Pointer to host adapter structure. +* inCount - number of mailbox registers to load. +* outCount - number of mailbox registers to return. +* mbx_cmd - data pointer for mailbox in registers. +* mbx_sts - data pointer for mailbox out registers. +* +* Output: +* mbx_sts - returned mailbox out data. +* +* Remarks: +* If outCount is 0, this routine completes successfully WITHOUT waiting +* for the mailbox command to complete. +* +* Returns: +* QLA_SUCCESS - Mailbox command completed successfully +* QLA_ERROR - Mailbox command competed in error. +**************************************************************************/ +int qla4xxx_mailbox_command (struct scsi_qla_host *ha,uint8_t inCount, +uint8_t outCount,uint32_t *mbx_cmd, +uint32_t *mbx_sts) +{ +int status =QLA_ERROR ; +uint8_t i; +u_long wait_count; +uint32_t intr_status; +unsigned long flags =0 ; +DECLARE_WAITQUEUE (wait, current); + +mutex_lock (&ha->mbox_sem); + +/* Mailbox code active */ +set_bit (AF_MBOX_COMMAND , &ha->flags); + +/* Make sure that pointers are valid */ +if (!mbx_cmd || !mbx_sts) { +DEBUG2 (printk ("scsi%ld: %s: Invalid mbx_cmd or mbx_sts " +"pointer\n" , ha->host_no, __func__)); + goto mbox_exit; + } + +/* To prevent overwriting mailbox registers for a command that has +* not yet been serviced, check to see if a previously issued +* mailbox command is interrupting. +* ----------------------------------------------------------------- +*/ +spin_lock_irqsave (&ha->hardware_lock, flags); + intr_status =readl (&ha->reg->ctrl_status); +if (intr_status &CSR_SCSI_PROCESSOR_INTR ) { +/* Service existing interrupt */ +qla4xxx_interrupt_service_routine (ha, intr_status); +clear_bit (AF_MBOX_COMMAND_DONE , &ha->flags); + } + +/* Send the mailbox command to the firmware */ + ha->mbox_status_count = outCount; +for (i =0 ; i < outCount; i++) + ha->mbox_status[i] =0 ; + +/* Load all mailbox registers, except mailbox 0. */ +for (i =1 ; i < inCount; i++) +writel (mbx_cmd[i], &ha->reg->mailbox[i]); + +/* Wakeup firmware */ +writel (mbx_cmd[0 ], &ha->reg->mailbox[0 ]); +readl (&ha->reg->mailbox[0 ]); +writel (set_rmask (CSR_INTR_RISC ), &ha->reg->ctrl_status); +readl (&ha->reg->ctrl_status); +spin_unlock_irqrestore (&ha->hardware_lock, flags); + +/* Wait for completion */ +set_current_state (TASK_UNINTERRUPTIBLE ); +add_wait_queue (&ha->mailbox_wait_queue, &wait); + +/* +* If we don't want status, don't wait for the mailbox command to +* complete. For example, MBOX_CMD_RESET_FW doesn't return status, +* you must poll the inbound Interrupt Mask for completion. +*/ +if (outCount ==0 ) { + status =QLA_SUCCESS ; +set_current_state (TASK_RUNNING ); +remove_wait_queue (&ha->mailbox_wait_queue, &wait); + goto mbox_exit; + } +/* Wait for command to complete */ + wait_count = jiffies +MBOX_TOV *HZ ; +while (test_bit (AF_MBOX_COMMAND_DONE , &ha->flags) ==0 ) { +if (time_after_eq (jiffies, wait_count)) +break ; + +spin_lock_irqsave (&ha->hardware_lock, flags); + intr_status =readl (&ha->reg->ctrl_status); +if (intr_status &INTR_PENDING ) { +/* +* Service the interrupt. +* The ISR will save the mailbox status registers +* to a temporary storage location in the adapter +* structure. +*/ + ha->mbox_status_count = outCount; +qla4xxx_interrupt_service_routine (ha, intr_status); + } +spin_unlock_irqrestore (&ha->hardware_lock, flags); +mdelay (10 ); + } +set_current_state (TASK_RUNNING ); +remove_wait_queue (&ha->mailbox_wait_queue, &wait); + +/* Check for mailbox timeout. */ +if (!test_bit (AF_MBOX_COMMAND_DONE , &ha->flags)) { +DEBUG2 (printk ("scsi%ld: Mailbox Cmd 0x%08X timed out ...," +" Scheduling Adapter Reset\n" , ha->host_no, + mbx_cmd[0 ])); + ha->mailbox_timeout_count++; + mbx_sts[0 ] = (-1 ); +set_bit (DPC_RESET_HA , &ha->dpc_flags); + goto mbox_exit; + } + +/* +* Copy the mailbox out registers to the caller's mailbox in/out +* structure. +*/ +spin_lock_irqsave (&ha->hardware_lock, flags); +for (i =0 ; i < outCount; i++) + mbx_sts[i] = ha->mbox_status[i]; + +/* Set return status and error flags (if applicable). */ +switch (ha->mbox_status[0 ]) { +case MBOX_STS_COMMAND_COMPLETE : + status =QLA_SUCCESS ; +break ; + +case MBOX_STS_INTERMEDIATE_COMPLETION : + status =QLA_SUCCESS ; +break ; + +case MBOX_STS_BUSY : +DEBUG2 (printk ("scsi%ld: %s: Cmd = %08X, ISP BUSY\n" , + ha->host_no, __func__, mbx_cmd[0 ])); + ha->mailbox_timeout_count++; +break ; + +default : +DEBUG2 (printk ("scsi%ld: %s: **** FAILED, cmd = %08X, " +"sts = %08X ****\n" , ha->host_no, __func__, + mbx_cmd[0 ], mbx_sts[0 ])); +break ; + } +spin_unlock_irqrestore (&ha->hardware_lock, flags); + +mbox_exit: +clear_bit (AF_MBOX_COMMAND , &ha->flags); +clear_bit (AF_MBOX_COMMAND_DONE , &ha->flags); +mutex_unlock (&ha->mbox_sem); + +return status; +} + + +/* +* qla4xxx_issue_iocb +* Issue IOCB using mailbox command +* +* Input: +* ha = adapter state pointer. +* buffer = buffer pointer. +* phys_addr = physical address of buffer. +* size = size of buffer. +* TARGET_QUEUE_LOCK must be released. +* ADAPTER_STATE_LOCK must be released. +* +* Returns: +* qla2x00 local function return status code. +*/ +int +qla4xxx_issue_iocb (struct scsi_qla_host * ha,void *buffer, +dma_addr_t phys_addr,size_t size) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; +int status; + +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_EXECUTE_IOCB_A64 ; + mbox_cmd[1 ] =0 ; + mbox_cmd[2 ] =LSDW (phys_addr); + mbox_cmd[3 ] =MSDW (phys_addr); + status =qla4xxx_mailbox_command (ha,4 ,1 , &mbox_cmd[0 ], &mbox_sts[0 ]); +return status; +} + +int qla4xxx_conn_close_sess_logout (struct scsi_qla_host * ha, +uint16_t fw_ddb_index, +uint16_t connection_id, +uint16_t option) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_CONN_CLOSE_SESS_LOGOUT ; + mbox_cmd[1 ] = fw_ddb_index; + mbox_cmd[2 ] = connection_id; + mbox_cmd[3 ] =LOGOUT_OPTION_RELOGIN ; +if (qla4xxx_mailbox_command (ha,4 ,2 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT " +"option %04x failed sts %04X %04X" , + ha->host_no, __func__, + option, mbox_sts[0 ], mbox_sts[1 ])); +if (mbox_sts[0 ] ==0x4005 ) +DEBUG2 (printk ("%s reason %04X\n" , __func__, + mbox_sts[1 ])); + } +return QLA_SUCCESS ; +} + +int qla4xxx_clear_database_entry (struct scsi_qla_host * ha, +uint16_t fw_ddb_index) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_CLEAR_DATABASE_ENTRY ; + mbox_cmd[1 ] = fw_ddb_index; +if (qla4xxx_mailbox_command (ha,2 ,5 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) +return QLA_ERROR ; + +return QLA_SUCCESS ; +} + +/************************************************************************** +* qla4xxx_initialize_fw_cb +* This routine initializes the firmware control block for the +* specified adapter. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* QLA_SUCCESS - Successfully initialized firmware ctrl block +* QLA_ERROR - Failed to initialize firmware ctrl block +**************************************************************************/ +int qla4xxx_initialize_fw_cb (struct scsi_qla_host * ha) +{ +struct init_fw_ctrl_blk *init_fw_cb; +dma_addr_t init_fw_cb_dma; +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; +int status =QLA_ERROR ; + + init_fw_cb =dma_alloc_coherent (&ha->pdev->dev, +sizeof (struct init_fw_ctrl_blk ), + &init_fw_cb_dma,GFP_KERNEL ); +if (init_fw_cb ==NULL ) { +DEBUG2 (printk ("scsi%ld: %s: Unable to alloc init_cb\n" , + ha->host_no, __func__)); +return 10 ; + } +memset (init_fw_cb,0 ,sizeof (struct init_fw_ctrl_blk )); + +/* Get Initialize Firmware Control Block. */ +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_GET_INIT_FW_CTRL_BLOCK ; + mbox_cmd[2 ] =LSDW (init_fw_cb_dma); + mbox_cmd[3 ] =MSDW (init_fw_cb_dma); +if (qla4xxx_mailbox_command (ha,4 ,1 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +dma_free_coherent (&ha->pdev->dev, +sizeof (struct init_fw_ctrl_blk ), + init_fw_cb, init_fw_cb_dma); +return status; + } + +/* Initialize request and response queues. */ +qla4xxx_init_rings (ha); + +/* Fill in the request and response queue information. */ + init_fw_cb->ReqQConsumerIndex =cpu_to_le16 (ha->request_out); + init_fw_cb->ComplQProducerIndex =cpu_to_le16 (ha->response_in); + init_fw_cb->ReqQLen =__constant_cpu_to_le16 (REQUEST_QUEUE_DEPTH ); + init_fw_cb->ComplQLen =__constant_cpu_to_le16 (RESPONSE_QUEUE_DEPTH ); + init_fw_cb->ReqQAddrLo =cpu_to_le32 (LSDW (ha->request_dma)); + init_fw_cb->ReqQAddrHi =cpu_to_le32 (MSDW (ha->request_dma)); + init_fw_cb->ComplQAddrLo =cpu_to_le32 (LSDW (ha->response_dma)); + init_fw_cb->ComplQAddrHi =cpu_to_le32 (MSDW (ha->response_dma)); + init_fw_cb->ShadowRegBufAddrLo = +cpu_to_le32 (LSDW (ha->shadow_regs_dma)); + init_fw_cb->ShadowRegBufAddrHi = +cpu_to_le32 (MSDW (ha->shadow_regs_dma)); + +/* Set up required options. */ + init_fw_cb->FwOptions |= +__constant_cpu_to_le16 (FWOPT_SESSION_MODE | +FWOPT_INITIATOR_MODE ); + init_fw_cb->FwOptions &=__constant_cpu_to_le16 (~FWOPT_TARGET_MODE ); + +/* Save some info in adapter structure. */ + ha->firmware_options =le16_to_cpu (init_fw_cb->FwOptions); + ha->tcp_options =le16_to_cpu (init_fw_cb->TCPOptions); + ha->heartbeat_interval = init_fw_cb->HeartbeatInterval; + ha->isns_server_port_number = +le16_to_cpu (init_fw_cb->iSNSServerPortNumber); +memcpy (ha->ip_address, init_fw_cb->IPAddr, +min (sizeof (ha->ip_address),sizeof (init_fw_cb->IPAddr))); +memcpy (ha->subnet_mask, init_fw_cb->SubnetMask, +min (sizeof (ha->subnet_mask),sizeof (init_fw_cb->SubnetMask))); +memcpy (ha->gateway, init_fw_cb->GatewayIPAddr, +min (sizeof (ha->gateway),sizeof (init_fw_cb->GatewayIPAddr))); +memcpy (ha->isns_ip_address, init_fw_cb->iSNSIPAddr, +min (sizeof (ha->isns_ip_address), +sizeof (init_fw_cb->iSNSIPAddr))); +memcpy (ha->name_string, init_fw_cb->iSCSINameString, +min (sizeof (ha->name_string), +sizeof (init_fw_cb->iSCSINameString))); +memcpy (ha->alias, init_fw_cb->Alias, +min (sizeof (ha->alias),sizeof (init_fw_cb->Alias))); + +/* Save Command Line Paramater info */ + ha->port_down_retry_count =le16_to_cpu (init_fw_cb->KeepAliveTimeout); + ha->discovery_wait = ql4xdiscoverywait; + +/* Send Initialize Firmware Control Block. */ + mbox_cmd[0 ] =MBOX_CMD_INITIALIZE_FIRMWARE ; + mbox_cmd[1 ] =0 ; + mbox_cmd[2 ] =LSDW (init_fw_cb_dma); + mbox_cmd[3 ] =MSDW (init_fw_cb_dma); +if (qla4xxx_mailbox_command (ha,4 ,1 , &mbox_cmd[0 ], &mbox_sts[0 ]) == +QLA_SUCCESS ) + status =QLA_SUCCESS ; +else { +DEBUG2 (printk ("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE " +"failed w/ status %04X\n" , ha->host_no, __func__, + mbox_sts[0 ])); + } +dma_free_coherent (&ha->pdev->dev,sizeof (struct init_fw_ctrl_blk ), + init_fw_cb, init_fw_cb_dma); + +return status; +} + +/************************************************************************** +* qla4xxx_get_dhcp_ip_address +* This routine retrieves the IP Address obtained via DHCP for the +* specified adapter. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* QLA_SUCCESS - Successfully obtained DHCP IP Address +* QLA_ERROR - Failed to obtained +**************************************************************************/ +int qla4xxx_get_dhcp_ip_address (struct scsi_qla_host * ha) +{ +struct init_fw_ctrl_blk *init_fw_cb; +dma_addr_t init_fw_cb_dma; +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + + init_fw_cb =dma_alloc_coherent (&ha->pdev->dev, +sizeof (struct init_fw_ctrl_blk ), + &init_fw_cb_dma,GFP_KERNEL ); +if (init_fw_cb ==NULL ) { +printk ("scsi%ld: %s: Unable to alloc init_cb\n" , ha->host_no, + __func__); +return 10 ; + } + +/* Get Initialize Firmware Control Block. */ +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); +memset (init_fw_cb,0 ,sizeof (struct init_fw_ctrl_blk )); + mbox_cmd[0 ] =MBOX_CMD_GET_INIT_FW_CTRL_BLOCK ; + mbox_cmd[2 ] =LSDW (init_fw_cb_dma); + mbox_cmd[3 ] =MSDW (init_fw_cb_dma); + +if (qla4xxx_mailbox_command (ha,4 ,1 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n" , + ha->host_no, __func__)); +dma_free_coherent (&ha->pdev->dev, +sizeof (struct init_fw_ctrl_blk ), + init_fw_cb, init_fw_cb_dma); +return QLA_ERROR ; + } + +/* Save IP Address. */ +memcpy (ha->ip_address, init_fw_cb->IPAddr, +min (sizeof (ha->ip_address),sizeof (init_fw_cb->IPAddr))); +memcpy (ha->subnet_mask, init_fw_cb->SubnetMask, +min (sizeof (ha->subnet_mask),sizeof (init_fw_cb->SubnetMask))); +memcpy (ha->gateway, init_fw_cb->GatewayIPAddr, +min (sizeof (ha->gateway),sizeof (init_fw_cb->GatewayIPAddr))); + +dma_free_coherent (&ha->pdev->dev,sizeof (struct init_fw_ctrl_blk ), + init_fw_cb, init_fw_cb_dma); + +return QLA_SUCCESS ; +} + +/************************************************************************** +* qla4xxx_get_firmware_state +* This routine retrieves the firmware state for the specified adapter. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* QLA_SUCCESS - Successfully retrieved firmware state +* QLA_ERROR - Failed to retrieve firmware state +**************************************************************************/ +int qla4xxx_get_firmware_state (struct scsi_qla_host * ha) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +/* Get firmware version */ +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_GET_FW_STATE ; +if (qla4xxx_mailbox_command (ha,1 ,4 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ " +"status %04X\n" , ha->host_no, __func__, + mbox_sts[0 ])); +return QLA_ERROR ; + } + ha->firmware_state = mbox_sts[1 ]; + ha->board_id = mbox_sts[2 ]; + ha->addl_fw_state = mbox_sts[3 ]; +DEBUG2 (printk ("scsi%ld: %s firmware_state=0x%x\n" , + ha->host_no, __func__, ha->firmware_state);) + +return QLA_SUCCESS ; +} + +/************************************************************************** +* qla4xxx_get_firmware_status +* This routine retrieves the firmware status for the specified adapter. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* QLA_SUCCESS - Successfully retrieved firmware status +* QLA_ERROR - Failed to retrieve firmware status +**************************************************************************/ +int qla4xxx_get_firmware_status (struct scsi_qla_host * ha) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +/* Get firmware version */ +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_GET_FW_STATUS ; +if (qla4xxx_mailbox_command (ha,1 ,3 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ " +"status %04X\n" , ha->host_no, __func__, + mbox_sts[0 ])); +return QLA_ERROR ; + } + +/* High-water mark of IOCBs */ + ha->iocb_hiwat = mbox_sts[2 ]; +if (ha->iocb_hiwat >IOCB_HIWAT_CUSHION ) + ha->iocb_hiwat -=IOCB_HIWAT_CUSHION ; +else +ql4_printk (KERN_INFO , ha,"WARNING!!! You have less than %d " +"firmare IOCBs available (%d).\n" , +IOCB_HIWAT_CUSHION , ha->iocb_hiwat); + +return QLA_SUCCESS ; +} + +/************************************************************************** +* qla4xxx_get_fwddb_entry +* This routine retrieves the firmware's device database entry. +* +* Input: +* ha - Pointer to host adapter structure. +* fw_ddb_index - Firmware's device database index +* fw_ddb_entry - Pointer to firmware's device database entry structure +* num_valid_ddb_entries - Pointer to number of valid ddb entries +* next_ddb_index - Pointer to next valid device database index +* fw_ddb_device_state - Pointer to device state +* +* Output: +* fw_ddb_entry - Fills in structure if pointer is supplied +* num_valid_ddb_entries - Fills in if pointer is supplied +* next_ddb_index - Fills in if pointer is supplied +* fw_ddb_device_state - Fills in if pointer is supplied +* +* Returns: +* QLA_SUCCESS - Successfully retrieved ddb info from firmware +* QLA_ERROR - Failed to retrieve ddb info from firmware +**************************************************************************/ +int qla4xxx_get_fwddb_entry (struct scsi_qla_host *ha, +uint16_t fw_ddb_index, +struct dev_db_entry *fw_ddb_entry, +dma_addr_t fw_ddb_entry_dma, +uint32_t *num_valid_ddb_entries, +uint32_t *next_ddb_index, +uint32_t *fw_ddb_device_state, +uint32_t *conn_err_detail, +uint16_t *tcp_source_port_num, +uint16_t *connection_id) +{ +int status =QLA_ERROR ; +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +/* Make sure the device index is valid */ +if (fw_ddb_index >=MAX_DDB_ENTRIES ) { +DEBUG2 (printk ("scsi%ld: %s: index [%d] out of range.\n" , + ha->host_no, __func__, fw_ddb_index)); + goto exit_get_fwddb; + } +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_GET_DATABASE_ENTRY ; + mbox_cmd[1 ] = (uint32_t ) fw_ddb_index; + mbox_cmd[2 ] =LSDW (fw_ddb_entry_dma); + mbox_cmd[3 ] =MSDW (fw_ddb_entry_dma); +if (qla4xxx_mailbox_command (ha,4 ,7 , &mbox_cmd[0 ], &mbox_sts[0 ]) == +QLA_ERROR ) { +DEBUG2 (printk ("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed" +" with status 0x%04X\n" , ha->host_no, __func__, + mbox_sts[0 ])); + goto exit_get_fwddb; + } +if (fw_ddb_index != mbox_sts[1 ]) { +DEBUG2 (printk ("scsi%ld: %s: index mismatch [%d] != [%d].\n" , + ha->host_no, __func__, fw_ddb_index, + mbox_sts[1 ])); + goto exit_get_fwddb; + } +if (fw_ddb_entry) { +ql4_printk (KERN_INFO , ha,"DDB[%d] MB0 %04x Tot %d Next %d " +"State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n" , + fw_ddb_index, mbox_sts[0 ], mbox_sts[2 ], mbox_sts[3 ], + mbox_sts[4 ], mbox_sts[5 ], fw_ddb_entry->ipAddr[0 ], + fw_ddb_entry->ipAddr[1 ], fw_ddb_entry->ipAddr[2 ], + fw_ddb_entry->ipAddr[3 ], +le16_to_cpu (fw_ddb_entry->portNumber), + fw_ddb_entry->iscsiName); + } +if (num_valid_ddb_entries) + *num_valid_ddb_entries = mbox_sts[2 ]; +if (next_ddb_index) + *next_ddb_index = mbox_sts[3 ]; +if (fw_ddb_device_state) + *fw_ddb_device_state = mbox_sts[4 ]; + +/* +* RA: This mailbox has been changed to pass connection error and +* details. Its true for ISP4010 as per Version E - Not sure when it +* was changed. Get the time2wait from the fw_dd_entry field : +* default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY +* struct. +*/ +if (conn_err_detail) + *conn_err_detail = mbox_sts[5 ]; +if (tcp_source_port_num) + *tcp_source_port_num = (uint16_t ) mbox_sts[6 ] >>16 ; +if (connection_id) + *connection_id = (uint16_t ) mbox_sts[6 ] &0x00FF ; + status =QLA_SUCCESS ; + +exit_get_fwddb: +return status; +} + +/************************************************************************** +* qla4xxx_set_fwddb_entry +* This routine initializes or updates the adapter's device database +* entry for the specified device. +* +* Input: +* ha - Pointer to host adapter structure. +* fw_ddb_index - Firmware's device database index +* fw_ddb_entry - Pointer to firmware's device database entry +* structure, or NULL. +* +* Output: +* None +* +* Remarks: +* This routine also triggers a login for the specified device. +* Therefore, it may also be used as a secondary login routine when +* a NULL pointer is specified for the fw_ddb_entry. +* +* Returns: +* QLA_SUCCESS - Successfully set ddb_entry in firmware +* QLA_ERROR - Failed to set ddb_entry in firmware +**************************************************************************/ +int qla4xxx_set_ddb_entry (struct scsi_qla_host * ha,uint16_t fw_ddb_index, +dma_addr_t fw_ddb_entry_dma) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +/* Do not wait for completion. The firmware will send us an +* ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. +*/ +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + + mbox_cmd[0 ] =MBOX_CMD_SET_DATABASE_ENTRY ; + mbox_cmd[1 ] = (uint32_t ) fw_ddb_index; + mbox_cmd[2 ] =LSDW (fw_ddb_entry_dma); + mbox_cmd[3 ] =MSDW (fw_ddb_entry_dma); +return qla4xxx_mailbox_command (ha,4 ,1 , &mbox_cmd[0 ], &mbox_sts[0 ]); +} + +int qla4xxx_conn_open_session_login (struct scsi_qla_host * ha, +uint16_t fw_ddb_index) +{ +int status =QLA_ERROR ; +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +/* Do not wait for completion. The firmware will send us an +* ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. +*/ +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_CONN_OPEN_SESS_LOGIN ; + mbox_cmd[1 ] = (uint32_t ) fw_ddb_index; + mbox_cmd[2 ] =0 ; + mbox_cmd[3 ] =0 ; + mbox_cmd[4 ] =0 ; + status =qla4xxx_mailbox_command (ha,4 ,0 , &mbox_cmd[0 ], &mbox_sts[0 ]); +DEBUG2 (printk ("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n" , + __func__, fw_ddb_index, status, mbox_sts[0 ], + mbox_sts[1]);) + +return status; +} + +/************************************************************************** +* qla4xxx_get_crash_record +* This routine retrieves a crash record from the QLA4010 after an +* 8002h aen. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* None +**************************************************************************/ +void qla4xxx_get_crash_record (struct scsi_qla_host * ha) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; +struct crash_record *crash_record =NULL ; +dma_addr_t crash_record_dma =0 ; +uint32_t crash_record_size =0 ; +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_cmd)); + +/* Get size of crash record. */ + mbox_cmd[0 ] =MBOX_CMD_GET_CRASH_RECORD ; +if (qla4xxx_mailbox_command (ha,5 ,5 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: ERROR: Unable to retrieve size!\n" , + ha->host_no, __func__)); + goto exit_get_crash_record; + } + crash_record_size = mbox_sts[4 ]; +if (crash_record_size ==0 ) { +DEBUG2 (printk ("scsi%ld: %s: ERROR: Crash record size is 0!\n" , + ha->host_no, __func__)); + goto exit_get_crash_record; + } + +/* Alloc Memory for Crash Record. */ + crash_record =dma_alloc_coherent (&ha->pdev->dev, crash_record_size, + &crash_record_dma,GFP_KERNEL ); +if (crash_record ==NULL ) + goto exit_get_crash_record; + +/* Get Crash Record. */ + mbox_cmd[0 ] =MBOX_CMD_GET_CRASH_RECORD ; + mbox_cmd[2 ] =LSDW (crash_record_dma); + mbox_cmd[3 ] =MSDW (crash_record_dma); + mbox_cmd[4 ] = crash_record_size; +if (qla4xxx_mailbox_command (ha,5 ,5 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) + goto exit_get_crash_record; + +/* Dump Crash Record. */ + +exit_get_crash_record: +if (crash_record) +dma_free_coherent (&ha->pdev->dev, crash_record_size, + crash_record, crash_record_dma); +} + +/************************************************************************** +* qla4xxx_get_conn_event_log +* This routine retrieves the connection event log +* +* Input: +* ha - Pointer to host adapter structure. +* +* Returns: +* None +**************************************************************************/ +void qla4xxx_get_conn_event_log (struct scsi_qla_host * ha) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; +struct conn_event_log_entry *event_log =NULL ; +dma_addr_t event_log_dma =0 ; +uint32_t event_log_size =0 ; +uint32_t num_valid_entries; +uint32_t oldest_entry =0 ; +uint32_t max_event_log_entries; +uint8_t i; + + +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_cmd)); + +/* Get size of crash record. */ + mbox_cmd[0 ] =MBOX_CMD_GET_CONN_EVENT_LOG ; +if (qla4xxx_mailbox_command (ha,4 ,5 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) + goto exit_get_event_log; + + event_log_size = mbox_sts[4 ]; +if (event_log_size ==0 ) + goto exit_get_event_log; + +/* Alloc Memory for Crash Record. */ + event_log =dma_alloc_coherent (&ha->pdev->dev, event_log_size, + &event_log_dma,GFP_KERNEL ); +if (event_log ==NULL ) + goto exit_get_event_log; + +/* Get Crash Record. */ + mbox_cmd[0 ] =MBOX_CMD_GET_CONN_EVENT_LOG ; + mbox_cmd[2 ] =LSDW (event_log_dma); + mbox_cmd[3 ] =MSDW (event_log_dma); +if (qla4xxx_mailbox_command (ha,4 ,5 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: ERROR: Unable to retrieve event " +"log!\n" , ha->host_no, __func__)); + goto exit_get_event_log; + } + +/* Dump Event Log. */ + num_valid_entries = mbox_sts[1 ]; + + max_event_log_entries = event_log_size / +sizeof (struct conn_event_log_entry ); + +if (num_valid_entries > max_event_log_entries) + oldest_entry = num_valid_entries % max_event_log_entries; + +DEBUG3 (printk ("scsi%ld: Connection Event Log Dump (%d entries):\n" , + ha->host_no, num_valid_entries)); + +if (extended_error_logging ==3 ) { +if (oldest_entry ==0 ) { +/* Circular Buffer has not wrapped around */ +for (i=0 ; i < num_valid_entries; i++) { +qla4xxx_dump_buffer ((uint8_t *)event_log+ + (i*sizeof (*event_log)), +sizeof (*event_log)); + } + } +else { +/* Circular Buffer has wrapped around - +* display accordingly*/ +for (i=oldest_entry; i < max_event_log_entries; i++) { +qla4xxx_dump_buffer ((uint8_t *)event_log+ + (i*sizeof (*event_log)), +sizeof (*event_log)); + } +for (i=0 ; i < oldest_entry; i++) { +qla4xxx_dump_buffer ((uint8_t *)event_log+ + (i*sizeof (*event_log)), +sizeof (*event_log)); + } + } + } + +exit_get_event_log: +if (event_log) +dma_free_coherent (&ha->pdev->dev, event_log_size, event_log, + event_log_dma); +} + +/************************************************************************** +* qla4xxx_reset_lun +* This routine performs a LUN RESET on the specified target/lun. +* +* Input: +* ha - Pointer to host adapter structure. +* ddb_entry - Pointer to device database entry +* lun_entry - Pointer to lun entry structure +* +* Remarks: +* The caller must ensure that the ddb_entry and lun_entry pointers +* are valid before calling this routine. +* +* Returns: +* QLA_SUCCESS - lun reset completed successfully +* QLA_ERROR - lun reset failed +**************************************************************************/ +int qla4xxx_reset_lun (struct scsi_qla_host * ha,struct ddb_entry * ddb_entry, +int lun) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; +int status =QLA_SUCCESS ; + +DEBUG2 (printk ("scsi%ld:%d:%d: lun reset issued\n" , ha->host_no, + ddb_entry->os_target_id, lun)); + +/* +* Send lun reset command to ISP, so that the ISP will return all +* outstanding requests with RESET status +*/ +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_LUN_RESET ; + mbox_cmd[1 ] = ddb_entry->fw_ddb_index; + mbox_cmd[2 ] = lun <<8 ; + mbox_cmd[5 ] =0x01 ;/* Immediate Command Enable */ +qla4xxx_mailbox_command (ha,6 ,1 , &mbox_cmd[0 ], &mbox_sts[0 ]); +if (mbox_sts[0 ] !=MBOX_STS_COMMAND_COMPLETE && + mbox_sts[0 ] !=MBOX_STS_COMMAND_ERROR ) + status =QLA_ERROR ; + +return status; +} + + +int qla4xxx_get_flash (struct scsi_qla_host * ha,dma_addr_t dma_addr, +uint32_t offset,uint32_t len) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_READ_FLASH ; + mbox_cmd[1 ] =LSDW (dma_addr); + mbox_cmd[2 ] =MSDW (dma_addr); + mbox_cmd[3 ] = offset; + mbox_cmd[4 ] = len; +if (qla4xxx_mailbox_command (ha,5 ,2 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ " +"status %04X %04X, offset %08x, len %08x\n" , ha->host_no, + __func__, mbox_sts[0 ], mbox_sts[1 ], offset, len)); +return QLA_ERROR ; + } +return QLA_SUCCESS ; +} + +/************************************************************************** +* qla4xxx_get_fw_version +* This routine retrieves the firmware version for the specified adapter. +* +* Input: +* ha - Pointer to host adapter structure. +* +* Output: +* None +* +* Remarks: +* In QLA4010, mailboxes 2 & 3 may hold an address for data. Make sure +* that we write 0 to those mailboxes, if unused. +* +* Returns: +* QLA_SUCCESS - Successfully retrieved firmware version +* QLA_ERROR - Failed to retrieve firmware version +**************************************************************************/ +int qla4xxx_get_fw_version (struct scsi_qla_host * ha) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +/* Get firmware version. */ +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + mbox_cmd[0 ] =MBOX_CMD_ABOUT_FW ; +if (qla4xxx_mailbox_command (ha,4 ,5 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ " +"status %04X\n" , ha->host_no, __func__, mbox_sts[0 ])); +return QLA_ERROR ; + } + +/* Save firmware version information. */ + ha->firmware_version[0 ] = mbox_sts[1 ]; + ha->firmware_version[1 ] = mbox_sts[2 ]; + ha->patch_number = mbox_sts[3 ]; + ha->build_number = mbox_sts[4 ]; + +return QLA_SUCCESS ; +} + +int qla4xxx_get_default_ddb (struct scsi_qla_host *ha,dma_addr_t dma_addr) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + + mbox_cmd[0 ] =MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS ; + mbox_cmd[2 ] =LSDW (dma_addr); + mbox_cmd[3 ] =MSDW (dma_addr); + +if (qla4xxx_mailbox_command (ha,4 ,1 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: failed status %04X\n" , + ha->host_no, __func__, mbox_sts[0 ])); +return QLA_ERROR ; + } +return QLA_SUCCESS ; +} + +int qla4xxx_req_ddb_entry (struct scsi_qla_host *ha,uint32_t *ddb_index) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + + mbox_cmd[0 ] =MBOX_CMD_REQUEST_DATABASE_ENTRY ; + mbox_cmd[1 ] =MAX_PRST_DEV_DB_ENTRIES ; + +if (qla4xxx_mailbox_command (ha,2 ,3 , &mbox_cmd[0 ], &mbox_sts[0 ]) != +QLA_SUCCESS ) { +if (mbox_sts[0 ] ==MBOX_STS_COMMAND_ERROR ) { + *ddb_index = mbox_sts[2 ]; + }else { +DEBUG2 (printk ("scsi%ld: %s: failed status %04X\n" , + ha->host_no, __func__, mbox_sts[0 ])); +return QLA_ERROR ; + } + }else { + *ddb_index =MAX_PRST_DEV_DB_ENTRIES ; + } + +return QLA_SUCCESS ; +} + +int qla4xxx_isns (struct scsi_qla_host *ha,uint32_t enable, +char *ip,uint16_t port,struct qla_isns_rsp *isns_rsp) +{ +uint32_t mbox_cmd[MBOX_REG_COUNT ]; +uint32_t mbox_sts[MBOX_REG_COUNT ]; + +while (test_and_set_bit (AF_ISNS_CMD_IN_PROCESS , &ha->flags) & +AF_ISNS_CMD_IN_PROCESS ) { +msleep (10 ); + } +/* Get firmware version. */ +memset (&mbox_cmd,0 ,sizeof (mbox_cmd)); +memset (&mbox_sts,0 ,sizeof (mbox_sts)); + + mbox_cmd[0 ] =MBOX_CMD_SET_ISNS_SERVICE ; +if (enable) { + mbox_cmd[1 ] =ISNS_ENABLE ; + }else { + mbox_cmd[1 ] =ISNS_DISABLE ; + } + mbox_cmd[2 ] = *((uint32_t *)ip); + mbox_cmd[3 ] = port; + +if (qla4xxx_mailbox_command (ha,4 ,6 , &mbox_cmd[0 ], &mbox_sts[0 ]) + !=QLA_SUCCESS ) { +DEBUG2 (printk ("scsi%ld: %s: MBOX_CMD_SET_ISNS_SERVICE failed " +"w/ status %04X %04X\n" , + ha->host_no, __func__, mbox_sts[0 ], + mbox_sts[1 ])); +clear_bit (AF_ISNS_CMD_IN_PROCESS , &ha->flags); +return QLA_ERROR ; + } + +if (enable) { +if (mbox_cmd[0 ] ==MBOX_STS_INTERMEDIATE_COMPLETION ) { +/* wait for the AEN to complete the call */ +while (test_bit (AF_ISNS_CMD_DONE , &ha->flags)) { +msleep (10 ); + } +clear_bit (AF_ISNS_CMD_DONE , &ha->flags); + +memcpy (isns_rsp, &ha->isns_rsp, +sizeof (struct qla_isns_rsp )); + }else { + isns_rsp->conn_id = (uint16_t )(mbox_sts[2 ] &0xFFFF ); + isns_rsp->scn_conn_id = + (uint16_t )(mbox_sts[3 ] &0xFFFF ); + isns_rsp->esi_conn_id = + (uint16_t )(mbox_sts[4 ] &0xFFFF ); + + isns_rsp->conn_port = (uint16_t )(mbox_sts[2 ] >>16 ); + isns_rsp->scn_port = (uint16_t )(mbox_sts[3 ] >>16 ); + isns_rsp->esi_port = (uint16_t )(mbox_sts[4 ] >>16 ); + } + } + +clear_bit (AF_ISNS_CMD_IN_PROCESS , &ha->flags); + +return QLA_SUCCESS ; +} + +int qla4xxx_send_tgts (struct scsi_qla_host *ha,char *ip,uint16_t port) +{ +struct dev_db_entry *fw_ddb_entry; +dma_addr_t fw_ddb_entry_dma; +uint32_t ddb_index; +int ret_val =QLA_SUCCESS ; + + + fw_ddb_entry =dma_alloc_coherent (&ha->pdev->dev, +sizeof (*fw_ddb_entry), + &fw_ddb_entry_dma,GFP_KERNEL ); +if (!fw_ddb_entry) { +DEBUG2 (printk ("scsi%ld: %s: Unable to allocate dma buffer.\n" , + ha->host_no, __func__)); + ret_val =QLA_ERROR ; + goto qla4xxx_send_tgts_exit; + } + + ret_val =qla4xxx_get_default_ddb (ha, fw_ddb_entry_dma); +if (ret_val !=QLA_SUCCESS ) + goto qla4xxx_send_tgts_exit; + + ret_val =qla4xxx_req_ddb_entry (ha, &ddb_index); +if (ret_val !=QLA_SUCCESS ) + goto qla4xxx_send_tgts_exit; + +memset ((void *)fw_ddb_entry->iSCSIAlias,0 , +sizeof (fw_ddb_entry->iSCSIAlias)); + +memset ((void *)fw_ddb_entry->iscsiName,0 , +sizeof (fw_ddb_entry->iscsiName)); + +memset ((void *)fw_ddb_entry->ipAddr,0 ,sizeof (fw_ddb_entry->ipAddr)); +memset ((void *)fw_ddb_entry->targetAddr,0 , +sizeof (fw_ddb_entry->targetAddr)); + + fw_ddb_entry->options = (DDB_OPT_DISC_SESSION |DDB_OPT_TARGET ); + fw_ddb_entry->portNumber =cpu_to_le16 (ntohs (port)); + + fw_ddb_entry->ipAddr[0 ] = *ip; + fw_ddb_entry->ipAddr[1 ] = *(ip +1 ); + fw_ddb_entry->ipAddr[2 ] = *(ip +2 ); + fw_ddb_entry->ipAddr[3 ] = *(ip +3 ); + + ret_val =qla4xxx_set_ddb_entry (ha, ddb_index, fw_ddb_entry_dma); + +qla4xxx_send_tgts_exit: +dma_free_coherent (&ha->pdev->dev,sizeof (*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); +return ret_val; +} +
RFC PATCH 6/7 qla4xxx: driver support routines
qla4xxx driver support routines.
Signed-off-by Ravi Anand <[email protected]>
Signed-off-by David Somayajulu <[email protected]>
Signed-off-by Doug Maxey <[email protected]>
Signed-off-by Mike Christie <[email protected]>
---
drivers/scsi/qla4xxx/ql4_dbg.c new file +215 -0
@@ -0,0 +1,215 @@ +/* +* QLogic iSCSI HBA Driver +* Copyright (c) 2003-2006 QLogic Corporation +* +* See LICENSE.qla4xxx for copyright and licensing details. +*/ + +#include "ql4_def.h" + +/* +* qla4xxx_print_srb_cmd +* This routine displays the SRB command +*/ +static void qla4xxx_print_srb_info (struct srb * srb) +{ +printk ("%s: srb = 0x%p, flags=0x%02x\n" , __func__, srb, srb->flags); +printk ("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n" , + __func__, srb->cmd, (unsigned long ) srb->dma_handle); +printk ("%s: fw_ddb_index = %d, lun = %d\n" , + __func__, srb->fw_ddb_index, srb->cmd->device->lun); +printk ("%s: iocb_tov = %d\n" , + __func__, srb->iocb_tov); +printk ("%s: cc_stat = 0x%x, r_start = 0x%lx, u_start = 0x%lx\n\n" , + __func__, srb->cc_stat, srb->r_start, srb->u_start); +} + +/* +* qla4xxx_print_scsi_cmd +* This routine displays the SCSI command +*/ +void qla4xxx_print_scsi_cmd (struct scsi_cmnd *cmd) +{ +int i; +printk ("SCSI Command = 0x%p, Handle=0x%p\n" , cmd, cmd->host_scribble); +printk (" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n" , + cmd->device->channel, cmd->device->id, cmd->device->lun, + cmd->cmd_len); +printk (" CDB = " ); +for (i =0 ; i < cmd->cmd_len; i++) +printk ("%02x " , cmd->cmnd[i]); +printk (" seg_cnt = %d\n" , cmd->use_sg); +printk (" request buffer = 0x%p, request buffer len = 0x%x\n" , + cmd->request_buffer, cmd->request_bufflen); +if (cmd->use_sg) { +struct scatterlist *sg; + sg = (struct scatterlist *)cmd->request_buffer; +printk (" SG buffer: \n" ); +qla4xxx_dump_buffer ((caddr_t ) sg, + (cmd->use_sg *sizeof (*sg))); + } +printk (" tag = %d, transfersize = 0x%x \n" , cmd->tag, + cmd->transfersize); +printk (" Pid = %d, SP = 0x%p\n" , (int )cmd->pid, cmd->SCp.ptr); +printk (" underflow size = 0x%x, direction=0x%x\n" , cmd->underflow, + cmd->sc_data_direction); +printk (" Current time (jiffies) = 0x%lx, " +"timeout expires = 0x%lx\n" , jiffies, cmd->eh_timeout.expires); +qla4xxx_print_srb_info ((struct srb *) cmd->SCp.ptr); +} + +void __dump_registers (struct scsi_qla_host *ha) +{ +uint8_t i; +for (i =0 ; i <MBOX_REG_COUNT ; i++) { +printk (KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n" , + (uint8_t) offsetof(struct isp_reg, mailbox[i]), i, + readw(&ha->reg->mailbox[i])); + } +printk (KERN_INFO "0x%02X flash_address = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , flash_address), +readw (&ha->reg->flash_address)); +printk (KERN_INFO "0x%02X flash_data = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , flash_data), +readw (&ha->reg->flash_data)); +printk (KERN_INFO "0x%02X ctrl_status = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , ctrl_status), +readw (&ha->reg->ctrl_status)); +if (is_qla4010 (ha)) { +printk (KERN_INFO "0x%02X nvram = 0x%08X\n" , + (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram), + readw(&ha->reg->u1.isp4010.nvram)); + } + +else if (is_qla4022 (ha)) { +printk (KERN_INFO "0x%02X intr_mask = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u1.isp4022.intr_mask), + readw(&ha->reg->u1.isp4022.intr_mask)); +printk (KERN_INFO "0x%02X nvram = 0x%08X\n" , + (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram), + readw(&ha->reg->u1.isp4022.nvram)); +printk (KERN_INFO "0x%02X semaphore = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u1.isp4022.semaphore), + readw(&ha->reg->u1.isp4022.semaphore)); + } +printk (KERN_INFO "0x%02X req_q_in = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , req_q_in), +readw (&ha->reg->req_q_in)); +printk (KERN_INFO "0x%02X rsp_q_out = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , rsp_q_out), +readw (&ha->reg->rsp_q_out)); +if (is_qla4010 (ha)) { +printk (KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4010.ext_hw_conf), + readw(&ha->reg->u2.isp4010.ext_hw_conf)); +printk (KERN_INFO "0x%02X port_ctrl = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4010.port_ctrl), + readw(&ha->reg->u2.isp4010.port_ctrl)); +printk (KERN_INFO "0x%02X port_status = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4010.port_status), + readw(&ha->reg->u2.isp4010.port_status)); +printk (KERN_INFO "0x%02X req_q_out = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4010.req_q_out), + readw(&ha->reg->u2.isp4010.req_q_out)); +printk (KERN_INFO "0x%02X gp_out = 0x%08X\n" , + (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out), + readw(&ha->reg->u2.isp4010.gp_out)); +printk (KERN_INFO "0x%02X gp_in = 0x%08X\n" , + (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in), + readw(&ha->reg->u2.isp4010.gp_in)); +printk (KERN_INFO "0x%02X port_err_status = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4010.port_err_status), + readw(&ha->reg->u2.isp4010.port_err_status)); + } + +else if (is_qla4022 (ha)) { +printk (KERN_INFO "Page 0 Registers:\n" ); +printk (KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4022.p0.ext_hw_conf), + readw(&ha->reg->u2.isp4022.p0.ext_hw_conf)); +printk (KERN_INFO "0x%02X port_ctrl = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4022.p0.port_ctrl), + readw(&ha->reg->u2.isp4022.p0.port_ctrl)); +printk (KERN_INFO "0x%02X port_status = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4022.p0.port_status), + readw(&ha->reg->u2.isp4022.p0.port_status)); +printk (KERN_INFO "0x%02X gp_out = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4022.p0.gp_out), + readw(&ha->reg->u2.isp4022.p0.gp_out)); +printk (KERN_INFO "0x%02X gp_in = 0x%08X\n" , + (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in), + readw(&ha->reg->u2.isp4022.p0.gp_in)); +printk (KERN_INFO "0x%02X port_err_status = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4022.p0.port_err_status), + readw(&ha->reg->u2.isp4022.p0.port_err_status)); +printk (KERN_INFO "Page 1 Registers:\n" ); +writel (HOST_MEM_CFG_PAGE &set_rmask (CSR_SCSI_PAGE_SELECT ), + &ha->reg->ctrl_status); +printk (KERN_INFO "0x%02X req_q_out = 0x%08X\n" , + (uint8_t ) offsetof(struct isp_reg , + u2.isp4022.p1.req_q_out), + readw(&ha->reg->u2.isp4022.p1.req_q_out)); +writel (PORT_CTRL_STAT_PAGE &set_rmask (CSR_SCSI_PAGE_SELECT ), + &ha->reg->ctrl_status); + } +} + +/* +* qla4xxx_dump_registers +* This routine displays ISP registers +* +* Input: +* ha - adapter structure pointer +* +*/ +void qla4xxx_dump_mbox_registers (struct scsi_qla_host *ha) +{ +unsigned long flags =0 ; +int i =0 ; +spin_lock_irqsave (&ha->hardware_lock, flags); +for (i =1 ; i <MBOX_REG_COUNT ; i++) +printk (KERN_INFO " Mailbox[%d] = %08x\n" , i, +readw (&ha->reg->mailbox[i])); +spin_unlock_irqrestore (&ha->hardware_lock, flags); +} + +void qla4xxx_dump_registers (struct scsi_qla_host *ha) +{ +unsigned long flags =0 ; +spin_lock_irqsave (&ha->hardware_lock, flags); +__dump_registers (ha); +spin_unlock_irqrestore (&ha->hardware_lock, flags); +} + +void qla4xxx_dump_buffer (void *b,uint32_t size) +{ +uint32_t cnt; +uint8_t *c = b; + +printk (" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh " +"Fh\n" ); +printk ("------------------------------------------------------------" +"--\n" ); +for (cnt =0 ; cnt < size; cnt++, c++) { +printk (KERN_DEBUG "%02x" , *c); +if (!(cnt %16 )) +printk (KERN_DEBUG "\n" ); + +else +printk (KERN_DEBUG " " ); + } +if (cnt %16 ) +printk (KERN_DEBUG "\n" ); +}
drivers/scsi/qla4xxx/ql4_dbg.h new file +55 -0
55 lines not on this page · raw message
drivers/scsi/qla4xxx/ql4_nvram.c new file +223 -0
223 lines not on this page · raw message
drivers/scsi/qla4xxx/ql4_nvram.h new file +256 -0
256 lines not on this page · raw message
RFC PATCH 7/7 qla4xxx: driver version
qla4xxx driver version.
Signed-off-by Ravi Anand <[email protected]>
Signed-off-by David Somayajulu <[email protected]>
Signed-off-by Doug Maxey <[email protected]>
Signed-off-by Mike Christie <[email protected]>
---
drivers/scsi/qla4xxx/ql4_version.h new file +13 -0
@@ -0,0 +1,13 @@ +/* +* QLogic iSCSI HBA Driver +* Copyright (c) 2003-2006 QLogic Corporation +* +* See LICENSE.qla4xxx for copyright and licensing details. +*/ + +#define QLA4XXX_DRIVER_VERSION "5.00.05b7-k" + +#define QL4_DRIVER_MAJOR_VER 5 +#define QL4_DRIVER_MINOR_VER 0 +#define QL4_DRIVER_PATCH_VER 5 +#define QL4_DRIVER_BETA_VER 7