|
@@ -11,9 +11,6 @@
|
|
|
#include "ql4_dbg.h"
|
|
|
#include "ql4_inline.h"
|
|
|
|
|
|
-static struct ddb_entry *qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
|
|
|
- uint32_t fw_ddb_index);
|
|
|
-
|
|
|
static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
|
|
|
{
|
|
|
uint32_t value;
|
|
@@ -59,25 +56,6 @@ void qla4xxx_free_ddb(struct scsi_qla_host *ha,
|
|
|
ha->tot_ddbs--;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * qla4xxx_free_ddb_list - deallocate all ddbs
|
|
|
- * @ha: pointer to host adapter structure.
|
|
|
- *
|
|
|
- * This routine deallocates and removes all devices on the sppecified adapter.
|
|
|
- **/
|
|
|
-void qla4xxx_free_ddb_list(struct scsi_qla_host *ha)
|
|
|
-{
|
|
|
- struct list_head *ptr;
|
|
|
- struct ddb_entry *ddb_entry;
|
|
|
-
|
|
|
- while (!list_empty(&ha->ddb_list)) {
|
|
|
- ptr = ha->ddb_list.next;
|
|
|
- /* Free memory for device entry and remove */
|
|
|
- ddb_entry = list_entry(ptr, struct ddb_entry, list);
|
|
|
- qla4xxx_free_ddb(ha, ddb_entry);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* qla4xxx_init_response_q_entries() - Initializes response queue entries.
|
|
|
* @ha: HA context
|
|
@@ -468,489 +446,6 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha)
|
|
|
return qla4xxx_get_firmware_status(ha);
|
|
|
}
|
|
|
|
|
|
-static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
|
|
|
- uint32_t fw_ddb_index,
|
|
|
- uint32_t *new_tgt)
|
|
|
-{
|
|
|
- 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;
|
|
|
-
|
|
|
- *new_tgt = 0;
|
|
|
- /* 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_get_ddb_entry_no_free;
|
|
|
- }
|
|
|
-
|
|
|
- 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));
|
|
|
- goto exit_get_ddb_entry;
|
|
|
- }
|
|
|
-
|
|
|
- /* 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->iscsi_name,
|
|
|
- ISCSI_NAME_SIZE) == 0) &&
|
|
|
- (ddb_entry->tpgt ==
|
|
|
- le32_to_cpu(fw_ddb_entry->tgt_portal_grp)) &&
|
|
|
- (memcmp(ddb_entry->isid, fw_ddb_entry->isid,
|
|
|
- sizeof(ddb_entry->isid)) == 0)) {
|
|
|
- found++;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* if not found allocate new ddb */
|
|
|
- if (!found) {
|
|
|
- DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating "
|
|
|
- "new ddb\n", ha->host_no, __func__,
|
|
|
- fw_ddb_index));
|
|
|
- *new_tgt = 1;
|
|
|
- ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
|
|
|
- }
|
|
|
-
|
|
|
-exit_get_ddb_entry:
|
|
|
- dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
|
|
|
- fw_ddb_entry_dma);
|
|
|
-
|
|
|
-exit_get_ddb_entry_no_free:
|
|
|
- return ddb_entry;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * qla4xxx_update_ddb_entry - update driver's internal ddb
|
|
|
- * @ha: pointer to host adapter structure.
|
|
|
- * @ddb_entry: pointer to device database structure to be filled
|
|
|
- * @fw_ddb_index: index of the ddb entry in fw ddb table
|
|
|
- *
|
|
|
- * This routine updates the driver's internal device database entry
|
|
|
- * with information retrieved from the firmware's device database
|
|
|
- * entry for the specified device. The ddb_entry->fw_ddb_index field
|
|
|
- * must be initialized prior to calling this routine
|
|
|
- *
|
|
|
- **/
|
|
|
-static 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;
|
|
|
- uint32_t conn_err;
|
|
|
-
|
|
|
- if (ddb_entry == NULL) {
|
|
|
- DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no,
|
|
|
- __func__));
|
|
|
-
|
|
|
- goto exit_update_ddb_no_free;
|
|
|
- }
|
|
|
-
|
|
|
- /* 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_no_free;
|
|
|
- }
|
|
|
-
|
|
|
- if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
|
|
|
- fw_ddb_entry_dma, NULL, NULL,
|
|
|
- &ddb_entry->fw_ddb_device_state, &conn_err,
|
|
|
- &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->options = le16_to_cpu(fw_ddb_entry->options);
|
|
|
- ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid);
|
|
|
- ddb_entry->task_mgmt_timeout =
|
|
|
- le16_to_cpu(fw_ddb_entry->def_timeout);
|
|
|
- ddb_entry->CmdSn = 0;
|
|
|
- ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exec_throttle);
|
|
|
- ddb_entry->default_relogin_timeout =
|
|
|
- le16_to_cpu(fw_ddb_entry->def_timeout);
|
|
|
- ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
|
|
|
-
|
|
|
- /* 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->port);
|
|
|
- ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
|
|
|
- memcpy(ddb_entry->isid, fw_ddb_entry->isid, sizeof(ddb_entry->isid));
|
|
|
-
|
|
|
- memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
|
|
|
- min(sizeof(ddb_entry->iscsi_name),
|
|
|
- sizeof(fw_ddb_entry->iscsi_name)));
|
|
|
- memcpy(&ddb_entry->iscsi_alias[0], &fw_ddb_entry->iscsi_alias[0],
|
|
|
- min(sizeof(ddb_entry->iscsi_alias),
|
|
|
- sizeof(fw_ddb_entry->iscsi_alias)));
|
|
|
- memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0],
|
|
|
- min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr)));
|
|
|
-
|
|
|
- ddb_entry->iscsi_max_burst_len = fw_ddb_entry->iscsi_max_burst_len;
|
|
|
- ddb_entry->iscsi_max_outsnd_r2t = fw_ddb_entry->iscsi_max_outsnd_r2t;
|
|
|
- ddb_entry->iscsi_first_burst_len = fw_ddb_entry->iscsi_first_burst_len;
|
|
|
- ddb_entry->iscsi_max_rcv_data_seg_len =
|
|
|
- fw_ddb_entry->iscsi_max_rcv_data_seg_len;
|
|
|
- ddb_entry->iscsi_max_snd_data_seg_len =
|
|
|
- fw_ddb_entry->iscsi_max_snd_data_seg_len;
|
|
|
-
|
|
|
- if (ddb_entry->options & DDB_OPT_IPV6_DEVICE) {
|
|
|
- memcpy(&ddb_entry->remote_ipv6_addr,
|
|
|
- fw_ddb_entry->ip_addr,
|
|
|
- min(sizeof(ddb_entry->remote_ipv6_addr),
|
|
|
- sizeof(fw_ddb_entry->ip_addr)));
|
|
|
- memcpy(&ddb_entry->link_local_ipv6_addr,
|
|
|
- fw_ddb_entry->link_local_ipv6_addr,
|
|
|
- min(sizeof(ddb_entry->link_local_ipv6_addr),
|
|
|
- sizeof(fw_ddb_entry->link_local_ipv6_addr)));
|
|
|
-
|
|
|
- DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB[%d] State %04x"
|
|
|
- " ConnErr %08x IP %pI6 "
|
|
|
- ":%04d \"%s\"\n",
|
|
|
- __func__, fw_ddb_index,
|
|
|
- ddb_entry->fw_ddb_device_state,
|
|
|
- conn_err, fw_ddb_entry->ip_addr,
|
|
|
- le16_to_cpu(fw_ddb_entry->port),
|
|
|
- fw_ddb_entry->iscsi_name));
|
|
|
- } else
|
|
|
- DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB[%d] State %04x"
|
|
|
- " ConnErr %08x IP %pI4 "
|
|
|
- ":%04d \"%s\"\n",
|
|
|
- __func__, fw_ddb_index,
|
|
|
- ddb_entry->fw_ddb_device_state,
|
|
|
- conn_err, fw_ddb_entry->ip_addr,
|
|
|
- le16_to_cpu(fw_ddb_entry->port),
|
|
|
- fw_ddb_entry->iscsi_name));
|
|
|
-exit_update_ddb:
|
|
|
- if (fw_ddb_entry)
|
|
|
- dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
|
- fw_ddb_entry, fw_ddb_entry_dma);
|
|
|
-
|
|
|
-exit_update_ddb_no_free:
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * qla4xxx_alloc_ddb - allocate device database entry
|
|
|
- * @ha: Pointer to host adapter structure.
|
|
|
- * @fw_ddb_index: Firmware's device database index
|
|
|
- *
|
|
|
- * This routine allocates a ddb_entry, ititializes some values, and
|
|
|
- * inserts it into the ddb list.
|
|
|
- **/
|
|
|
-static 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->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;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * qla4_is_relogin_allowed - Are we allowed to login?
|
|
|
- * @ha: Pointer to host adapter structure.
|
|
|
- * @conn_err: Last connection error associated with the ddb
|
|
|
- *
|
|
|
- * This routine tests the given connection error to determine if
|
|
|
- * we are allowed to login.
|
|
|
- **/
|
|
|
-int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err)
|
|
|
-{
|
|
|
- uint32_t err_code, login_rsp_sts_class;
|
|
|
- int relogin = 1;
|
|
|
-
|
|
|
- err_code = ((conn_err & 0x00ff0000) >> 16);
|
|
|
- login_rsp_sts_class = ((conn_err & 0x0000ff00) >> 8);
|
|
|
- if (err_code == 0x1c || err_code == 0x06) {
|
|
|
- DEBUG2(ql4_printk(KERN_INFO, ha,
|
|
|
- ": conn_err=0x%08x, send target completed"
|
|
|
- " or access denied failure\n", conn_err));
|
|
|
- relogin = 0;
|
|
|
- }
|
|
|
- if ((err_code == 0x08) && (login_rsp_sts_class == 0x02)) {
|
|
|
- /* Login Response PDU returned an error.
|
|
|
- Login Response Status in Error Code Detail
|
|
|
- indicates login should not be retried.*/
|
|
|
- DEBUG2(ql4_printk(KERN_INFO, ha,
|
|
|
- ": conn_err=0x%08x, do not retry relogin\n",
|
|
|
- conn_err));
|
|
|
- relogin = 0;
|
|
|
- }
|
|
|
-
|
|
|
- return relogin;
|
|
|
-}
|
|
|
-
|
|
|
-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));
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * qla4xxx_build_ddb_list - builds driver ddb list
|
|
|
- * @ha: Pointer to host adapter structure.
|
|
|
- *
|
|
|
- * This routine searches for all valid firmware ddb entries and builds
|
|
|
- * an internal ddb list. Ddbs that are considered valid are those with
|
|
|
- * a device state of SESSION_ACTIVE.
|
|
|
- * A relogin (set_ddb) is issued for DDBs that are not online.
|
|
|
- **/
|
|
|
-static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
|
|
|
-{
|
|
|
- int status = QLA_ERROR;
|
|
|
- uint32_t fw_ddb_index = 0;
|
|
|
- uint32_t next_fw_ddb_index = 0;
|
|
|
- uint32_t ddb_state;
|
|
|
- uint32_t conn_err;
|
|
|
- struct ddb_entry *ddb_entry;
|
|
|
- struct dev_db_entry *fw_ddb_entry = NULL;
|
|
|
- dma_addr_t fw_ddb_entry_dma;
|
|
|
- uint32_t ipv6_device;
|
|
|
- uint32_t new_tgt;
|
|
|
-
|
|
|
- qla4xxx_flush_AENS(ha);
|
|
|
-
|
|
|
- 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(ql4_printk(KERN_INFO, ha, "%s: DMA alloc failed\n",
|
|
|
- __func__));
|
|
|
-
|
|
|
- goto exit_build_ddb_list_no_free;
|
|
|
- }
|
|
|
-
|
|
|
- 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, fw_ddb_entry,
|
|
|
- 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));
|
|
|
- goto exit_build_ddb_list;
|
|
|
- }
|
|
|
-
|
|
|
- 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));
|
|
|
- ipv6_device = le16_to_cpu(fw_ddb_entry->options) &
|
|
|
- DDB_OPT_IPV6_DEVICE;
|
|
|
- if (qla4_is_relogin_allowed(ha, conn_err) &&
|
|
|
- ((!ipv6_device &&
|
|
|
- *((uint32_t *)fw_ddb_entry->ip_addr))
|
|
|
- || ipv6_device)) {
|
|
|
- qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0,
|
|
|
- NULL);
|
|
|
- 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 %d failed\n",
|
|
|
- ha->host_no,
|
|
|
- __func__, fw_ddb_index));
|
|
|
- goto exit_build_ddb_list;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (ddb_state != DDB_DS_SESSION_ACTIVE)
|
|
|
- goto next_one;
|
|
|
- /*
|
|
|
- * if fw_ddb with session active state found,
|
|
|
- * add to ddb_list
|
|
|
- */
|
|
|
- DEBUG2(printk("scsi%ld: %s: DDB[%d] added to list\n",
|
|
|
- ha->host_no, __func__, fw_ddb_index));
|
|
|
-
|
|
|
- /* Add DDB to internal our ddb list. */
|
|
|
- ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt);
|
|
|
- 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));
|
|
|
- goto exit_build_ddb_list;
|
|
|
- }
|
|
|
- /* 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));
|
|
|
- goto exit_build_ddb_list;
|
|
|
- }
|
|
|
-
|
|
|
-next_one:
|
|
|
- /* We know we've reached the last device when
|
|
|
- * next_fw_ddb_index is 0 */
|
|
|
- if (next_fw_ddb_index == 0)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- status = QLA_SUCCESS;
|
|
|
- ql4_printk(KERN_INFO, ha, "DDB list done..\n");
|
|
|
-
|
|
|
-exit_build_ddb_list:
|
|
|
- dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
|
|
|
- fw_ddb_entry_dma);
|
|
|
-
|
|
|
-exit_build_ddb_list_no_free:
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha)
|
|
|
-{
|
|
|
- uint16_t fw_ddb_index;
|
|
|
- int status = QLA_SUCCESS;
|
|
|
-
|
|
|
- /* free the ddb list if is not empty */
|
|
|
- if (!list_empty(&ha->ddb_list))
|
|
|
- qla4xxx_free_ddb_list(ha);
|
|
|
-
|
|
|
- for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++)
|
|
|
- ha->fw_ddb_index_map[fw_ddb_index] =
|
|
|
- (struct ddb_entry *)INVALID_ENTRY;
|
|
|
-
|
|
|
- ha->tot_ddbs = 0;
|
|
|
-
|
|
|
- /* Perform device discovery and build ddb list. */
|
|
|
- status = qla4xxx_build_ddb_list(ha);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * qla4xxx_reinitialize_ddb_list - update the driver ddb list
|
|
|
- * @ha: pointer to host adapter structure.
|
|
|
- *
|
|
|
- * This routine obtains device information from the F/W database after
|
|
|
- * firmware or adapter resets. The device table is preserved.
|
|
|
- **/
|
|
|
-int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha)
|
|
|
-{
|
|
|
- int status = QLA_SUCCESS;
|
|
|
- struct ddb_entry *ddb_entry, *detemp;
|
|
|
-
|
|
|
- /* Update the device information for all devices. */
|
|
|
- list_for_each_entry_safe(ddb_entry, detemp, &ha->ddb_list, list) {
|
|
|
- qla4xxx_update_ddb_entry(ha, ddb_entry,
|
|
|
- ddb_entry->fw_ddb_index);
|
|
|
- if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
|
|
|
- atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
|
|
|
- DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked "
|
|
|
- "ONLINE\n", ha->host_no, __func__,
|
|
|
- ddb_entry->fw_ddb_index));
|
|
|
- iscsi_unblock_session(ddb_entry->sess);
|
|
|
- } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
|
|
|
- qla4xxx_mark_device_missing(ddb_entry->sess);
|
|
|
- }
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * qla4xxx_relogin_device - re-establish session
|
|
|
- * @ha: Pointer to host adapter structure.
|
|
|
- * @ddb_entry: Pointer to device database entry
|
|
|
- *
|
|
|
- * This routine does a session relogin with the specified device.
|
|
|
- * The ddb entry must be assigned prior to making this call.
|
|
|
- **/
|
|
|
-int qla4xxx_relogin_device(struct scsi_qla_host *ha,
|
|
|
- struct ddb_entry * ddb_entry)
|
|
|
-{
|
|
|
- uint16_t relogin_timer;
|
|
|
-
|
|
|
- relogin_timer = max(ddb_entry->default_relogin_timeout,
|
|
|
- (uint16_t)RELOGIN_TOV);
|
|
|
- atomic_set(&ddb_entry->relogin_timer, relogin_timer);
|
|
|
-
|
|
|
- DEBUG2(printk("scsi%ld: Relogin ddb [%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, NULL);
|
|
|
-
|
|
|
- return QLA_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
|
|
|
{
|
|
|
unsigned long flags;
|
|
@@ -1254,18 +749,13 @@ int qla4xxx_start_firmware(struct scsi_qla_host *ha)
|
|
|
/**
|
|
|
* qla4xxx_initialize_adapter - initiailizes hba
|
|
|
* @ha: Pointer to host adapter structure.
|
|
|
- * @renew_ddb_list: Indicates what to do with the adapter's ddb list
|
|
|
- * after adapter recovery has completed.
|
|
|
- * 0=preserve ddb list, 1=destroy and rebuild ddb list
|
|
|
*
|
|
|
* This routine parforms all of the steps necessary to initialize the adapter.
|
|
|
*
|
|
|
**/
|
|
|
-int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
|
|
|
- uint8_t renew_ddb_list)
|
|
|
+int qla4xxx_initialize_adapter(struct scsi_qla_host *ha)
|
|
|
{
|
|
|
int status = QLA_ERROR;
|
|
|
- int8_t ip_address[IP_ADDR_LEN] = {0} ;
|
|
|
|
|
|
ha->eeprom_cmd_data = 0;
|
|
|
|
|
@@ -1291,47 +781,6 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
|
|
|
if (status == QLA_ERROR)
|
|
|
goto exit_init_hba;
|
|
|
|
|
|
- /*
|
|
|
- * 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_CONFIGURING_IP)
|
|
|
- goto exit_init_online;
|
|
|
-
|
|
|
- /* Skip device discovery if ip and subnet is zero */
|
|
|
- if (memcmp(ha->ip_config.ip_address, ip_address, IP_ADDR_LEN) == 0 ||
|
|
|
- memcmp(ha->ip_config.subnet_mask, ip_address, IP_ADDR_LEN) == 0)
|
|
|
- goto exit_init_online;
|
|
|
-
|
|
|
- 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_online:
|
|
|
set_bit(AF_ONLINE, &ha->flags);
|
|
|
exit_init_hba:
|
|
|
if (is_qla8022(ha) && (status == QLA_ERROR)) {
|
|
@@ -1345,61 +794,6 @@ exit_init_hba:
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * qla4xxx_add_device_dynamically - ddb addition due to an AEN
|
|
|
- * @ha: Pointer to host adapter structure.
|
|
|
- * @fw_ddb_index: Firmware's device database index
|
|
|
- *
|
|
|
- * This routine processes adds a device as a result of an 8014h AEN.
|
|
|
- **/
|
|
|
-static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,
|
|
|
- uint32_t fw_ddb_index)
|
|
|
-{
|
|
|
- struct ddb_entry * ddb_entry;
|
|
|
- uint32_t new_tgt;
|
|
|
-
|
|
|
- /* First allocate a device structure */
|
|
|
- ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt);
|
|
|
- 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 (!new_tgt && (ddb_entry->fw_ddb_index != fw_ddb_index)) {
|
|
|
- /* Target has been bound to a new fw_ddb_index */
|
|
|
- qla4xxx_free_ddb(ha, ddb_entry);
|
|
|
- ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
|
|
|
- if (ddb_entry == NULL) {
|
|
|
- DEBUG2(printk(KERN_WARNING
|
|
|
- "scsi%ld: Unable to allocate memory"
|
|
|
- " to add fw_ddb_index %d\n",
|
|
|
- ha->host_no, fw_ddb_index));
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
|
|
|
- QLA_ERROR) {
|
|
|
- ha->fw_ddb_index_map[fw_ddb_index] =
|
|
|
- (struct ddb_entry *)INVALID_ENTRY;
|
|
|
- DEBUG2(printk(KERN_WARNING
|
|
|
- "scsi%ld: failed to add new device at index "
|
|
|
- "[%d]\n Unable to retrieve fw ddb entry\n",
|
|
|
- ha->host_no, fw_ddb_index));
|
|
|
- qla4xxx_free_ddb(ha, ddb_entry);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (qla4xxx_add_sess(ddb_entry)) {
|
|
|
- DEBUG2(printk(KERN_WARNING
|
|
|
- "scsi%ld: failed to add new device at index "
|
|
|
- "[%d]\n Unable to add connection and session\n",
|
|
|
- ha->host_no, fw_ddb_index));
|
|
|
- qla4xxx_free_ddb(ha, ddb_entry);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* qla4xxx_process_ddb_changed - process ddb state change
|
|
|
* @ha - Pointer to host adapter structure.
|