提交 4549415a 编写于 作者: L Lalit Chandivade 提交者: James Bottomley

[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: NLalit Chandivade <lalit.chandivade@qlogic.com>
Signed-off-by: NVikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: NMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: NJames Bottomley <JBottomley@Parallels.com>
上级 0854f665
...@@ -279,7 +279,8 @@ struct ql82xx_hw_data { ...@@ -279,7 +279,8 @@ struct ql82xx_hw_data {
uint32_t flt_region_fw; uint32_t flt_region_fw;
uint32_t flt_iscsi_param; uint32_t flt_iscsi_param;
uint32_t reserved; uint32_t flt_region_chap;
uint32_t flt_chap_size;
}; };
struct qla4_8xxx_legacy_intr_set { struct qla4_8xxx_legacy_intr_set {
...@@ -609,6 +610,8 @@ struct scsi_qla_host { ...@@ -609,6 +610,8 @@ struct scsi_qla_host {
#define QLFLASH_READING 1 #define QLFLASH_READING 1
#define QLFLASH_WRITING 2 #define QLFLASH_WRITING 2
struct dma_pool *chap_dma_pool; struct dma_pool *chap_dma_pool;
uint8_t *chap_list; /* CHAP table cache */
struct mutex chap_sem;
#define CHAP_DMA_BLOCK_SIZE 512 #define CHAP_DMA_BLOCK_SIZE 512
struct workqueue_struct *task_wq; struct workqueue_struct *task_wq;
unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG]; unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG];
...@@ -671,6 +674,11 @@ static inline int is_qla4032(struct scsi_qla_host *ha) ...@@ -671,6 +674,11 @@ static inline int is_qla4032(struct scsi_qla_host *ha)
return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4032; return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4032;
} }
static inline int is_qla40XX(struct scsi_qla_host *ha)
{
return is_qla4032(ha) || is_qla4022(ha) || is_qla4010(ha);
}
static inline int is_qla8022(struct scsi_qla_host *ha) static inline int is_qla8022(struct scsi_qla_host *ha)
{ {
return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022; return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022;
......
...@@ -251,6 +251,8 @@ union external_hw_config_reg { ...@@ -251,6 +251,8 @@ union external_hw_config_reg {
#define FA_BOOT_CODE_ADDR_82 0x20000 #define FA_BOOT_CODE_ADDR_82 0x20000
#define FA_RISC_CODE_ADDR_82 0x40000 #define FA_RISC_CODE_ADDR_82 0x40000
#define FA_GOLD_RISC_CODE_ADDR_82 0x80000 #define FA_GOLD_RISC_CODE_ADDR_82 0x80000
#define FA_FLASH_ISCSI_CHAP 0x540000
#define FA_FLASH_CHAP_SIZE 0xC0000
/* Flash Description Table */ /* Flash Description Table */
struct qla_fdt_layout { struct qla_fdt_layout {
...@@ -310,6 +312,7 @@ struct qla_flt_header { ...@@ -310,6 +312,7 @@ struct qla_flt_header {
#define FLT_REG_GOLD_FW_82 0x75 #define FLT_REG_GOLD_FW_82 0x75
#define FLT_REG_BOOT_CODE_82 0x78 #define FLT_REG_BOOT_CODE_82 0x78
#define FLT_REG_ISCSI_PARAM 0x65 #define FLT_REG_ISCSI_PARAM 0x65
#define FLT_REG_ISCSI_CHAP 0x63
struct qla_flt_region { struct qla_flt_region {
uint32_t code; uint32_t code;
...@@ -681,6 +684,8 @@ struct addr_ctrl_blk_def { ...@@ -681,6 +684,8 @@ struct addr_ctrl_blk_def {
#define MAX_CHAP_ENTRIES_40XX 128 #define MAX_CHAP_ENTRIES_40XX 128
#define MAX_CHAP_ENTRIES_82XX 1024 #define MAX_CHAP_ENTRIES_82XX 1024
#define MAX_RESRV_CHAP_IDX 3
#define FLASH_CHAP_OFFSET 0x06000000
struct ql4_chap_table { struct ql4_chap_table {
uint16_t link; uint16_t link;
......
...@@ -1304,7 +1304,7 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password, ...@@ -1304,7 +1304,7 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password,
{ {
int ret = 0; int ret = 0;
int rval = QLA_ERROR; int rval = QLA_ERROR;
uint32_t offset = 0; uint32_t offset = 0, chap_size;
struct ql4_chap_table *chap_table; struct ql4_chap_table *chap_table;
dma_addr_t chap_dma; dma_addr_t chap_dma;
...@@ -1314,12 +1314,22 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password, ...@@ -1314,12 +1314,22 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password,
goto exit_get_chap; goto exit_get_chap;
} }
memset(chap_table, 0, sizeof(struct ql4_chap_table)); chap_size = sizeof(struct ql4_chap_table);
memset(chap_table, 0, chap_size);
offset = 0x06000000 | (idx * sizeof(struct ql4_chap_table)); 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, rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
sizeof(struct ql4_chap_table));
if (rval != QLA_SUCCESS) { if (rval != QLA_SUCCESS) {
ret = -EINVAL; ret = -EINVAL;
goto exit_get_chap; goto exit_get_chap;
...@@ -1366,10 +1376,16 @@ static int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, ...@@ -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->secret, password, MAX_CHAP_SECRET_LEN);
strncpy(chap_table->name, username, MAX_CHAP_NAME_LEN); strncpy(chap_table->name, username, MAX_CHAP_NAME_LEN);
chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE); 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, rval = qla4xxx_set_flash(ha, chap_dma, offset,
sizeof(struct ql4_chap_table), sizeof(struct ql4_chap_table),
FLASH_OPT_RMW_COMMIT); 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); dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
if (rval != QLA_SUCCESS) if (rval != QLA_SUCCESS)
ret = -EINVAL; ret = -EINVAL;
...@@ -1378,6 +1394,83 @@ static int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, ...@@ -1378,6 +1394,83 @@ static int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username,
return ret; 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, int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha,
uint16_t fw_ddb_index, uint16_t fw_ddb_index,
uint16_t connection_id, uint16_t connection_id,
...@@ -1490,7 +1583,6 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, ...@@ -1490,7 +1583,6 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha,
uint16_t iscsi_opts = 0; uint16_t iscsi_opts = 0;
uint32_t options = 0; uint32_t options = 0;
uint16_t idx; 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_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
&fw_ddb_entry_dma, GFP_KERNEL); &fw_ddb_entry_dma, GFP_KERNEL);
...@@ -1559,26 +1651,14 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, ...@@ -1559,26 +1651,14 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha,
goto exit_set_param; goto exit_set_param;
} }
if (is_qla8022(ha))
max_chap_entries = MAX_CHAP_ENTRIES_82XX;
else
max_chap_entries = MAX_CHAP_ENTRIES_40XX;
/* CHAP */ /* CHAP */
if (sess->username != NULL && sess->password != NULL) { if (sess->username != NULL && sess->password != NULL) {
if (strlen(sess->username) && strlen(sess->password)) { if (strlen(sess->username) && strlen(sess->password)) {
iscsi_opts |= BIT_7; 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, rval = qla4xxx_get_chap_index(ha, sess->username,
sess->password, idx, sess->password,
LOCAL_CHAP); LOCAL_CHAP, &idx);
if (rval) if (rval)
goto exit_set_param; goto exit_set_param;
...@@ -1590,17 +1670,10 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, ...@@ -1590,17 +1670,10 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha,
/* Check if BIDI CHAP */ /* Check if BIDI CHAP */
if (strlen(sess->username_in) && strlen(sess->password_in)) { if (strlen(sess->username_in) && strlen(sess->password_in)) {
iscsi_opts |= BIT_4; iscsi_opts |= BIT_4;
idx = (ddb_entry->fw_ddb_index * 2) + 1;
if (idx > max_chap_entries) { rval = qla4xxx_get_chap_index(ha, sess->username_in,
ql4_printk(KERN_ERR, ha, sess->password_in,
"%s: Invalid ddb or bidi chap " BIDI_CHAP, &idx);
"index\n", __func__);
rval = -EINVAL;
goto exit_set_param;
}
rval = qla4xxx_set_chap(ha, sess->username_in,
sess->password_in, idx,
BIDI_CHAP);
if (rval) if (rval)
goto exit_set_param; goto exit_set_param;
} }
......
...@@ -2024,6 +2024,10 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr) ...@@ -2024,6 +2024,10 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
case FLT_REG_ISCSI_PARAM: case FLT_REG_ISCSI_PARAM:
hw->flt_iscsi_param = start; hw->flt_iscsi_param = start;
break; break;
case FLT_REG_ISCSI_CHAP:
hw->flt_region_chap = start;
hw->flt_chap_size = le32_to_cpu(region->size);
break;
} }
} }
goto done; goto done;
...@@ -2036,6 +2040,9 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr) ...@@ -2036,6 +2040,9 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
hw->flt_region_boot = FA_BOOT_CODE_ADDR_82; hw->flt_region_boot = FA_BOOT_CODE_ADDR_82;
hw->flt_region_bootload = FA_BOOT_LOAD_ADDR_82; hw->flt_region_bootload = FA_BOOT_LOAD_ADDR_82;
hw->flt_region_fw = FA_RISC_CODE_ADDR_82; hw->flt_region_fw = FA_RISC_CODE_ADDR_82;
hw->flt_region_chap = FA_FLASH_ISCSI_CHAP;
hw->flt_chap_size = FA_FLASH_CHAP_SIZE;
done: done:
DEBUG2(ql4_printk(KERN_INFO, ha, "FLT[%s]: flt=0x%x fdt=0x%x " DEBUG2(ql4_printk(KERN_INFO, ha, "FLT[%s]: flt=0x%x fdt=0x%x "
"boot=0x%x bootload=0x%x fw=0x%x\n", loc, hw->flt_region_flt, "boot=0x%x bootload=0x%x fw=0x%x\n", loc, hw->flt_region_flt,
......
...@@ -1605,6 +1605,10 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) ...@@ -1605,6 +1605,10 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha)
if (ha->chap_dma_pool) if (ha->chap_dma_pool)
dma_pool_destroy(ha->chap_dma_pool); dma_pool_destroy(ha->chap_dma_pool);
if (ha->chap_list)
vfree(ha->chap_list);
ha->chap_list = NULL;
/* release io space registers */ /* release io space registers */
if (is_qla8022(ha)) { if (is_qla8022(ha)) {
if (ha->nx_pcibase) if (ha->nx_pcibase)
...@@ -3058,6 +3062,66 @@ static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) ...@@ -3058,6 +3062,66 @@ static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha)
return -ENOMEM; return -ENOMEM;
} }
/**
* qla4xxx_create chap_list - Create CHAP list from FLASH
* @ha: pointer to adapter structure
*
* Read flash and make a list of CHAP entries, during login when a CHAP entry
* is received, it will be checked in this list. If entry exist then the CHAP
* entry index is set in the DDB. If CHAP entry does not exist in this list
* then a new entry is added in FLASH in CHAP table and the index obtained is
* used in the DDB.
**/
static void qla4xxx_create_chap_list(struct scsi_qla_host *ha)
{
int rval = 0;
uint8_t *chap_flash_data = NULL;
uint32_t offset;
dma_addr_t chap_dma;
uint32_t chap_size = 0;
if (is_qla40XX(ha))
chap_size = MAX_CHAP_ENTRIES_40XX *
sizeof(struct ql4_chap_table);
else /* Single region contains CHAP info for both
* ports which is divided into half for each port.
*/
chap_size = ha->hw.flt_chap_size / 2;
chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size,
&chap_dma, GFP_KERNEL);
if (!chap_flash_data) {
ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n");
return;
}
if (is_qla40XX(ha))
offset = FLASH_CHAP_OFFSET;
else {
offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
if (ha->port_num == 1)
offset += chap_size;
}
rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
if (rval != QLA_SUCCESS)
goto exit_chap_list;
if (ha->chap_list == NULL)
ha->chap_list = vmalloc(chap_size);
if (ha->chap_list == NULL) {
ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n");
goto exit_chap_list;
}
memcpy(ha->chap_list, chap_flash_data, chap_size);
exit_chap_list:
dma_free_coherent(&ha->pdev->dev, chap_size,
chap_flash_data, chap_dma);
return;
}
/** /**
* qla4xxx_probe_adapter - callback function to probe HBA * qla4xxx_probe_adapter - callback function to probe HBA
* @pdev: pointer to pci_dev structure * @pdev: pointer to pci_dev structure
...@@ -3135,6 +3199,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ...@@ -3135,6 +3199,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
INIT_LIST_HEAD(&ha->free_srb_q); INIT_LIST_HEAD(&ha->free_srb_q);
mutex_init(&ha->mbox_sem); mutex_init(&ha->mbox_sem);
mutex_init(&ha->chap_sem);
init_completion(&ha->mbx_intr_comp); init_completion(&ha->mbx_intr_comp);
init_completion(&ha->disable_acb_comp); init_completion(&ha->disable_acb_comp);
...@@ -3266,6 +3331,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ...@@ -3266,6 +3331,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
ha->patch_number, ha->build_number); ha->patch_number, ha->build_number);
qla4xxx_create_chap_list(ha);
if (qla4xxx_setup_boot_info(ha)) if (qla4xxx_setup_boot_info(ha))
ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n", ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n",
__func__); __func__);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册