diff mbox

[ndctl,4/5] Make interfaces to use Translate SPA.

Message ID 20170831102908.DA3B.E1E9C6FF@jp.fujitsu.com (mailing list archive)
State New, archived
Headers show

Commit Message

Gotou, Yasunori/五島 康文 Aug. 31, 2017, 1:29 a.m. UTC
This patch makes 2 new interfaces :
  - Call translate SPA featture of ACPI 6.2.
  - Find DIMM which SPA(System Physical Address) belongs to.


Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
---
 ndctl/Makefile.am         |   1 +
 ndctl/lib/Makefile.am     |   4 +-
 ndctl/lib/libndctl-nfit.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++
 ndctl/lib/libndctl-nfit.h |   5 ++
 4 files changed, 156 insertions(+), 1 deletion(-)

Comments

Dan Williams Aug. 31, 2017, 4:32 a.m. UTC | #1
Looks good in general...

Add "ndctl:" to the subject.

On Wed, Aug 30, 2017 at 6:29 PM, Yasunori Goto <y-goto@jp.fujitsu.com> wrote:
>
> This patch makes 2 new interfaces :
>   - Call translate SPA featture of ACPI 6.2.
>   - Find DIMM which SPA(System Physical Address) belongs to.
>
>
> Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
> ---
>  ndctl/Makefile.am         |   1 +
>  ndctl/lib/Makefile.am     |   4 +-
>  ndctl/lib/libndctl-nfit.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++

Rename this to ndctl/lib/nfit.c, I pushed out a large rename of other
files to drop the "libdctl-" prefix to the 'pending' branch on github.

>  ndctl/lib/libndctl-nfit.h |   5 ++
>  4 files changed, 156 insertions(+), 1 deletion(-)
>
> diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
> index d346c04..20d5f59 100644
> --- a/ndctl/Makefile.am
> +++ b/ndctl/Makefile.am
> @@ -25,6 +25,7 @@ endif
>
>  ndctl_LDADD =\
>         lib/libndctl.la \
> +       lib/libndctl-nfit.la \

Let's just add these symbols to the existing libndctl.so rather than
add a new one.

