bool is_nvdimm_bus_locked(struct device *dev) { struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); if (!nvdimm_bus) return false; return mutex_is_locked(&nvdimm_bus->reconfig_mutex); }
void nvdimm_bus_unlock(struct device *dev) { struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); if (!nvdimm_bus) return; mutex_unlock(&nvdimm_bus->reconfig_mutex); }
int nvdimm_init_config_data(struct nvdimm_drvdata *ndd) { struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev); struct nd_cmd_get_config_data_hdr *cmd; struct nvdimm_bus_descriptor *nd_desc; int rc = validate_dimm(ndd); u32 max_cmd_size, config_size; size_t offset; if (rc) return rc; if (ndd->data) return 0; if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0 || ndd->nsarea.config_size < ND_LABEL_MIN_SIZE) { dev_dbg(ndd->dev, "failed to init config data area: (%d:%d)\n", ndd->nsarea.max_xfer, ndd->nsarea.config_size); return -ENXIO; } ndd->data = kmalloc(ndd->nsarea.config_size, GFP_KERNEL); if (!ndd->data) ndd->data = vmalloc(ndd->nsarea.config_size); if (!ndd->data) return -ENOMEM; max_cmd_size = min_t(u32, PAGE_SIZE, ndd->nsarea.max_xfer); cmd = kzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL); if (!cmd) return -ENOMEM; nd_desc = nvdimm_bus->nd_desc; for (config_size = ndd->nsarea.config_size, offset = 0; config_size; config_size -= cmd->in_length, offset += cmd->in_length) { cmd->in_length = min(config_size, max_cmd_size); cmd->in_offset = offset; rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev), ND_CMD_GET_CONFIG_DATA, cmd, cmd->in_length + sizeof(*cmd), NULL); if (rc || cmd->status) { rc = -ENXIO; break; } memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length); } dev_dbg(ndd->dev, "%s: len: %zu rc: %d\n", __func__, offset, rc); kfree(cmd); return rc; }
/** * nd_is_uuid_unique - verify that no other namespace has @uuid * @dev: any device on a nvdimm_bus * @uuid: uuid to check */ bool nd_is_uuid_unique(struct device *dev, u8 *uuid) { struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); if (!nvdimm_bus) return false; WARN_ON_ONCE(!is_nvdimm_bus_locked(&nvdimm_bus->dev)); if (device_for_each_child(&nvdimm_bus->dev, uuid, is_namespace_uuid_busy) != 0) return false; return true; }
int nd_blk_region_init(struct nd_region *nd_region) { struct device *dev = &nd_region->dev; struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); if (!is_nd_blk(dev)) return 0; if (nd_region->ndr_mappings < 1) { dev_err(dev, "invalid BLK region\n"); return -ENXIO; } return to_nd_blk_region(dev)->enable(nvdimm_bus, dev); }
int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, void *buf, size_t len) { int rc = validate_dimm(ndd); size_t max_cmd_size, buf_offset; struct nd_cmd_set_config_hdr *cmd; struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev); struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc; if (rc) return rc; if (!ndd->data) return -ENXIO; if (offset + len > ndd->nsarea.config_size) return -ENXIO; max_cmd_size = min_t(u32, PAGE_SIZE, len); max_cmd_size = min_t(u32, max_cmd_size, ndd->nsarea.max_xfer); cmd = kzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL); if (!cmd) return -ENOMEM; for (buf_offset = 0; len; len -= cmd->in_length, buf_offset += cmd->in_length) { size_t cmd_size; u32 *status; cmd->in_offset = offset + buf_offset; cmd->in_length = min(max_cmd_size, len); memcpy(cmd->in_buf, buf + buf_offset, cmd->in_length); /* status is output in the last 4-bytes of the command buffer */ cmd_size = sizeof(*cmd) + cmd->in_length + sizeof(u32); status = ((void *) cmd) + cmd_size - sizeof(u32); rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev), ND_CMD_SET_CONFIG_DATA, cmd, cmd_size, NULL); if (rc || *status) { rc = rc ? rc : -ENXIO; break; } } kfree(cmd); return rc; }
/** * nvdimm_init_nsarea - determine the geometry of a dimm's namespace area * @nvdimm: dimm to initialize */ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd) { struct nd_cmd_get_config_size *cmd = &ndd->nsarea; struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev); struct nvdimm_bus_descriptor *nd_desc; int rc = validate_dimm(ndd); if (rc) return rc; if (cmd->config_size) return 0; /* already valid */ memset(cmd, 0, sizeof(*cmd)); nd_desc = nvdimm_bus->nd_desc; return nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev), ND_CMD_GET_CONFIG_SIZE, cmd, sizeof(*cmd), NULL); }