|
@@ -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) ==
|