>         ../daxctl/lib/libdaxctl.la \
>         ../libutil.a \
>         $(UUID_LIBS) \
> diff --git a/ndctl/lib/Makefile.am b/ndctl/lib/Makefile.am
> index 7a446be..cfa54ae 100644
> --- a/ndctl/lib/Makefile.am
> +++ b/ndctl/lib/Makefile.am
> @@ -8,7 +8,7 @@ BUILT_SOURCES = ../libndctl.h
>         $(SED_PROCESS)
>
>  pkginclude_HEADERS = ../libndctl.h
> -lib_LTLIBRARIES = libndctl.la
> +lib_LTLIBRARIES = libndctl.la libndctl-nfit.la
>
>  libndctl_la_SOURCES =\
>         libndctl.h \
> @@ -35,6 +35,8 @@ libndctl_la_SOURCES += libndctl-hpe1.c
>  libndctl_la_SOURCES += libndctl-msft.c
>  endif
>
> +libndctl_nfit_la_SOURCES = libndctl-nfit.c
> +
>  EXTRA_DIST += libndctl.sym
>
>  libndctl_la_LDFLAGS = $(AM_LDFLAGS) \
> diff --git a/ndctl/lib/libndctl-nfit.c b/ndctl/lib/libndctl-nfit.c
> new file mode 100644
> index 0000000..455815d
> --- /dev/null
> +++ b/ndctl/lib/libndctl-nfit.c
> @@ -0,0 +1,147 @@
> +/*
> + * Copyright (c) 2017, FUJITSU LIMITED. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU Lesser General Public License,
> + * version 2.1, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT ANY
> + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
> + * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
> + * more details.
> + */
> +#include <stdlib.h>
> +#include <ndctl/libndctl.h>
> +#include "libndctl-private.h"
> +#include "libndctl-nfit.h"
> +
> +static int bus_has_translate_spa(struct ndctl_bus *bus)
> +{
> +       if (!ndctl_bus_has_nfit(bus))
> +               return 0;
> +
> +       return ndctl_bus_is_passthru_cmd_supported(bus, NFIT_CMD_TRANSLATE_SPA);
> +}
> +
> +static struct ndctl_cmd *ndctl_bus_cmd_new_translate_spa(struct ndctl_bus *bus)
> +{
> +       struct ndctl_cmd *cmd;
> +       struct nd_cmd_pkg *pkg;
> +       struct nd_cmd_translate_spa *translate_spa;
> +       size_t size, spa_length;
> +
> +       spa_length = sizeof(struct nd_cmd_translate_spa)
> +               + sizeof(struct nd_nvdimm_device);
> +       size = sizeof(*cmd) + sizeof(*pkg) + spa_length;
> +       cmd = calloc(1, size);
> +       if (!cmd)
> +               return NULL;
> +
> +       cmd->bus = bus;
> +       ndctl_cmd_ref(cmd);
> +       cmd->type = ND_CMD_CALL;
> +       cmd->size = size;
> +       cmd->status = 1;
> +       pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
> +       pkg->nd_command = NFIT_CMD_TRANSLATE_SPA;
> +       pkg->nd_size_in = sizeof(unsigned long long);
> +       pkg->nd_size_out = spa_length;
> +       pkg->nd_fw_size = spa_length;
> +       translate_spa = (struct nd_cmd_translate_spa *)&pkg->nd_payload[0];
> +       cmd->firmware_status = &translate_spa->status;
> +       translate_spa->translate_length = spa_length;
> +
> +       return cmd;
> +}
> +
> +static int ndctl_bus_cmd_get_translate_spa(struct ndctl_cmd *cmd,
> +                                       unsigned int *handle, unsigned long long *dpa)
> +{
> +       struct nd_cmd_pkg *pkg;
> +       struct nd_cmd_translate_spa *translate_spa;
> +
> +       pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
> +       translate_spa = (struct nd_cmd_translate_spa *)&pkg->nd_payload[0];
> +
> +       if (translate_spa->status == ND_TRANSLATE_SPA_STATUS_INVALID_SPA)
> +               return -EINVAL;
> +
> +       /*
> +        * XXX: Currently NVDIMM mirroring is not supported.
> +        * Even if ACPI returned plural dimms due to mirroring,
> +        * this function returns just the first dimm.
> +        */
> +
> +       *handle = translate_spa->devices[0].nfit_device_handle;
> +       *dpa = translate_spa->devices[0].dpa;
> +
> +       return 0;
> +}
> +
> +static int is_valid_spa(struct ndctl_bus *bus, unsigned long long spa)
> +{
> +       struct ndctl_region *region;
> +       unsigned long long region_start, region_end;
> +
> +       ndctl_region_foreach(bus, region) {
> +               region_start = ndctl_region_get_resource(region);
> +               region_end = region_start + ndctl_region_get_size(region);
> +               if (region_start <= spa && spa < region_end)
> +                       return 1;
> +       }
> +
> +       return 0;
> +}
> +
> +NDCTL_EXPORT int ndctl_bus_cmd_translate_spa(struct ndctl_bus *bus,
> +       unsigned long long addr, unsigned int *handle, unsigned long long *dpa)
> +{
> +
> +       struct ndctl_cmd *cmd;
> +       struct nd_cmd_pkg *pkg;
> +       struct nd_cmd_translate_spa *translate_spa;
> +       int rc;
> +
> +       if (!bus || !handle || !dpa)
> +               return -EINVAL;
> +
> +       if (!bus_has_translate_spa(bus))
> +               return -ENOTTY;
> +
> +       if (!is_valid_spa(bus, addr))
> +               return -EINVAL;
> +
> +       cmd = ndctl_bus_cmd_new_translate_spa(bus);
> +       if (!cmd)
> +               return -ENOMEM;
> +
> +       pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
> +       translate_spa = (struct nd_cmd_translate_spa *)&pkg->nd_payload[0];
> +       translate_spa->spa = addr;
> +
> +       rc = ndctl_cmd_submit(cmd);
> +       if (rc) {
> +               ndctl_cmd_unref(cmd);
> +               return rc;
> +       }
> +
> +       rc = ndctl_bus_cmd_get_translate_spa(cmd, handle, dpa);
> +       ndctl_cmd_unref(cmd);
> +
> +       return rc;
> +}
> +
> +NDCTL_EXPORT struct ndctl_dimm *ndctl_dimm_get_by_spa(struct ndctl_bus *bus,
> +               unsigned long long spa)
> +{
> +       int rc;
> +       unsigned int handle;
> +       unsigned long long dpa;
> +
> +       /* ndctl_bus_cmd_translate_spa() has sanity check */
> +       rc = ndctl_bus_cmd_translate_spa(bus, spa, &handle, &dpa);
> +       if (rc)
> +               return NULL;
> +
> +       return ndctl_dimm_get_by_handle(bus, handle);
> +}

