[PATCH 17/21] nd: write pmem label set

2015-04-17 Thread Dan Williams
After 'uuid', 'size', and optionally 'alt_name' have been set to valid
values the labels on the dimms can be updated.

Write procedure is:
1/ Allocate and write new labels in the "next" index
2/ Free the old labels in the working copy
3/ Write the bitmap and the label space on the dimm
4/ Write the index to make the update valid

Label ranges directly mirror the dpa resource values for the given
label_id of the namespace.

Signed-off-by: Dan Williams 
---
 drivers/block/nd/dimm_devs.c  |   49 ++
 drivers/block/nd/label.c  |  327 +
 drivers/block/nd/label.h  |6 +
 drivers/block/nd/namespace_devs.c |   82 -
 drivers/block/nd/nd.h |3 
 5 files changed, 453 insertions(+), 14 deletions(-)

diff --git a/drivers/block/nd/dimm_devs.c b/drivers/block/nd/dimm_devs.c
index ae77bf4a5188..a1685c01a2bb 100644
--- a/drivers/block/nd/dimm_devs.c
+++ b/drivers/block/nd/dimm_devs.c
@@ -134,6 +134,55 @@ int nd_dimm_init_config_data(struct nd_dimm_drvdata *ndd)
return rc;
 }
 
+int nd_dimm_set_config_data(struct nd_dimm_drvdata *ndd, size_t offset,
+   void *buf, size_t len)
+{
+   int rc = validate_dimm(ndd);
+   size_t max_cmd_size, buf_offset;
+   struct nfit_cmd_set_config_hdr *cmd;
+   struct nd_bus *nd_bus = walk_to_nd_bus(ndd->dev);
+   struct nfit_bus_descriptor *nfit_desc = nd_bus->nfit_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 = nfit_desc->nfit_ctl(nfit_desc, to_nd_dimm(ndd->dev),
+   NFIT_CMD_SET_CONFIG_DATA, cmd, cmd_size);
+   if (rc || *status) {
+   rc = rc ? rc : -ENXIO;
+   break;
+   }
+   }
+   kfree(cmd);
+
+   return rc;
+}
+
 static void nd_dimm_release(struct device *dev)
 {
struct nd_dimm *nd_dimm = to_nd_dimm(dev);
diff --git a/drivers/block/nd/label.c b/drivers/block/nd/label.c
index b55fa2a6f872..78898b642191 100644
--- a/drivers/block/nd/label.c
+++ b/drivers/block/nd/label.c
@@ -12,6 +12,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include "nd-private.h"
@@ -57,6 +58,11 @@ size_t sizeof_namespace_index(struct nd_dimm_drvdata *ndd)
return ndd->nsindex_size;
 }
 
