aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManish Rangankar <manish.rangankar@qlogic.com>2013-09-17 07:30:02 -0400
committerJames Bottomley <JBottomley@Parallels.com>2013-10-25 04:57:58 -0400
commitad8bd45ed6cde29e668cdc40426f9c894274155d (patch)
treecc9d2f938c6e957016384e26f10a1e5c0d8be974
parent3993a86241a036aaf7204586c94b839db239c402 (diff)
[SCSI] qla4xxx: correctly update session discovery_parent_idx.
Earlier logic for driver created iscsi_session->discovery_parent_idx was to store ram index of a sendtarget entry, but driver frees sendtarget ram index as soon as firmware is done with discovery, which is available for further use. So changing the logic to point iscsi_session->discovery_parent_idx to store sendtarget flashnode index. Signed-off-by: Manish Rangankar <manish.rangankar@qlogic.com> Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h1
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c199
2 files changed, 181 insertions, 19 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 41327d46ecf5..084d1fd59c9e 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -306,6 +306,7 @@ struct ddb_entry {
306struct qla_ddb_index { 306struct qla_ddb_index {
307 struct list_head list; 307 struct list_head list;
308 uint16_t fw_ddb_idx; 308 uint16_t fw_ddb_idx;
309 uint16_t flash_ddb_idx;
309 struct dev_db_entry fw_ddb; 310 struct dev_db_entry fw_ddb;
310 uint8_t flash_isid[6]; 311 uint8_t flash_isid[6];
311}; 312};
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index f8a0a26a3cd4..a8847a31273d 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -2373,11 +2373,6 @@ static void qla4xxx_copy_to_sess_conn_params(struct iscsi_conn *conn,
2373 COPY_ISID(sess->isid, fw_ddb_entry->isid); 2373 COPY_ISID(sess->isid, fw_ddb_entry->isid);
2374 2374
2375 ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link); 2375 ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
2376 if (ddb_link < MAX_DDB_ENTRIES)
2377 sess->discovery_parent_idx = ddb_link;
2378 else
2379 sess->discovery_parent_idx = DDB_NO_LINK;
2380
2381 if (ddb_link == DDB_ISNS) 2376 if (ddb_link == DDB_ISNS)
2382 disc_parent = ISCSI_DISC_PARENT_ISNS; 2377 disc_parent = ISCSI_DISC_PARENT_ISNS;
2383 else if (ddb_link == DDB_NO_LINK) 2378 else if (ddb_link == DDB_NO_LINK)
@@ -4937,7 +4932,8 @@ static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha,
4937} 4932}
4938 4933
4939static int qla4xxx_is_session_exists(struct scsi_qla_host *ha, 4934static int qla4xxx_is_session_exists(struct scsi_qla_host *ha,
4940 struct dev_db_entry *fw_ddb_entry) 4935 struct dev_db_entry *fw_ddb_entry,
4936 uint32_t *index)
4941{ 4937{
4942 struct ddb_entry *ddb_entry; 4938 struct ddb_entry *ddb_entry;
4943 struct ql4_tuple_ddb *fw_tddb = NULL; 4939 struct ql4_tuple_ddb *fw_tddb = NULL;
@@ -4971,6 +4967,8 @@ static int qla4xxx_is_session_exists(struct scsi_qla_host *ha,
4971 qla4xxx_get_param_ddb(ddb_entry, tmp_tddb); 4967 qla4xxx_get_param_ddb(ddb_entry, tmp_tddb);
4972 if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) { 4968 if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) {
4973 ret = QLA_SUCCESS; /* found */ 4969 ret = QLA_SUCCESS; /* found */
4970 if (index != NULL)
4971 *index = idx;
4974 goto exit_check; 4972 goto exit_check;
4975 } 4973 }
4976 } 4974 }
@@ -5267,6 +5265,87 @@ static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha)
5267 } while (time_after(wtime, jiffies)); 5265 } while (time_after(wtime, jiffies));
5268} 5266}
5269 5267
5268static int qla4xxx_cmp_fw_stentry(struct dev_db_entry *fw_ddb_entry,
5269 struct dev_db_entry *flash_ddb_entry)
5270{
5271 uint16_t options = 0;
5272 size_t ip_len = IP_ADDR_LEN;
5273
5274 options = le16_to_cpu(fw_ddb_entry->options);
5275 if (options & DDB_OPT_IPV6_DEVICE)
5276 ip_len = IPv6_ADDR_LEN;
5277
5278 if (memcmp(fw_ddb_entry->ip_addr, flash_ddb_entry->ip_addr, ip_len))
5279 return QLA_ERROR;
5280
5281 if (memcmp(&fw_ddb_entry->isid[0], &flash_ddb_entry->isid[0],
5282 sizeof(fw_ddb_entry->isid)))
5283 return QLA_ERROR;
5284
5285 if (memcmp(&fw_ddb_entry->port, &flash_ddb_entry->port,
5286 sizeof(fw_ddb_entry->port)))
5287 return QLA_ERROR;
5288
5289 return QLA_SUCCESS;
5290}
5291
5292static int qla4xxx_find_flash_st_idx(struct scsi_qla_host *ha,
5293 struct dev_db_entry *fw_ddb_entry,
5294 uint32_t fw_idx, uint32_t *flash_index)
5295{
5296 struct dev_db_entry *flash_ddb_entry;
5297 dma_addr_t flash_ddb_entry_dma;
5298 uint32_t idx = 0;
5299 int max_ddbs;
5300 int ret = QLA_ERROR, status;
5301
5302 max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
5303 MAX_DEV_DB_ENTRIES;
5304
5305 flash_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
5306 &flash_ddb_entry_dma);
5307 if (flash_ddb_entry == NULL || fw_ddb_entry == NULL) {
5308 ql4_printk(KERN_ERR, ha, "Out of memory\n");
5309 goto exit_find_st_idx;
5310 }
5311
5312 status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry,
5313 flash_ddb_entry_dma, fw_idx);
5314 if (status == QLA_SUCCESS) {
5315 status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry);
5316 if (status == QLA_SUCCESS) {
5317 *flash_index = fw_idx;
5318 ret = QLA_SUCCESS;
5319 goto exit_find_st_idx;
5320 }
5321 }
5322
5323 for (idx = 0; idx < max_ddbs; idx++) {
5324 status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry,
5325 flash_ddb_entry_dma, idx);
5326 if (status == QLA_ERROR)
5327 continue;
5328
5329 status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry);
5330 if (status == QLA_SUCCESS) {
5331 *flash_index = idx;
5332 ret = QLA_SUCCESS;
5333 goto exit_find_st_idx;
5334 }
5335 }
5336
5337 if (idx == max_ddbs)
5338 ql4_printk(KERN_ERR, ha, "Failed to find ST [%d] in flash\n",
5339 fw_idx);
5340
5341exit_find_st_idx:
5342 if (flash_ddb_entry)
5343 dma_pool_free(ha->fw_ddb_dma_pool, flash_ddb_entry,
5344 flash_ddb_entry_dma);
5345
5346 return ret;
5347}
5348
5270static void qla4xxx_build_st_list(struct scsi_qla_host *ha, 5349static void qla4xxx_build_st_list(struct scsi_qla_host *ha,
5271 struct list_head *list_st) 5350 struct list_head *list_st)
5272{ 5351{
@@ -5278,6 +5357,7 @@ static void qla4xxx_build_st_list(struct scsi_qla_host *ha,
5278 int ret; 5357 int ret;
5279 uint32_t idx = 0, next_idx = 0; 5358 uint32_t idx = 0, next_idx = 0;
5280 uint32_t state = 0, conn_err = 0; 5359 uint32_t state = 0, conn_err = 0;
5360 uint32_t flash_index = -1;
5281 uint16_t conn_id = 0; 5361 uint16_t conn_id = 0;
5282 5362
5283 fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 5363 fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
@@ -5310,6 +5390,19 @@ static void qla4xxx_build_st_list(struct scsi_qla_host *ha,
5310 if (!st_ddb_idx) 5390 if (!st_ddb_idx)
5311 break; 5391 break;
5312 5392
5393 ret = qla4xxx_find_flash_st_idx(ha, fw_ddb_entry, idx,
5394 &flash_index);
5395 if (ret == QLA_ERROR) {
5396 ql4_printk(KERN_ERR, ha,
5397 "No flash entry for ST at idx [%d]\n", idx);
5398 st_ddb_idx->flash_ddb_idx = idx;
5399 } else {
5400 ql4_printk(KERN_INFO, ha,
5401 "ST at idx [%d] is stored at flash [%d]\n",
5402 idx, flash_index);
5403 st_ddb_idx->flash_ddb_idx = flash_index;
5404 }
5405
5313 st_ddb_idx->fw_ddb_idx = idx; 5406 st_ddb_idx->fw_ddb_idx = idx;
5314 5407
5315 list_add_tail(&st_ddb_idx->list, list_st); 5408 list_add_tail(&st_ddb_idx->list, list_st);
@@ -5354,6 +5447,28 @@ static void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha,
5354 } 5447 }
5355} 5448}
5356 5449
5450static void qla4xxx_update_sess_disc_idx(struct scsi_qla_host *ha,
5451 struct ddb_entry *ddb_entry,
5452 struct dev_db_entry *fw_ddb_entry)
5453{
5454 struct iscsi_cls_session *cls_sess;
5455 struct iscsi_session *sess;
5456 uint32_t max_ddbs = 0;
5457 uint16_t ddb_link = -1;
5458
5459 max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
5460 MAX_DEV_DB_ENTRIES;
5461
5462 cls_sess = ddb_entry->sess;
5463 sess = cls_sess->dd_data;
5464
5465 ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
5466 if (ddb_link < max_ddbs)
5467 sess->discovery_parent_idx = ddb_link;
5468 else
5469 sess->discovery_parent_idx = DDB_NO_LINK;
5470}
5471
5357static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha, 5472static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha,
5358 struct dev_db_entry *fw_ddb_entry, 5473 struct dev_db_entry *fw_ddb_entry,
5359 int is_reset, uint16_t idx) 5474 int is_reset, uint16_t idx)
@@ -5418,6 +5533,7 @@ static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha,
5418 5533
5419 /* Update sess/conn params */ 5534 /* Update sess/conn params */
5420 qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); 5535 qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
5536 qla4xxx_update_sess_disc_idx(ha, ddb_entry, fw_ddb_entry);
5421 5537
5422 if (is_reset == RESET_ADAPTER) { 5538 if (is_reset == RESET_ADAPTER) {
5423 iscsi_block_session(cls_sess); 5539 iscsi_block_session(cls_sess);
@@ -5434,17 +5550,43 @@ exit_setup:
5434 return ret; 5550 return ret;
5435} 5551}
5436 5552
5553static void qla4xxx_update_fw_ddb_link(struct scsi_qla_host *ha,
5554 struct list_head *list_ddb,
5555 struct dev_db_entry *fw_ddb_entry)
5556{
5557 struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
5558 uint16_t ddb_link;
5559
5560 ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
5561
5562 list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
5563 if (ddb_idx->fw_ddb_idx == ddb_link) {
5564 DEBUG2(ql4_printk(KERN_INFO, ha,
5565 "Updating NT parent idx from [%d] to [%d]\n",
5566 ddb_link, ddb_idx->flash_ddb_idx));
5567 fw_ddb_entry->ddb_link =
5568 cpu_to_le16(ddb_idx->flash_ddb_idx);
5569 return;
5570 }
5571 }
5572}
5573
5437static void qla4xxx_build_nt_list(struct scsi_qla_host *ha, 5574static void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
5438 struct list_head *list_nt, int is_reset) 5575 struct list_head *list_nt,
5576 struct list_head *list_st,
5577 int is_reset)
5439{ 5578{
5440 struct dev_db_entry *fw_ddb_entry; 5579 struct dev_db_entry *fw_ddb_entry;
5580 struct ddb_entry *ddb_entry = NULL;
5441 dma_addr_t fw_ddb_dma; 5581 dma_addr_t fw_ddb_dma;
5442 int max_ddbs; 5582 int max_ddbs;
5443 int fw_idx_size; 5583 int fw_idx_size;
5444 int ret; 5584 int ret;
5445 uint32_t idx = 0, next_idx = 0; 5585 uint32_t idx = 0, next_idx = 0;
5446 uint32_t state = 0, conn_err = 0; 5586 uint32_t state = 0, conn_err = 0;
5587 uint32_t ddb_idx = -1;
5447 uint16_t conn_id = 0; 5588 uint16_t conn_id = 0;
5589 uint16_t ddb_link = -1;
5448 struct qla_ddb_index *nt_ddb_idx; 5590 struct qla_ddb_index *nt_ddb_idx;
5449 5591
5450 fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 5592 fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
@@ -5471,12 +5613,18 @@ static void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
5471 if (strlen((char *) fw_ddb_entry->iscsi_name) == 0) 5613 if (strlen((char *) fw_ddb_entry->iscsi_name) == 0)
5472 goto continue_next_nt; 5614 goto continue_next_nt;
5473 5615
5616 ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
5617 if (ddb_link < max_ddbs)
5618 qla4xxx_update_fw_ddb_link(ha, list_st, fw_ddb_entry);
5619
5474 if (!(state == DDB_DS_NO_CONNECTION_ACTIVE || 5620 if (!(state == DDB_DS_NO_CONNECTION_ACTIVE ||
5475 state == DDB_DS_SESSION_FAILED)) 5621 state == DDB_DS_SESSION_FAILED) &&
5622 (is_reset == INIT_ADAPTER))
5476 goto continue_next_nt; 5623 goto continue_next_nt;
5477 5624
5478 DEBUG2(ql4_printk(KERN_INFO, ha, 5625 DEBUG2(ql4_printk(KERN_INFO, ha,
5479 "Adding DDB to session = 0x%x\n", idx)); 5626 "Adding DDB to session = 0x%x\n", idx));
5627
5480 if (is_reset == INIT_ADAPTER) { 5628 if (is_reset == INIT_ADAPTER) {
5481 nt_ddb_idx = vmalloc(fw_idx_size); 5629 nt_ddb_idx = vmalloc(fw_idx_size);
5482 if (!nt_ddb_idx) 5630 if (!nt_ddb_idx)
@@ -5506,9 +5654,17 @@ static void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
5506 5654
5507 list_add_tail(&nt_ddb_idx->list, list_nt); 5655 list_add_tail(&nt_ddb_idx->list, list_nt);
5508 } else if (is_reset == RESET_ADAPTER) { 5656 } else if (is_reset == RESET_ADAPTER) {
5509 if (qla4xxx_is_session_exists(ha, fw_ddb_entry) == 5657 ret = qla4xxx_is_session_exists(ha, fw_ddb_entry,
5510 QLA_SUCCESS) 5658 &ddb_idx);
5659 if (ret == QLA_SUCCESS) {
5660 ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha,
5661 ddb_idx);
5662 if (ddb_entry != NULL)
5663 qla4xxx_update_sess_disc_idx(ha,
5664 ddb_entry,
5665 fw_ddb_entry);
5511 goto continue_next_nt; 5666 goto continue_next_nt;
5667 }
5512 } 5668 }
5513 5669
5514 ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset, idx); 5670 ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset, idx);
@@ -5526,7 +5682,8 @@ exit_nt_list:
5526} 5682}
5527 5683
5528static void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha, 5684static void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha,
5529 struct list_head *list_nt) 5685 struct list_head *list_nt,
5686 uint16_t target_id)
5530{ 5687{
5531 struct dev_db_entry *fw_ddb_entry; 5688 struct dev_db_entry *fw_ddb_entry;
5532 dma_addr_t fw_ddb_dma; 5689 dma_addr_t fw_ddb_dma;
@@ -5571,13 +5728,16 @@ static void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha,
5571 5728
5572 nt_ddb_idx->fw_ddb_idx = idx; 5729 nt_ddb_idx->fw_ddb_idx = idx;
5573 5730
5574 ret = qla4xxx_is_session_exists(ha, fw_ddb_entry); 5731 ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL);
5575 if (ret == QLA_SUCCESS) { 5732 if (ret == QLA_SUCCESS) {
5576 /* free nt_ddb_idx and do not add to list_nt */ 5733 /* free nt_ddb_idx and do not add to list_nt */
5577 vfree(nt_ddb_idx); 5734 vfree(nt_ddb_idx);
5578 goto continue_next_new_nt; 5735 goto continue_next_new_nt;
5579 } 5736 }
5580 5737
5738 if (target_id < max_ddbs)
5739 fw_ddb_entry->ddb_link = cpu_to_le16(target_id);
5740
5581 list_add_tail(&nt_ddb_idx->list, list_nt); 5741 list_add_tail(&nt_ddb_idx->list, list_nt);
5582 5742
5583 ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER, 5743 ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
@@ -5894,7 +6054,8 @@ exit_ddb_conn_open:
5894} 6054}
5895 6055
5896static int qla4xxx_ddb_login_st(struct scsi_qla_host *ha, 6056static int qla4xxx_ddb_login_st(struct scsi_qla_host *ha,
5897 struct dev_db_entry *fw_ddb_entry) 6057 struct dev_db_entry *fw_ddb_entry,
6058 uint16_t target_id)
5898{ 6059{
5899 struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; 6060 struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
5900 struct list_head list_nt; 6061 struct list_head list_nt;
@@ -5919,7 +6080,7 @@ static int qla4xxx_ddb_login_st(struct scsi_qla_host *ha,
5919 if (ret == QLA_ERROR) 6080 if (ret == QLA_ERROR)
5920 goto exit_login_st; 6081 goto exit_login_st;
5921 6082
5922 qla4xxx_build_new_nt_list(ha, &list_nt); 6083 qla4xxx_build_new_nt_list(ha, &list_nt, target_id);
5923 6084
5924 list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) { 6085 list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) {
5925 list_del_init(&ddb_idx->list); 6086 list_del_init(&ddb_idx->list);
@@ -5946,7 +6107,7 @@ static int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha,
5946{ 6107{
5947 int ret = QLA_ERROR; 6108 int ret = QLA_ERROR;
5948 6109
5949 ret = qla4xxx_is_session_exists(ha, fw_ddb_entry); 6110 ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL);
5950 if (ret != QLA_SUCCESS) 6111 if (ret != QLA_SUCCESS)
5951 ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER, 6112 ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
5952 idx); 6113 idx);
@@ -6001,7 +6162,8 @@ static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
6001 fw_ddb_entry->cookie = DDB_VALID_COOKIE; 6162 fw_ddb_entry->cookie = DDB_VALID_COOKIE;
6002 6163
6003 if (strlen((char *)fw_ddb_entry->iscsi_name) == 0) 6164 if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
6004 ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry); 6165 ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry,
6166 fnode_sess->target_id);
6005 else 6167 else
6006 ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry, 6168 ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry,
6007 fnode_sess->target_id); 6169 fnode_sess->target_id);
@@ -6926,11 +7088,10 @@ void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
6926 schedule_timeout_uninterruptible(HZ / 10); 7088 schedule_timeout_uninterruptible(HZ / 10);
6927 } while (time_after(wtime, jiffies)); 7089 } while (time_after(wtime, jiffies));
6928 7090
6929 /* Free up the sendtargets list */
6930 qla4xxx_free_ddb_list(&list_st);
6931 7091
6932 qla4xxx_build_nt_list(ha, &list_nt, is_reset); 7092 qla4xxx_build_nt_list(ha, &list_nt, &list_st, is_reset);
6933 7093
7094 qla4xxx_free_ddb_list(&list_st);
6934 qla4xxx_free_ddb_list(&list_nt); 7095 qla4xxx_free_ddb_list(&list_nt);
6935 7096
6936 qla4xxx_free_ddb_index(ha); 7097 qla4xxx_free_ddb_index(ha);