cxlflash: Fix AFU version access/storage and add check
authorMatthew R. Ochs <mrochs@linux.vnet.ibm.com>
Wed, 21 Oct 2015 20:14:01 +0000 (15:14 -0500)
committerJames Bottomley <JBottomley@Odin.com>
Fri, 30 Oct 2015 08:14:41 +0000 (17:14 +0900)
The AFU version is stored as a non-terminated string of bytes within
a 64-bit little-endian register. Presently the value is read directly
(no MMIO accessor) and is stored in a buffer that is not big enough
to contain a NULL terminator. Additionally the version obtained is not
evaluated against a known value to prevent usage with unsupported AFUs.
All of these deficiencies can lead to a variety of problems.

To remedy, use the correct MMIO accessor to read the version value into
a null-terminated buffer and add a check to prevent an incompatible AFU
from being used with this driver.

Signed-off-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>
Signed-off-by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>
Reviewed-by: Brian King <brking@linux.vnet.ibm.com>
Reviewed-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
drivers/scsi/cxlflash/common.h
drivers/scsi/cxlflash/main.c
drivers/scsi/cxlflash/sislite.h

index faf7f56f0fb30e5bc60fa87954d858cf3270ce34..3be57549fe443117ad1305bb046b1c6292b48979 100644 (file)
@@ -179,7 +179,7 @@ struct afu {
        u32 cmd_couts;          /* Number of command checkouts */
        u32 internal_lun;       /* User-desired LUN mode for this AFU */
 
-       char version[8];
+       char version[16];
        u64 interface_version;
 
        struct cxlflash_cfg *parent; /* Pointer back to parent cxlflash_cfg */
index c25efc31c3fc2567bf3c38c817bf6818c1bf9792..c1d5c886b375d1b7d6ab78277c0d82cd6950b3b3 100644 (file)
@@ -1751,14 +1751,20 @@ static int init_afu(struct cxlflash_cfg *cfg)
                goto err1;
        }
 
-       /* don't byte reverse on reading afu_version, else the string form */
-       /*     will be backwards */
-       reg = afu->afu_map->global.regs.afu_version;
-       memcpy(afu->version, &reg, 8);
+       /* No byte reverse on reading afu_version or string will be backwards */
+       reg = readq(&afu->afu_map->global.regs.afu_version);
+       memcpy(afu->version, &reg, sizeof(reg));
        afu->interface_version =
            readq_be(&afu->afu_map->global.regs.interface_version);
-       pr_debug("%s: afu version %s, interface version 0x%llX\n",
-                __func__, afu->version, afu->interface_version);
+       if ((afu->interface_version + 1) == 0) {
+               pr_err("Back level AFU, please upgrade. AFU version %s "
+                      "interface version 0x%llx\n", afu->version,
+                      afu->interface_version);
+               rc = -EINVAL;
+               goto err1;
+       } else
+               pr_debug("%s: afu version %s, interface version 0x%llX\n",
+                        __func__, afu->version, afu->interface_version);
 
        rc = start_afu(cfg);
        if (rc) {
index 63bf394fe78c7a7ffd8c5f4b131b001466c3c499..8425d1ab65ef3e666f584a0ae1956b291e3d482f 100644 (file)
@@ -340,7 +340,7 @@ struct sisl_global_regs {
 #define SISL_AFUCONF_MBOX_CLR_READ     0x0010ULL
        __be64 afu_config;
        __be64 rsvd[0xf8];
-       __be64 afu_version;
+       __le64 afu_version;
        __be64 interface_version;
 };