Let's move this out of nfit.c and make it generic in libndctl.c

    ndctl_dimm_get_by_physical_address()

...where the common case of a single DIMM can be handled without
calling any DSMs. But if it is an interleave-set we can check for
ndctl_bus_has_nfit() before trying to call the nfit specific
ndctl_bus_nfit_cmd_translate_spa().
diff mbox

Patch

diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index d346c04..20d5f59 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -25,6 +25,7 @@  endif
 
 ndctl_LDADD =\
 	lib/libndctl.la \
+	lib/libndctl-nfit.la \
 	../daxctl/lib/libdaxctl.la \
 	../libutil.a \
 	$(UUID_LIBS) \
diff --git a/ndctl/lib/Makefile.am b/ndctl/lib/Makefile.am
index 7a446be..cfa54ae 100644
--- a/ndctl/lib/Makefile.am
+++ b/ndctl/lib/Makefile.am
@@ -8,7 +8,7 @@  BUILT_SOURCES = ../libndctl.h
 	$(SED_PROCESS)
 
 pkginclude_HEADERS = ../libndctl.h
-lib_LTLIBRARIES = libndctl.la
+lib_LTLIBRARIES = libndctl.la libndctl-nfit.la
 
 libndctl_la_SOURCES =\
 	libndctl.h \
@@ -35,6 +35,8 @@  libndctl_la_SOURCES += libndctl-hpe1.c
 libndctl_la_SOURCES += libndctl-msft.c
 endif
 
+libndctl_nfit_la_SOURCES = libndctl-nfit.c
+
 EXTRA_DIST += libndctl.sym
 
 libndctl_la_LDFLAGS = $(AM_LDFLAGS) \
