diff options
author | Vikas Chaudhary <vikas.chaudhary@qlogic.com> | 2012-06-14 06:35:48 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-07-20 03:58:34 -0400 |
commit | 1cb78d73d36d03950501230473620fd56cec1e49 (patch) | |
tree | b6ed2ebcbd8e68f0764126fd3d6b25cb0bb901f2 /drivers/scsi | |
parent | bc97f4bb4490ff31b2be8e006f750d4187ef0c7e (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.h | 1 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 156 |
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 | ||
4301 | static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, | 4301 | static 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 | ||
4320 | static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, | 4326 | 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, | |||
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 | **/ | ||
4424 | static 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 | **/ | ||
4450 | static 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 | **/ | ||
4478 | static 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 | |||
4410 | static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, | 4512 | static 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) == |