[SCSI] qla2xxx: Add mutex around optrom calls to serialize accesses.

Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: Saurav Kashyap <saurav.kashyap@qlogic.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
Chad Dupuis 2014-02-26 04:14:56 -05:00 committed by James Bottomley
parent 38e83bff14
commit 7a8ab9c840
4 changed files with 54 additions and 21 deletions

View file

@ -241,12 +241,17 @@ qla2x00_sysfs_read_optrom(struct file *filp, struct kobject *kobj,
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
ssize_t rval = 0;
if (ha->optrom_state != QLA_SREADING)
return 0;
return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
ha->optrom_region_size);
mutex_lock(&ha->optrom_mutex);
rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
ha->optrom_region_size);
mutex_unlock(&ha->optrom_mutex);
return rval;
}
static ssize_t
@ -265,7 +270,9 @@ qla2x00_sysfs_write_optrom(struct file *filp, struct kobject *kobj,
if (off + count > ha->optrom_region_size)
count = ha->optrom_region_size - off;
mutex_lock(&ha->optrom_mutex);
memcpy(&ha->optrom_buffer[off], buf, count);
mutex_unlock(&ha->optrom_mutex);
return count;
}
@ -288,10 +295,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
uint32_t start = 0;
uint32_t size = ha->optrom_size;
int val, valid;
ssize_t rval = count;
if (off)
return -EINVAL;
@ -304,12 +311,14 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
if (start > ha->optrom_size)
return -EINVAL;
mutex_lock(&ha->optrom_mutex);
switch (val) {
case 0:
if (ha->optrom_state != QLA_SREADING &&
ha->optrom_state != QLA_SWRITING)
return -EINVAL;
ha->optrom_state != QLA_SWRITING) {
rval = -EINVAL;
goto out;
}
ha->optrom_state = QLA_SWAITING;
ql_dbg(ql_dbg_user, vha, 0x7061,
@ -320,8 +329,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
ha->optrom_buffer = NULL;
break;
case 1:
if (ha->optrom_state != QLA_SWAITING)
return -EINVAL;
if (ha->optrom_state != QLA_SWAITING) {
rval = -EINVAL;
goto out;
}
ha->optrom_region_start = start;
ha->optrom_region_size = start + size > ha->optrom_size ?
@ -335,13 +346,15 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
"(%x).\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING;
return -ENOMEM;
rval = -ENOMEM;
goto out;
}
if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7063,
"HBA not online, failing NVRAM update.\n");
return -EAGAIN;
rval = -EAGAIN;
goto out;
}
ql_dbg(ql_dbg_user, vha, 0x7064,
@ -353,8 +366,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
ha->optrom_region_start, ha->optrom_region_size);
break;
case 2:
if (ha->optrom_state != QLA_SWAITING)
return -EINVAL;
if (ha->optrom_state != QLA_SWAITING) {
rval = -EINVAL;
goto out;
}
/*
* We need to be more restrictive on which FLASH regions are
@ -388,7 +403,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
if (!valid) {
ql_log(ql_log_warn, vha, 0x7065,
"Invalid start region 0x%x/0x%x.\n", start, size);
return -EINVAL;
rval = -EINVAL;
goto out;
}
ha->optrom_region_start = start;
@ -403,7 +419,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
"(%x)\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING;
return -ENOMEM;
rval = -ENOMEM;
goto out;
}
ql_dbg(ql_dbg_user, vha, 0x7067,
@ -413,13 +430,16 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
memset(ha->optrom_buffer, 0, ha->optrom_region_size);
break;
case 3:
if (ha->optrom_state != QLA_SWRITING)
return -EINVAL;
if (ha->optrom_state != QLA_SWRITING) {
rval = -EINVAL;
goto out;
}
if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7068,
"HBA not online, failing flash update.\n");
return -EAGAIN;
rval = -EAGAIN;
goto out;
}
ql_dbg(ql_dbg_user, vha, 0x7069,
@ -430,9 +450,12 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
ha->optrom_region_start, ha->optrom_region_size);
break;
default:
return -EINVAL;
rval = -EINVAL;
}
return count;
out:
mutex_unlock(&ha->optrom_mutex);
return rval;
}
static struct bin_attribute sysfs_optrom_ctl_attr = {

View file

@ -1437,9 +1437,12 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
if (ha->flags.nic_core_reset_hdlr_active)
return -EBUSY;
mutex_lock(&ha->optrom_mutex);
rval = qla2x00_optrom_setup(bsg_job, vha, 0);
if (rval)
if (rval) {
mutex_unlock(&ha->optrom_mutex);
return rval;
}
ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
ha->optrom_region_start, ha->optrom_region_size);
@ -1453,6 +1456,7 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING;
mutex_unlock(&ha->optrom_mutex);
bsg_job->job_done(bsg_job);
return rval;
}
@ -1465,9 +1469,12 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
struct qla_hw_data *ha = vha->hw;
int rval = 0;
mutex_lock(&ha->optrom_mutex);
rval = qla2x00_optrom_setup(bsg_job, vha, 1);
if (rval)
if (rval) {
mutex_unlock(&ha->optrom_mutex);
return rval;
}
/* Set the isp82xx_no_md_cap not to capture minidump */
ha->flags.isp82xx_no_md_cap = 1;
@ -1483,6 +1490,7 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING;
mutex_unlock(&ha->optrom_mutex);
bsg_job->job_done(bsg_job);
return rval;
}

View file

@ -3183,6 +3183,7 @@ struct qla_hw_data {
#define QLA_SWRITING 2
uint32_t optrom_region_start;
uint32_t optrom_region_size;
struct mutex optrom_mutex;
/* PCI expansion ROM image information. */
#define ROM_CODE_TYPE_BIOS 0

View file

@ -2334,6 +2334,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ha->hardware_lock);
spin_lock_init(&ha->vport_slock);
mutex_init(&ha->selflogin_lock);
mutex_init(&ha->optrom_mutex);
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);