#include <linux/nd.h>
#include <asm/cacheflush.h>
#include <acpi/nfit.h>
+#include "intel.h"
#include "nfit.h"
#include "intel.h"
[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;
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)
{
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
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);
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 */
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;
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;
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,
return rc;
if (ars_status_process_records(acpi_desc))
- return -ENOMEM;
+ dev_err(acpi_desc->dev, "Failed to process ARS records\n");
- return 0;
+ return rc;
}
static int ars_register(struct acpi_nfit_desc *acpi_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);
- struct nfit_spa *nfit_spa;
- int rc = 0;
if (nvdimm)
return 0;
* just needs guarantees that any ARS it initiates are not
* interrupted by any intervening start requests from userspace.
*/
- mutex_lock(&acpi_desc->init_mutex);
- list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
- if (acpi_desc->scrub_spa
- || test_bit(ARS_REQ_SHORT, &nfit_spa->ars_state)
- || test_bit(ARS_REQ_LONG, &nfit_spa->ars_state)) {
- rc = -EBUSY;
- break;
- }
- mutex_unlock(&acpi_desc->init_mutex);
+ if (work_busy(&acpi_desc->dwork.work))
+ return -EBUSY;
- return rc;
+ 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,