diff options
author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-09-12 11:14:33 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-09-12 11:14:33 -0400 |
commit | 25a765b7f05cb8460fa01b54568894b20e184862 (patch) | |
tree | 0b56db57b4d9f912393ab303c269e0fe6cdf8635 /drivers/scsi/qla4xxx/ql4_os.c | |
parent | 9d2be9287107695708e6aae5105a8a518a6cb4d0 (diff) | |
parent | 64282278989d5b0398dcb3ba7904cb00c621dc35 (diff) | |
download | linux-stable-25a765b7f05cb8460fa01b54568894b20e184862.tar.gz linux-stable-25a765b7f05cb8460fa01b54568894b20e184862.tar.bz2 linux-stable-25a765b7f05cb8460fa01b54568894b20e184862.zip |
Merge branch 'x86/platform' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into stable/for-linus-3.7
* 'x86/platform' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (9690 commits)
x86: Document x86_init.paging.pagetable_init()
x86: xen: Cleanup and remove x86_init.paging.pagetable_setup_done()
x86: Move paging_init() call to x86_init.paging.pagetable_init()
x86: Rename pagetable_setup_start() to pagetable_init()
x86: Remove base argument from x86_init.paging.pagetable_setup_start
Linux 3.6-rc5
HID: tpkbd: work even if the new Lenovo Keyboard driver is not configured
Remove user-triggerable BUG from mpol_to_str
xen/pciback: Fix proper FLR steps.
uml: fix compile error in deliver_alarm()
dj: memory scribble in logi_dj
Fix order of arguments to compat_put_time[spec|val]
xen: Use correct masking in xen_swiotlb_alloc_coherent.
xen: fix logical error in tlb flushing
xen/p2m: Fix one-off error in checking the P2M tree directory.
powerpc: Don't use __put_user() in patch_instruction
powerpc: Make sure IPI handlers see data written by IPI senders
powerpc: Restore correct DSCR in context switch
powerpc: Fix DSCR inheritance in copy_thread()
powerpc: Keep thread.dscr and thread.dscr_inherit in sync
...
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_os.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 156 |
1 files changed, 143 insertions, 13 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index cd15678f9ada..9da426628b97 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -4299,7 +4299,8 @@ static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry, } static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, - struct ql4_tuple_ddb *tddb) + struct ql4_tuple_ddb *tddb, + uint8_t *flash_isid) { uint16_t options = 0; @@ -4314,7 +4315,12 @@ static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); tddb->port = le16_to_cpu(fw_ddb_entry->port); - memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0], sizeof(tddb->isid)); + + if (flash_isid == NULL) + memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0], + sizeof(tddb->isid)); + else + memcpy(&tddb->isid[0], &flash_isid[0], sizeof(tddb->isid)); } static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, @@ -4385,7 +4391,7 @@ static int qla4xxx_is_session_exists(struct scsi_qla_host *ha, goto exit_check; } - qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); + qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL); for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); @@ -4407,6 +4413,102 @@ exit_check: return ret; } +/** + * qla4xxx_check_existing_isid - check if target with same isid exist + * in target list + * @list_nt: list of target + * @isid: isid to check + * + * This routine return QLA_SUCCESS if target with same isid exist + **/ +static int qla4xxx_check_existing_isid(struct list_head *list_nt, uint8_t *isid) +{ + struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; + struct dev_db_entry *fw_ddb_entry; + + list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { + fw_ddb_entry = &nt_ddb_idx->fw_ddb; + + if (memcmp(&fw_ddb_entry->isid[0], &isid[0], + sizeof(nt_ddb_idx->fw_ddb.isid)) == 0) { + return QLA_SUCCESS; + } + } + return QLA_ERROR; +} + +/** + * qla4xxx_update_isid - compare ddbs and updated isid + * @ha: Pointer to host adapter structure. + * @list_nt: list of nt target + * @fw_ddb_entry: firmware ddb entry + * + * This routine update isid if ddbs have same iqn, same isid and + * different IP addr. + * Return QLA_SUCCESS if isid is updated. + **/ +static int qla4xxx_update_isid(struct scsi_qla_host *ha, + struct list_head *list_nt, + struct dev_db_entry *fw_ddb_entry) +{ + uint8_t base_value, i; + + base_value = fw_ddb_entry->isid[1] & 0x1f; + for (i = 0; i < 8; i++) { + fw_ddb_entry->isid[1] = (base_value | (i << 5)); + if (qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid)) + break; + } + + if (!qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid)) + return QLA_ERROR; + + return QLA_SUCCESS; +} + +/** + * qla4xxx_should_update_isid - check if isid need to update + * @ha: Pointer to host adapter structure. + * @old_tddb: ddb tuple + * @new_tddb: ddb tuple + * + * Return QLA_SUCCESS if different IP, different PORT, same iqn, + * same isid + **/ +static int qla4xxx_should_update_isid(struct scsi_qla_host *ha, + struct ql4_tuple_ddb *old_tddb, + struct ql4_tuple_ddb *new_tddb) +{ + if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr) == 0) { + /* Same ip */ + if (old_tddb->port == new_tddb->port) + return QLA_ERROR; + } + + if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) + /* different iqn */ + return QLA_ERROR; + + if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0], + sizeof(old_tddb->isid))) + /* different isid */ + return QLA_ERROR; + + return QLA_SUCCESS; +} + +/** + * qla4xxx_is_flash_ddb_exists - check if fw_ddb_entry already exists in list_nt + * @ha: Pointer to host adapter structure. + * @list_nt: list of nt target. + * @fw_ddb_entry: firmware ddb entry. + * + * This routine check if fw_ddb_entry already exists in list_nt to avoid + * duplicate ddb in list_nt. + * Return QLA_SUCCESS if duplicate ddb exit in list_nl. + * Note: This function also update isid of DDB if required. + **/ + static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, struct list_head *list_nt, struct dev_db_entry *fw_ddb_entry) @@ -4414,7 +4516,7 @@ static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; struct ql4_tuple_ddb *fw_tddb = NULL; struct ql4_tuple_ddb *tmp_tddb = NULL; - int ret = QLA_ERROR; + int rval, ret = QLA_ERROR; fw_tddb = vzalloc(sizeof(*fw_tddb)); if (!fw_tddb) { @@ -4432,12 +4534,28 @@ static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, goto exit_check; } - qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); + qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL); list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { - qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb); - if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true)) { - ret = QLA_SUCCESS; /* found */ + qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, + nt_ddb_idx->flash_isid); + ret = qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true); + /* found duplicate ddb */ + if (ret == QLA_SUCCESS) + goto exit_check; + } + + list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { + qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, NULL); + + ret = qla4xxx_should_update_isid(ha, tmp_tddb, fw_tddb); + if (ret == QLA_SUCCESS) { + rval = qla4xxx_update_isid(ha, list_nt, fw_ddb_entry); + if (rval == QLA_SUCCESS) + ret = QLA_ERROR; + else + ret = QLA_SUCCESS; + goto exit_check; } } @@ -4788,14 +4906,26 @@ static void qla4xxx_build_nt_list(struct scsi_qla_host *ha, nt_ddb_idx->fw_ddb_idx = idx; - memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, - sizeof(struct dev_db_entry)); - - if (qla4xxx_is_flash_ddb_exists(ha, list_nt, - fw_ddb_entry) == QLA_SUCCESS) { + /* Copy original isid as it may get updated in function + * qla4xxx_update_isid(). We need original isid in + * function qla4xxx_compare_tuple_ddb to find duplicate + * target */ + memcpy(&nt_ddb_idx->flash_isid[0], + &fw_ddb_entry->isid[0], + sizeof(nt_ddb_idx->flash_isid)); + + ret = qla4xxx_is_flash_ddb_exists(ha, list_nt, + fw_ddb_entry); + if (ret == QLA_SUCCESS) { + /* free nt_ddb_idx and do not add to list_nt */ vfree(nt_ddb_idx); goto continue_next_nt; } + + /* Copy updated isid */ + memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, + sizeof(struct dev_db_entry)); + list_add_tail(&nt_ddb_idx->list, list_nt); } else if (is_reset == RESET_ADAPTER) { if (qla4xxx_is_session_exists(ha, fw_ddb_entry) == |