diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_mbx.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 141 |
1 files changed, 107 insertions, 34 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index b60b903..4c2b848 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -1304,7 +1304,7 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password, { int ret = 0; int rval = QLA_ERROR; - uint32_t offset = 0; + uint32_t offset = 0, chap_size; struct ql4_chap_table *chap_table; dma_addr_t chap_dma; @@ -1314,12 +1314,22 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password, goto exit_get_chap; } - memset(chap_table, 0, sizeof(struct ql4_chap_table)); - - offset = 0x06000000 | (idx * sizeof(struct ql4_chap_table)); + chap_size = sizeof(struct ql4_chap_table); + memset(chap_table, 0, chap_size); + + if (is_qla40XX(ha)) + offset = FLASH_CHAP_OFFSET | (idx * chap_size); + else { + offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2); + /* flt_chap_size is CHAP table size for both ports + * so divide it by 2 to calculate the offset for second port + */ + if (ha->port_num == 1) + offset += (ha->hw.flt_chap_size / 2); + offset += (idx * chap_size); + } - rval = qla4xxx_get_flash(ha, chap_dma, offset, - sizeof(struct ql4_chap_table)); + rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size); if (rval != QLA_SUCCESS) { ret = -EINVAL; goto exit_get_chap; @@ -1366,10 +1376,16 @@ static int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, strncpy(chap_table->secret, password, MAX_CHAP_SECRET_LEN); strncpy(chap_table->name, username, MAX_CHAP_NAME_LEN); chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE); - offset = 0x06000000 | (idx * sizeof(struct ql4_chap_table)); + offset = FLASH_CHAP_OFFSET | (idx * sizeof(struct ql4_chap_table)); rval = qla4xxx_set_flash(ha, chap_dma, offset, sizeof(struct ql4_chap_table), FLASH_OPT_RMW_COMMIT); + + if (rval == QLA_SUCCESS && ha->chap_list) { + /* Update ha chap_list cache */ + memcpy((struct ql4_chap_table *)ha->chap_list + idx, + chap_table, sizeof(struct ql4_chap_table)); + } dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma); if (rval != QLA_SUCCESS) ret = -EINVAL; @@ -1378,6 +1394,83 @@ exit_set_chap: return ret; } +/** + * qla4xxx_get_chap_index - Get chap index given username and secret + * @ha: pointer to adapter structure + * @username: CHAP username to be searched + * @password: CHAP password to be searched + * @bidi: Is this a BIDI CHAP + * @chap_index: CHAP index to be returned + * + * Match the username and password in the chap_list, return the index if a + * match is found. If a match is not found then add the entry in FLASH and + * return the index at which entry is written in the FLASH. + **/ +static int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username, + char *password, int bidi, uint16_t *chap_index) +{ + int i, rval; + int free_index = -1; + int found_index = 0; + int max_chap_entries = 0; + struct ql4_chap_table *chap_table; + + if (is_qla8022(ha)) + max_chap_entries = (ha->hw.flt_chap_size / 2) / + sizeof(struct ql4_chap_table); + else + max_chap_entries = MAX_CHAP_ENTRIES_40XX; + + if (!ha->chap_list) { + ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n"); + return QLA_ERROR; + } + + mutex_lock(&ha->chap_sem); + for (i = 0; i < max_chap_entries; i++) { + chap_table = (struct ql4_chap_table *)ha->chap_list + i; + if (chap_table->cookie != + __constant_cpu_to_le16(CHAP_VALID_COOKIE)) { + if (i > MAX_RESRV_CHAP_IDX && free_index == -1) + free_index = i; + continue; + } + if (bidi) { + if (chap_table->flags & BIT_7) + continue; + } else { + if (chap_table->flags & BIT_6) + continue; + } + if (!strncmp(chap_table->secret, password, + MAX_CHAP_SECRET_LEN) && + !strncmp(chap_table->name, username, + MAX_CHAP_NAME_LEN)) { + *chap_index = i; + found_index = 1; + break; + } + } + + /* If chap entry is not present and a free index is available then + * write the entry in flash + */ + if (!found_index && free_index != -1) { + rval = qla4xxx_set_chap(ha, username, password, + free_index, bidi); + if (!rval) { + *chap_index = free_index; + found_index = 1; + } + } + + mutex_unlock(&ha->chap_sem); + + if (found_index) + return QLA_SUCCESS; + return QLA_ERROR; +} + int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha, uint16_t fw_ddb_index, uint16_t connection_id, @@ -1490,7 +1583,6 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, uint16_t iscsi_opts = 0; uint32_t options = 0; uint16_t idx; - int max_chap_entries = 0; fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), &fw_ddb_entry_dma, GFP_KERNEL); @@ -1559,26 +1651,14 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, goto exit_set_param; } - if (is_qla8022(ha)) - max_chap_entries = MAX_CHAP_ENTRIES_82XX; - else - max_chap_entries = MAX_CHAP_ENTRIES_40XX; /* CHAP */ if (sess->username != NULL && sess->password != NULL) { if (strlen(sess->username) && strlen(sess->password)) { iscsi_opts |= BIT_7; - idx = ddb_entry->fw_ddb_index * 2; - if (idx > max_chap_entries) { - ql4_printk(KERN_ERR, ha, - "%s: Invalid ddb or chap index\n", - __func__); - rval = -EINVAL; - goto exit_set_param; - } - rval = qla4xxx_set_chap(ha, sess->username, - sess->password, idx, - LOCAL_CHAP); + rval = qla4xxx_get_chap_index(ha, sess->username, + sess->password, + LOCAL_CHAP, &idx); if (rval) goto exit_set_param; @@ -1590,17 +1670,10 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, /* Check if BIDI CHAP */ if (strlen(sess->username_in) && strlen(sess->password_in)) { iscsi_opts |= BIT_4; - idx = (ddb_entry->fw_ddb_index * 2) + 1; - if (idx > max_chap_entries) { - ql4_printk(KERN_ERR, ha, - "%s: Invalid ddb or bidi chap " - "index\n", __func__); - rval = -EINVAL; - goto exit_set_param; - } - rval = qla4xxx_set_chap(ha, sess->username_in, - sess->password_in, idx, - BIDI_CHAP); + + rval = qla4xxx_get_chap_index(ha, sess->username_in, + sess->password_in, + BIDI_CHAP, &idx); if (rval) goto exit_set_param; } |