aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorVikas Chaudhary <vikas.chaudhary@qlogic.com>2012-06-14 06:35:48 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-07-20 03:58:34 -0400
commit1cb78d73d36d03950501230473620fd56cec1e49 (patch)
treeb6ed2ebcbd8e68f0764126fd3d6b25cb0bb901f2 /drivers/scsi
parentbc97f4bb4490ff31b2be8e006f750d4187ef0c7e (diff)
[SCSI] qla4xxx: multi-session fix for flash ddbs
Allow multi-session to target (for flash ddbs) accesible via multiple network portal Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h1
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c156
2 files changed, 144 insertions, 13 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 96a5616a8fda..7fdba7f1ffb7 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -279,6 +279,7 @@ struct qla_ddb_index {
279 struct list_head list; 279 struct list_head list;
280 uint16_t fw_ddb_idx; 280 uint16_t fw_ddb_idx;
281 struct dev_db_entry fw_ddb; 281 struct dev_db_entry fw_ddb;
282 uint8_t flash_isid[6];
282}; 283};
283 284
284#define DDB_IPADDR_LEN 64 285#define DDB_IPADDR_LEN 64
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,
4299} 4299}
4300 4300
4301static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, 4301static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
4302 struct ql4_tuple_ddb *tddb) 4302 struct ql4_tuple_ddb *tddb,
4303 uint8_t *flash_isid)
4303{ 4304{
4304 uint16_t options = 0; 4305 uint16_t options = 0;
4305 4306
@@ -4314,7 +4315,12 @@ static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
4314 sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); 4315 sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr);
4315 4316
4316 tddb->port = le16_to_cpu(fw_ddb_entry->port); 4317 tddb->port = le16_to_cpu(fw_ddb_entry->port);
4317 memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0], sizeof(tddb->isid)); 4318
4319 if (flash_isid == NULL)
4320 memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0],
4321 sizeof(tddb->isid));
4322 else
4323 memcpy(&tddb->isid[0], &flash_isid[0], sizeof(tddb->isid));
4318} 4324}
4319 4325
4320static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, 4326static 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,
4385 goto exit_check; 4391 goto exit_check;
4386 } 4392 }
4387 4393
4388 qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); 4394 qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
4389 4395
4390 for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { 4396 for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
4391 ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); 4397 ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
@@ -4407,6 +4413,102 @@ exit_check:
4407 return ret; 4413 return ret;
4408} 4414}
4409 4415
4416/**
4417 * qla4xxx_check_existing_isid - check if target with same isid exist
4418 * in target list
4419 * @list_nt: list of target
4420 * @isid: isid to check
4421 *
4422 * This routine return QLA_SUCCESS if target with same isid exist
4423 **/
4424static int qla4xxx_check_existing_isid(struct list_head *list_nt, uint8_t *isid)
4425{
4426 struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp;
4427 struct dev_db_entry *fw_ddb_entry;
4428
4429 list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
4430 fw_ddb_entry = &nt_ddb_idx->fw_ddb;
4431
4432 if (memcmp(&fw_ddb_entry->isid[0], &isid[0],
4433 sizeof(nt_ddb_idx->fw_ddb.isid)) == 0) {
4434 return QLA_SUCCESS;
4435 }
4436 }
4437 return QLA_ERROR;
4438}
4439
4440/**
4441 * qla4xxx_update_isid - compare ddbs and updated isid
4442 * @ha: Pointer to host adapter structure.
4443 * @list_nt: list of nt target
4444 * @fw_ddb_entry: firmware ddb entry
4445 *
4446 * This routine update isid if ddbs have same iqn, same isid and
4447 * different IP addr.
4448 * Return QLA_SUCCESS if isid is updated.
4449 **/
4450static int qla4xxx_update_isid(struct scsi_qla_host *ha,
4451 struct list_head *list_nt,
4452 struct dev_db_entry *fw_ddb_entry)
4453{
4454 uint8_t base_value, i;
4455
4456 base_value = fw_ddb_entry->isid[1] & 0x1f;
4457 for (i = 0; i < 8; i++) {
4458 fw_ddb_entry->isid[1] = (base_value | (i << 5));
4459 if (qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
4460 break;
4461 }
4462
4463 if (!qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
4464 return QLA_ERROR;
4465
4466 return QLA_SUCCESS;
4467}
4468
4469/**
4470 * qla4xxx_should_update_isid - check if isid need to update
4471 * @ha: Pointer to host adapter structure.
4472 * @old_tddb: ddb tuple
4473 * @new_tddb: ddb tuple
4474 *
4475 * Return QLA_SUCCESS if different IP, different PORT, same iqn,
4476 * same isid
4477 **/
4478static int qla4xxx_should_update_isid(struct scsi_qla_host *ha,
4479 struct ql4_tuple_ddb *old_tddb,
4480 struct ql4_tuple_ddb *new_tddb)
4481{
4482 if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr) == 0) {
4483 /* Same ip */
4484 if (old_tddb->port == new_tddb->port)
4485 return QLA_ERROR;
4486 }
4487
4488 if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
4489 /* different iqn */
4490 return QLA_ERROR;
4491
4492 if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
4493 sizeof(old_tddb->isid)))
4494 /* different isid */
4495 return QLA_ERROR;
4496
4497 return QLA_SUCCESS;
4498}
4499
4500/**
4501 * qla4xxx_is_flash_ddb_exists - check if fw_ddb_entry already exists in list_nt
4502 * @ha: Pointer to host adapter structure.
4503 * @list_nt: list of nt target.
4504 * @fw_ddb_entry: firmware ddb entry.
4505 *
4506 * This routine check if fw_ddb_entry already exists in list_nt to avoid
4507 * duplicate ddb in list_nt.
4508 * Return QLA_SUCCESS if duplicate ddb exit in list_nl.
4509 * Note: This function also update isid of DDB if required.
4510 **/
4511
4410static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, 4512static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
4411 struct list_head *list_nt, 4513 struct list_head *list_nt,
4412 struct dev_db_entry *fw_ddb_entry) 4514 struct dev_db_entry *fw_ddb_entry)
@@ -4414,7 +4516,7 @@ static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
4414 struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; 4516 struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp;
4415 struct ql4_tuple_ddb *fw_tddb = NULL; 4517 struct ql4_tuple_ddb *fw_tddb = NULL;
4416 struct ql4_tuple_ddb *tmp_tddb = NULL; 4518 struct ql4_tuple_ddb *tmp_tddb = NULL;
4417 int ret = QLA_ERROR; 4519 int rval, ret = QLA_ERROR;
4418 4520
4419 fw_tddb = vzalloc(sizeof(*fw_tddb)); 4521 fw_tddb = vzalloc(sizeof(*fw_tddb));
4420 if (!fw_tddb) { 4522 if (!fw_tddb) {
@@ -4432,12 +4534,28 @@ static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
4432 goto exit_check; 4534 goto exit_check;
4433 } 4535 }
4434 4536
4435 qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); 4537 qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
4436 4538
4437 list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { 4539 list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
4438 qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb); 4540 qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb,
4439 if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true)) { 4541 nt_ddb_idx->flash_isid);
4440 ret = QLA_SUCCESS; /* found */ 4542 ret = qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true);
4543 /* found duplicate ddb */
4544 if (ret == QLA_SUCCESS)
4545 goto exit_check;
4546 }
4547
4548 list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
4549 qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, NULL);
4550
4551 ret = qla4xxx_should_update_isid(ha, tmp_tddb, fw_tddb);
4552 if (ret == QLA_SUCCESS) {
4553 rval = qla4xxx_update_isid(ha, list_nt, fw_ddb_entry);
4554 if (rval == QLA_SUCCESS)
4555 ret = QLA_ERROR;
4556 else
4557 ret = QLA_SUCCESS;
4558
4441 goto exit_check; 4559 goto exit_check;
4442 } 4560 }
4443 } 4561 }
@@ -4788,14 +4906,26 @@ static void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
4788 4906
4789 nt_ddb_idx->fw_ddb_idx = idx; 4907 nt_ddb_idx->fw_ddb_idx = idx;
4790 4908
4791 memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, 4909 /* Copy original isid as it may get updated in function
4792 sizeof(struct dev_db_entry)); 4910 * qla4xxx_update_isid(). We need original isid in
4793 4911 * function qla4xxx_compare_tuple_ddb to find duplicate
4794 if (qla4xxx_is_flash_ddb_exists(ha, list_nt, 4912 * target */
4795 fw_ddb_entry) == QLA_SUCCESS) { 4913 memcpy(&nt_ddb_idx->flash_isid[0],
4914 &fw_ddb_entry->isid[0],
4915 sizeof(nt_ddb_idx->flash_isid));
4916
4917 ret = qla4xxx_is_flash_ddb_exists(ha, list_nt,
4918 fw_ddb_entry);
4919 if (ret == QLA_SUCCESS) {
4920 /* free nt_ddb_idx and do not add to list_nt */
4796 vfree(nt_ddb_idx); 4921 vfree(nt_ddb_idx);
4797 goto continue_next_nt; 4922 goto continue_next_nt;
4798 } 4923 }
4924
4925 /* Copy updated isid */
4926 memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry,
4927 sizeof(struct dev_db_entry));
4928
4799 list_add_tail(&nt_ddb_idx->list, list_nt); 4929 list_add_tail(&nt_ddb_idx->list, list_nt);
4800 } else if (is_reset == RESET_ADAPTER) { 4930 } else if (is_reset == RESET_ADAPTER) {
4801 if (qla4xxx_is_session_exists(ha, fw_ddb_entry) == 4931 if (qla4xxx_is_session_exists(ha, fw_ddb_entry) ==