diff --git a/ndctl/lib/libndctl-nfit.c b/ndctl/lib/libndctl-nfit.c
new file mode 100644
index 0000000..455815d
--- /dev/null
+++ b/ndctl/lib/libndctl-nfit.c
@@ -0,0 +1,147 @@ 
+/*
+ * Copyright (c) 2017, FUJITSU LIMITED. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+#include <stdlib.h>
+#include <ndctl/libndctl.h>
+#include "libndctl-private.h"
+#include "libndctl-nfit.h"
+
+static int bus_has_translate_spa(struct ndctl_bus *bus)
+{
+	if (!ndctl_bus_has_nfit(bus))
+		return 0;
+
+	return ndctl_bus_is_passthru_cmd_supported(bus, NFIT_CMD_TRANSLATE_SPA);
+}
+
+static struct ndctl_cmd *ndctl_bus_cmd_new_translate_spa(struct ndctl_bus *bus)
+{
+	struct ndctl_cmd *cmd;
+	struct nd_cmd_pkg *pkg;
+	struct nd_cmd_translate_spa *translate_spa;
+	size_t size, spa_length;
+
+	spa_length = sizeof(struct nd_cmd_translate_spa)
+		+ sizeof(struct nd_nvdimm_device);
+	size = sizeof(*cmd) + sizeof(*pkg) + spa_length;
+	cmd = calloc(1, size);
+	if (!cmd)
+		return NULL;
+
+	cmd->bus = bus;
+	ndctl_cmd_ref(cmd);
+	cmd->type = ND_CMD_CALL;
+	cmd->size = size;
+	cmd->status = 1;
+	pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
+	pkg->nd_command = NFIT_CMD_TRANSLATE_SPA;
+	pkg->nd_size_in = sizeof(unsigned long long);
+	pkg->nd_size_out = spa_length;
+	pkg->nd_fw_size = spa_length;
+	translate_spa = (struct nd_cmd_translate_spa *)&pkg->nd_payload[0];
+	cmd->firmware_status = &translate_spa->status;
+	translate_spa->translate_length = spa_length;
+
+	return cmd;
+}
+
+static int ndctl_bus_cmd_get_translate_spa(struct ndctl_cmd *cmd,
+					unsigned int *handle, unsigned long long *dpa)
+{
+	struct nd_cmd_pkg *pkg;
+	struct nd_cmd_translate_spa *translate_spa;
+
+	pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
+	translate_spa = (struct nd_cmd_translate_spa *)&pkg->nd_payload[0];
+
+	if (translate_spa->status == ND_TRANSLATE_SPA_STATUS_INVALID_SPA)
+		return -EINVAL;
+
+	/*
+	 * XXX: Currently NVDIMM mirroring is not supported.
+	 * Even if ACPI returned plural dimms due to mirroring,
+	 * this function returns just the first dimm.
+	 */
+
+	*handle = translate_spa->devices[0].nfit_device_handle;
+	*dpa = translate_spa->devices[0].dpa;
+
+	return 0;
+}
+
+static int is_valid_spa(struct ndctl_bus *bus, unsigned long long spa)
+{
+	struct ndctl_region *region;
+	unsigned long long region_start, region_end;
+
+	ndctl_region_foreach(bus, region) {
+		region_start = ndctl_region_get_resource(region);
+		region_end = region_start + ndctl_region_get_size(region);
+		if (region_start <= spa && spa < region_end)
+			return 1;
+	}
+
+	return 0;
+}
+
+NDCTL_EXPORT int ndctl_bus_cmd_translate_spa(struct ndctl_bus *bus,
+	unsigned long long addr, unsigned int *handle, unsigned long long *dpa)
+{
+
+	struct ndctl_cmd *cmd;
+	struct nd_cmd_pkg *pkg;
+	struct nd_cmd_translate_spa *translate_spa;
+	int rc;
+
+	if (!bus || !handle || !dpa)
+		return -EINVAL;
+
+	if (!bus_has_translate_spa(bus))
+		return -ENOTTY;
+
+	if (!is_valid_spa(bus, addr))
+		return -EINVAL;
+
+	cmd = ndctl_bus_cmd_new_translate_spa(bus);
+	if (!cmd)
+		return -ENOMEM;
+
+	pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
+	translate_spa = (struct nd_cmd_translate_spa *)&pkg->nd_payload[0];
+	translate_spa->spa = addr;
+
+	rc = ndctl_cmd_submit(cmd);
+	if (rc) {
+		ndctl_cmd_unref(cmd);
+		return rc;
+	}
+
+	rc = ndctl_bus_cmd_get_translate_spa(cmd, handle, dpa);
+	ndctl_cmd_unref(cmd);
+
+	return rc;
+}
+
+NDCTL_EXPORT struct ndctl_dimm *ndctl_dimm_get_by_spa(struct ndctl_bus *bus,
+		unsigned long long spa)
+{
+	int rc;
+	unsigned int handle;
+	unsigned long long dpa;
+
+	/* ndctl_bus_cmd_translate_spa() has sanity check */
+	rc = ndctl_bus_cmd_translate_spa(bus, spa, &handle, &dpa);
+	if (rc)
+		return NULL;
+
+	return ndctl_dimm_get_by_handle(bus, handle);
+}
diff --git a/ndctl/lib/libndctl-nfit.h b/ndctl/lib/libndctl-nfit.h
index 1398662..4a1dac6 100644
--- a/ndctl/lib/libndctl-nfit.h
+++ b/ndctl/lib/libndctl-nfit.h
@@ -58,4 +58,9 @@  struct nd_cmd_ars_err_inj_stat {
 	} __attribute__((packed)) record[0];
 } __attribute__((packed));
 
+int ndctl_bus_cmd_translate_spa(struct ndctl_bus *bus,
+	unsigned long long addr, unsigned int *handle, unsigned long long *dpa);
+struct ndctl_dimm *ndctl_dimm_get_by_spa(struct ndctl_bus *bus,
+	unsigned long long spa);
+
 #endif /* __LIBNDCTL_NFIT_H__ */