summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla4xxx/ql4_mbx.c
diff options
context:
space:
mode:
authorLalit Chandivade <lalit.chandivade@qlogic.com>2011-10-08 01:55:42 +0200
committerJames Bottomley <JBottomley@Parallels.com>2011-10-16 18:08:41 +0200
commit4549415af6915017f5d3fbdbfd5edd1dfbe63fa9 (patch)
treeb06ad5224dd3093d6fd9377d8461a295f101e1b7 /drivers/scsi/qla4xxx/ql4_mbx.c
parent[SCSI] qla4xxx: Fix bidirectional CHAP. (diff)
downloadlinux-4549415af6915017f5d3fbdbfd5edd1dfbe63fa9.tar.xz
linux-4549415af6915017f5d3fbdbfd5edd1dfbe63fa9.zip
[SCSI] qla4xxx: Do not add duplicate CHAP entry in FLASH
QLogic applications store the CHAP information in FLASH. During login, authentication information is provided using an index into the CHAP region. In order to support QLogic applications along with iscsiadm, updated the LLD to not add duplicate CHAP entries in the CHAP region and preserve the existing CHAP info in the CHAP region in FLASH. This allows QLogic applications to pre-write the CHAP entries in the CHAP region. With iscsiadm, when the CHAP authentication information is sent to the LLD, the LLD searches for the entry in CHAP region in FLASH, if exists then do not add. If CHAP entry does not exist then add the CHAP entry in the CHAP region. JIRA Key: UPSISCSI-146 Signed-off-by: Lalit Chandivade <lalit.chandivade@qlogic.com> Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com> Reviewed-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_mbx.c')
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c141
1 files changed, 107 insertions, 34 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index b60b90301a8b..4c2b84870392 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;
}