acpi/nfit, libnvdimm/security: add Intel DSM 1.8 master passphrase support
[linux-2.6-microblaze.git] / drivers / acpi / nfit / core.c
index 14d9f5b..c246e71 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/nd.h>
 #include <asm/cacheflush.h>
 #include <acpi/nfit.h>
+#include "intel.h"
 #include "nfit.h"
 #include "intel.h"
 
@@ -380,6 +381,16 @@ static u8 nfit_dsm_revid(unsigned family, unsigned func)
                        [NVDIMM_INTEL_QUERY_FWUPDATE] = 2,
                        [NVDIMM_INTEL_SET_THRESHOLD] = 2,
                        [NVDIMM_INTEL_INJECT_ERROR] = 2,
+                       [NVDIMM_INTEL_GET_SECURITY_STATE] = 2,
+                       [NVDIMM_INTEL_SET_PASSPHRASE] = 2,
+                       [NVDIMM_INTEL_DISABLE_PASSPHRASE] = 2,
+                       [NVDIMM_INTEL_UNLOCK_UNIT] = 2,
+                       [NVDIMM_INTEL_FREEZE_LOCK] = 2,
+                       [NVDIMM_INTEL_SECURE_ERASE] = 2,
+                       [NVDIMM_INTEL_OVERWRITE] = 2,
+                       [NVDIMM_INTEL_QUERY_OVERWRITE] = 2,
+                       [NVDIMM_INTEL_SET_MASTER_PASSPHRASE] = 2,
+                       [NVDIMM_INTEL_MASTER_SECURE_ERASE] = 2,
                },
        };
        u8 id;
@@ -394,6 +405,17 @@ static u8 nfit_dsm_revid(unsigned family, unsigned func)
        return id;
 }
 
+static bool payload_dumpable(struct nvdimm *nvdimm, unsigned int func)
+{
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+       if (nfit_mem && nfit_mem->family == NVDIMM_FAMILY_INTEL
+                       && func >= NVDIMM_INTEL_GET_SECURITY_STATE
+                       && func <= NVDIMM_INTEL_MASTER_SECURE_ERASE)
+               return IS_ENABLED(CONFIG_NFIT_SECURITY_DEBUG);
+       return true;
+}
+
 int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
                unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc)
 {
@@ -478,9 +500,10 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
 
        dev_dbg(dev, "%s cmd: %d: func: %d input length: %d\n",
                dimm_name, cmd, func, in_buf.buffer.length);
-       print_hex_dump_debug("nvdimm in  ", DUMP_PREFIX_OFFSET, 4, 4,
-                       in_buf.buffer.pointer,
-                       min_t(u32, 256, in_buf.buffer.length), true);
+       if (payload_dumpable(nvdimm, func))
+               print_hex_dump_debug("nvdimm in  ", DUMP_PREFIX_OFFSET, 4, 4,
+                               in_buf.buffer.pointer,
+                               min_t(u32, 256, in_buf.buffer.length), true);
 
        /* call the BIOS, prefer the named methods over _DSM if available */
        if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE
@@ -1573,18 +1596,10 @@ static DEVICE_ATTR_RO(flags);
 static ssize_t id_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 
-       if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID)
-               return sprintf(buf, "%04x-%02x-%04x-%08x\n",
-                               be16_to_cpu(dcr->vendor_id),
-                               dcr->manufacturing_location,
-                               be16_to_cpu(dcr->manufacturing_date),
-                               be32_to_cpu(dcr->serial_number));
-       else
-               return sprintf(buf, "%04x-%08x\n",
-                               be16_to_cpu(dcr->vendor_id),
-                               be32_to_cpu(dcr->serial_number));
+       return sprintf(buf, "%s\n", nfit_mem->id);
 }
 static DEVICE_ATTR_RO(id);
 
@@ -1780,10 +1795,23 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
        const guid_t *guid;
        int i;
        int family = -1;
+       struct acpi_nfit_control_region *dcr = nfit_mem->dcr;
 
        /* nfit test assumes 1:1 relationship between commands and dsms */
        nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en;
        nfit_mem->family = NVDIMM_FAMILY_INTEL;
+
+       if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID)
+               sprintf(nfit_mem->id, "%04x-%02x-%04x-%08x",
+                               be16_to_cpu(dcr->vendor_id),
+                               dcr->manufacturing_location,
+                               be16_to_cpu(dcr->manufacturing_date),
+                               be32_to_cpu(dcr->serial_number));
+       else
+               sprintf(nfit_mem->id, "%04x-%08x",
+                               be16_to_cpu(dcr->vendor_id),
+                               be32_to_cpu(dcr->serial_number));
+
        adev = to_acpi_dev(acpi_desc);
        if (!adev) {
                /* unit test case */
@@ -1904,6 +1932,16 @@ static void shutdown_dimm_notify(void *data)
        mutex_unlock(&acpi_desc->init_mutex);
 }
 
+static const struct nvdimm_security_ops *acpi_nfit_get_security_ops(int family)
+{
+       switch (family) {
+       case NVDIMM_FAMILY_INTEL:
+               return intel_security_ops;
+       default:
+               return NULL;
+       }
+}
+
 static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
 {
        struct nfit_mem *nfit_mem;
@@ -1970,10 +2008,11 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
 
                flush = nfit_mem->nfit_flush ? nfit_mem->nfit_flush->flush
                        : NULL;
-               nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem,
+               nvdimm = __nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem,
                                acpi_nfit_dimm_attribute_groups,
                                flags, cmd_mask, flush ? flush->hint_count : 0,
-                               nfit_mem->flush_wpq);
+                               nfit_mem->flush_wpq, &nfit_mem->id[0],
+                               acpi_nfit_get_security_ops(nfit_mem->family));
                if (!nvdimm)
                        return -ENOMEM;
 
@@ -2008,6 +2047,11 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
                if (!nvdimm)
                        continue;
 
+               rc = nvdimm_security_setup_events(nvdimm);
+               if (rc < 0)
+                       dev_warn(acpi_desc->dev,
+                               "security event setup failed: %d\n", rc);
+
                nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit");
                if (nfit_kernfs)
                        nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs,
@@ -3337,7 +3381,7 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc)
        return 0;
 }
 
-static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
+static int __acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
                struct nvdimm *nvdimm, unsigned int cmd)
 {
        struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
@@ -3359,6 +3403,23 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
        return 0;
 }
 
+/* prevent security commands from being issued via ioctl */
+static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
+               struct nvdimm *nvdimm, unsigned int cmd, void *buf)
+{
+       struct nd_cmd_pkg *call_pkg = buf;
+       unsigned int func;
+
+       if (nvdimm && cmd == ND_CMD_CALL &&
+                       call_pkg->nd_family == NVDIMM_FAMILY_INTEL) {
+               func = call_pkg->nd_command;
+               if ((1 << func) & NVDIMM_INTEL_SECURITY_CMDMASK)
+                       return -EOPNOTSUPP;
+       }
+
+       return __acpi_nfit_clear_to_send(nd_desc, nvdimm, cmd);
+}
+
 int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc,
                enum nfit_ars_state req_type)
 {