]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
qla2xxx: Add mutex around optrom calls to serialize accesses.
authorChad Dupuis <chad.dupuis@qlogic.com>
Wed, 26 Feb 2014 09:14:56 +0000 (04:14 -0500)
committerBen Hutchings <ben@decadent.org.uk>
Sun, 26 Nov 2017 13:51:06 +0000 (13:51 +0000)
commit 7a8ab9c840b5dff9bb70328338a86444ed1c2415 upstream.

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>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_os.c

index ee9500587e6c8e857b253ab6555815cec66530ba..7692f94cce77361ae55155fc5a23bef77f238f3b 100644 (file)
@@ -215,12 +215,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
@@ -239,7 +244,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;
 }
@@ -262,10 +269,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;
@@ -278,12 +285,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,
@@ -294,8 +303,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 ?
@@ -309,13 +320,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,
@@ -327,8 +340,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
@@ -361,7 +376,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;
@@ -376,7 +392,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,
@@ -386,13 +403,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,
@@ -403,9 +423,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 = {
index 8b641a8a0c74aed39307c73036de328e9cd11fee..30edc4b8ed1366fdb1d6d92b466852228e9b2a8f 100644 (file)
@@ -1400,9 +1400,12 @@ qla2x00_read_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, 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);
@@ -1416,6 +1419,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;
 }
@@ -1428,9 +1432,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;
+       }
 
        sg_copy_to_buffer(bsg_job->request_payload.sg_list,
            bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
@@ -1443,6 +1450,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;
 }
index c491a945f86020bcd0ae2f5cabce06276b3d7d1a..2032c3f1da4cd4c6619282015cf55d30eeba5aa3 100644 (file)
@@ -2723,6 +2723,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
index 6cda887fa797d1c67a7420c3fe64b042d71be0ec..7a5217fd0218767abc4ed5797a593ff321207f4b 100644 (file)
@@ -2023,6 +2023,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->mem_only = mem_only;
        spin_lock_init(&ha->hardware_lock);
        spin_lock_init(&ha->vport_slock);
+       mutex_init(&ha->optrom_mutex);
 
        /* Set ISP-type information. */
        qla2x00_set_isp_flags(ha);