Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1cb78d73 authored by Vikas Chaudhary's avatar Vikas Chaudhary Committed by James Bottomley
Browse files

[SCSI] qla4xxx: multi-session fix for flash ddbs



Allow multi-session to target (for flash ddbs) accesible via
multiple network portal

Signed-off-by: default avatarVikas Chaudhary <vikas.chaudhary@qlogic.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent bc97f4bb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -279,6 +279,7 @@ struct qla_ddb_index {
	struct list_head list;
	uint16_t fw_ddb_idx;
	struct dev_db_entry fw_ddb;
	uint8_t flash_isid[6];
};

#define DDB_IPADDR_LEN 64
+143 −13
Original line number Diff line number Diff line
@@ -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 @@ static int qla4xxx_is_session_exists(struct scsi_qla_host *ha,
	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));
			/* 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));

			if (qla4xxx_is_flash_ddb_exists(ha, list_nt,
					fw_ddb_entry) == QLA_SUCCESS) {
			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) ==