+static int nd_dimm_num_label_slots(struct nd_dimm_drvdata *ndd)
+{
+   return ndd->nsarea.config_size / 129;
+}
+
 int nd_label_validate(struct nd_dimm_drvdata *ndd)
 {
/*
@@ -202,23 +208,30 @@ static struct nd_namespace_label __iomem 
*nd_label_base(struct nd_dimm_drvdata *
return base + 2 * sizeof_namespace_index(ndd);
 }
 
+static int to_slot(struct nd_dimm_drvdata *ndd,
+   struct nd_namespace_label __iomem *nd_label)
+{
+   return nd_label - nd_label_base(ndd);
+}
+
 #define for_each_clear_bit_le(bit, addr, size) \
for ((bit) = find_next_zero_bit_le((addr), (size), 0);  \
 (bit) < (size);\
 (bit) = find_next_zero_bit_le((addr), (size), (bit) + 1))
 
 /**
- * preamble_current - common variable initialization for nd_label_* routines
+ * preamble_index - common variable initialization for nd_label_* routines
  * @nd_dimm: dimm container for the relevant label set
+ * @idx: namespace_index index
  * @nsindex: on return set to the currently active namespace index
  * @free: on return set to the free label bitmap in the index
  * @nslot: on return set to the number of slots in the label space
  */
-static bool preamble_current(struct nd_dimm_drvdata *ndd,
+static bool preamble_index(struct nd_dimm_drvdata *ndd, int idx,
struct nd_namespace_index **nsindex,
unsigned long **free, u32 *nslot)
 {
-   *nsindex = to_current_namespace_index(ndd);
+   *nsindex = to_namespace_index(ndd, idx);
if (*nsindex == NULL)
return false;
 
@@ -237,6 +250,22 @@ char *nd_label_gen_id(struct nd_label_id *label_id, u8 
*uuid, u32 flags)

[PATCH 17/21] nd: write pmem label set

2015-04-17 Thread Dan Williams
After 'uuid', 'size', and optionally 'alt_name' have been set to valid
values the labels on the dimms can be updated.

Write procedure is:
1/ Allocate and write new labels in the next index
2/ Free the old labels in the working copy
3/ Write the bitmap and the label space on the dimm
4/ Write the index to make the update valid

Label ranges directly mirror the dpa resource values for the given
label_id of the namespace.

Signed-off-by: Dan Williams dan.j.willi...@intel.com
---
 drivers/block/nd/dimm_devs.c  |   49 ++
 drivers/block/nd/label.c  |  327 +
 drivers/block/nd/label.h  |6 +
 drivers/block/nd/namespace_devs.c |   82 -
 drivers/block/nd/nd.h |3 
 5 files changed, 453 insertions(+), 14 deletions(-)

diff --git a/drivers/block/nd/dimm_devs.c b/drivers/block/nd/dimm_devs.c
index ae77bf4a5188..a1685c01a2bb 100644
--- a/drivers/block/nd/dimm_devs.c
+++ b/drivers/block/nd/dimm_devs.c
@@ -134,6 +134,55 @@ int nd_dimm_init_config_data(struct nd_dimm_drvdata *ndd)
return rc;
 }
 
+int nd_dimm_set_config_data(struct nd_dimm_drvdata *ndd, size_t offset,
+   void *buf, size_t len)
+{
+   int rc = validate_dimm(ndd);
+   size_t max_cmd_size, buf_offset;
+   struct nfit_cmd_set_config_hdr *cmd;
+   struct nd_bus *nd_bus = walk_to_nd_bus(ndd-dev);
+   struct nfit_bus_descriptor *nfit_desc = nd_bus-nfit_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 = nfit_desc-nfit_ctl(nfit_desc, to_nd_dimm(ndd-dev),
+   NFIT_CMD_SET_CONFIG_DATA, cmd, cmd_size);
+   if (rc || *status) {
+   rc = rc ? rc : -ENXIO;
+   break;
+   }
+   }
+   kfree(cmd);
+
+   return rc;
+}
+
 static void nd_dimm_release(struct device *dev)
 {
struct nd_dimm *nd_dimm = to_nd_dimm(dev);
diff --git a/drivers/block/nd/label.c b/drivers/block/nd/label.c
index b55fa2a6f872..78898b642191 100644
--- a/drivers/block/nd/label.c
+++ b/drivers/block/nd/label.c
@@ -12,6 +12,7 @@
  */
 #include linux/device.h
 #include linux/ndctl.h
+#include linux/slab.h
 #include linux/io.h
 #include linux/nd.h
 #include nd-private.h
@@ -57,6 +58,11 @@ size_t sizeof_namespace_index(struct nd_dimm_drvdata *ndd)
return ndd-nsindex_size;
 }
 
+static int nd_dimm_num_label_slots(struct nd_dimm_drvdata *ndd)
+{
+   return ndd-nsarea.config_size / 129;
+}
+
 int nd_label_validate(struct nd_dimm_drvdata *ndd)
 {
/*
@@ -202,23 +208,30 @@ static struct nd_namespace_label __iomem 
*nd_label_base(struct nd_dimm_drvdata *
return base + 2 * sizeof_namespace_index(ndd);
 }
 
+static int to_slot(struct nd_dimm_drvdata *ndd,
+   struct nd_namespace_label __iomem *nd_label)
+{
+   return nd_label - nd_label_base(ndd);
+}
+
 #define for_each_clear_bit_le(bit, addr, size) \
for ((bit) = find_next_zero_bit_le((addr), (size), 0);  \
 (bit)  (size);\
 (bit) = find_next_zero_bit_le((addr), (size), (bit) + 1))
 
 /**
- * preamble_current - common variable initialization for nd_label_* routines
+ * preamble_index - common variable initialization for nd_label_* routines
  * @nd_dimm: dimm container for the relevant label set
+ * @idx: namespace_index index
  * @nsindex: on return set to the currently active namespace index
  * @free: on return set to the free label bitmap in the index
  * @nslot: on return set to the number of slots in the label space
  */
-static bool preamble_current(struct nd_dimm_drvdata *ndd,
+static bool preamble_index(struct nd_dimm_drvdata *ndd, int idx,
struct nd_namespace_index **nsindex,
unsigned long **free, u32 *nslot)
 {
-   *nsindex = to_current_namespace_index(ndd);
+   *nsindex = to_namespace_index(ndd, idx);
if (*nsindex == NULL)
return false;
 
@@ -237,6 +250,22 @@ char