[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 scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj))); struct device, kobj)));
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
ssize_t rval = 0;
if (ha->optrom_state != QLA_SREADING) if (ha->optrom_state != QLA_SREADING)
return 0; return 0;
return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer, mutex_lock(&ha->optrom_mutex);
ha->optrom_region_size); 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 static ssize_t
@ -265,7 +270,9 @@ qla2x00_sysfs_write_optrom(struct file *filp, struct kobject *kobj,
if (off + count > ha->optrom_region_size) if (off + count > ha->optrom_region_size)
count = ha->optrom_region_size - off; count = ha->optrom_region_size - off;
mutex_lock(&ha->optrom_mutex);
memcpy(&ha->optrom_buffer[off], buf, count); memcpy(&ha->optrom_buffer[off], buf, count);
mutex_unlock(&ha->optrom_mutex);
return count; 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 scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj))); struct device, kobj)));
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
uint32_t start = 0; uint32_t start = 0;
uint32_t size = ha->optrom_size; uint32_t size = ha->optrom_size;
int val, valid; int val, valid;
ssize_t rval = count;
if (off) if (off)
return -EINVAL; return -EINVAL;
@ -304,12 +311,14 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
if (start > ha->optrom_size) if (start > ha->optrom_size)
return -EINVAL; return -EINVAL;
mutex_lock(&ha->optrom_mutex);
switch (val) { switch (val) {
case 0: case 0:
if (ha->optrom_state != QLA_SREADING && if (ha->optrom_state != QLA_SREADING &&
ha->optrom_state != QLA_SWRITING) ha->optrom_state != QLA_SWRITING) {
return -EINVAL; rval = -EINVAL;
goto out;
}
ha->optrom_state = QLA_SWAITING; ha->optrom_state = QLA_SWAITING;
ql_dbg(ql_dbg_user, vha, 0x7061, 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; ha->optrom_buffer = NULL;
break; break;
case 1: case 1:
if (ha->optrom_state != QLA_SWAITING) if (ha->optrom_state != QLA_SWAITING) {
return -EINVAL; rval = -EINVAL;
goto out;
}
ha->optrom_region_start = start; ha->optrom_region_start = start;
ha->optrom_region_size = start + size > ha->optrom_size ? 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); "(%x).\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING; ha->optrom_state = QLA_SWAITING;
return -ENOMEM; rval = -ENOMEM;
goto out;
} }
if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7063, ql_log(ql_log_warn, vha, 0x7063,
"HBA not online, failing NVRAM update.\n"); "HBA not online, failing NVRAM update.\n");
return -EAGAIN; rval = -EAGAIN;
goto out;
} }
ql_dbg(ql_dbg_user, vha, 0x7064, 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); ha->optrom_region_start, ha->optrom_region_size);
break; break;
case 2: case 2:
if (ha->optrom_state != QLA_SWAITING) if (ha->optrom_state != QLA_SWAITING) {
return -EINVAL; rval = -EINVAL;
goto out;
}
/* /*
* We need to be more restrictive on which FLASH regions are * 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) { if (!valid) {
ql_log(ql_log_warn, vha, 0x7065, ql_log(ql_log_warn, vha, 0x7065,
"Invalid start region 0x%x/0x%x.\n", start, size); "Invalid start region 0x%x/0x%x.\n", start, size);
return -EINVAL; rval = -EINVAL;
goto out;
} }
ha->optrom_region_start = start; 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); "(%x)\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING; ha->optrom_state = QLA_SWAITING;
return -ENOMEM; rval = -ENOMEM;
goto out;
} }
ql_dbg(ql_dbg_user, vha, 0x7067, 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); memset(ha->optrom_buffer, 0, ha->optrom_region_size);
break; break;
case 3: case 3:
if (ha->optrom_state != QLA_SWRITING) if (ha->optrom_state != QLA_SWRITING) {
return -EINVAL; rval = -EINVAL;
goto out;
}
if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7068, ql_log(ql_log_warn, vha, 0x7068,
"HBA not online, failing flash update.\n"); "HBA not online, failing flash update.\n");
return -EAGAIN; rval = -EAGAIN;
goto out;
} }
ql_dbg(ql_dbg_user, vha, 0x7069, 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); ha->optrom_region_start, ha->optrom_region_size);
break; break;
default: default:
return -EINVAL; rval = -EINVAL;
} }
return count;
out:
mutex_unlock(&ha->optrom_mutex);
return rval;
} }
static struct bin_attribute sysfs_optrom_ctl_attr = { 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) if (ha->flags.nic_core_reset_hdlr_active)
return -EBUSY; return -EBUSY;
mutex_lock(&ha->optrom_mutex);
rval = qla2x00_optrom_setup(bsg_job, vha, 0); rval = qla2x00_optrom_setup(bsg_job, vha, 0);
if (rval) if (rval) {
mutex_unlock(&ha->optrom_mutex);
return rval; return rval;
}
ha->isp_ops->read_optrom(vha, ha->optrom_buffer, ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
ha->optrom_region_start, ha->optrom_region_size); 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); vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL; ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING; ha->optrom_state = QLA_SWAITING;
mutex_unlock(&ha->optrom_mutex);
bsg_job->job_done(bsg_job); bsg_job->job_done(bsg_job);
return rval; return rval;
} }
@ -1465,9 +1469,12 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
int rval = 0; int rval = 0;
mutex_lock(&ha->optrom_mutex);
rval = qla2x00_optrom_setup(bsg_job, vha, 1); rval = qla2x00_optrom_setup(bsg_job, vha, 1);
if (rval) if (rval) {
mutex_unlock(&ha->optrom_mutex);
return rval; return rval;
}
/* Set the isp82xx_no_md_cap not to capture minidump */ /* Set the isp82xx_no_md_cap not to capture minidump */
ha->flags.isp82xx_no_md_cap = 1; ha->flags.isp82xx_no_md_cap = 1;
@ -1483,6 +1490,7 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
vfree(ha->optrom_buffer); vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL; ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING; ha->optrom_state = QLA_SWAITING;
mutex_unlock(&ha->optrom_mutex);
bsg_job->job_done(bsg_job); bsg_job->job_done(bsg_job);
return rval; return rval;
} }

View file

@ -3183,6 +3183,7 @@ struct qla_hw_data {
#define QLA_SWRITING 2 #define QLA_SWRITING 2
uint32_t optrom_region_start; uint32_t optrom_region_start;
uint32_t optrom_region_size; uint32_t optrom_region_size;
struct mutex optrom_mutex;
/* PCI expansion ROM image information. */ /* PCI expansion ROM image information. */
#define ROM_CODE_TYPE_BIOS 0 #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->hardware_lock);
spin_lock_init(&ha->vport_slock); spin_lock_init(&ha->vport_slock);
mutex_init(&ha->selflogin_lock); mutex_init(&ha->selflogin_lock);
mutex_init(&ha->optrom_mutex);
/* Set ISP-type information. */ /* Set ISP-type information. */
qla2x00_set_isp_flags(ha); qla2x00_set_isp_flags(ha);