diff options
Diffstat (limited to 'drivers/nvdimm/dimm_devs.c')
-rw-r--r-- | drivers/nvdimm/dimm_devs.c | 60 |
1 files changed, 24 insertions, 36 deletions
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 863cabc35215..6c3de2317390 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -85,56 +85,48 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd) return cmd_rc; } -int nvdimm_init_config_data(struct nvdimm_drvdata *ndd) +int nvdimm_get_config_data(struct nvdimm_drvdata *ndd, void *buf, + size_t offset, size_t len) { struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev); + struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc; int rc = validate_dimm(ndd), cmd_rc = 0; struct nd_cmd_get_config_data_hdr *cmd; - struct nvdimm_bus_descriptor *nd_desc; - u32 max_cmd_size, config_size; - size_t offset; + size_t max_cmd_size, buf_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); + if (offset + len > ndd->nsarea.config_size) return -ENXIO; - } - ndd->data = kvmalloc(ndd->nsarea.config_size, GFP_KERNEL); - 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); + max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer); + cmd = kvzalloc(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; + for (buf_offset = 0; len; + len -= cmd->in_length, buf_offset += cmd->in_length) { + size_t cmd_size; + + cmd->in_offset = offset + buf_offset; + cmd->in_length = min(max_cmd_size, len); + + cmd_size = sizeof(*cmd) + cmd->in_length; + rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev), - ND_CMD_GET_CONFIG_DATA, cmd, - cmd->in_length + sizeof(*cmd), &cmd_rc); + ND_CMD_GET_CONFIG_DATA, cmd, cmd_size, &cmd_rc); if (rc < 0) break; if (cmd_rc < 0) { rc = cmd_rc; break; } - memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length); + + /* out_buf should be valid, copy it into our output buffer */ + memcpy(buf + buf_offset, cmd->out_buf, cmd->in_length); } - dev_dbg(ndd->dev, "len: %zu rc: %d\n", offset, rc); - kfree(cmd); + kvfree(cmd); return rc; } @@ -151,15 +143,11 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, 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); + max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer); + cmd = kvzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL); if (!cmd) return -ENOMEM; @@ -183,7 +171,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, break; } } - kfree(cmd); + kvfree(cmd); return rc; } |