aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2017-11-08 19:59:15 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-11-20 20:35:24 -0600
commit6c83380260ce318a07b209d44df55cac3e0b912f (patch)
tree3e6002a7959e9ad49db28a88576d3178fa250fe4
parent1163d716518cb0b8c53c7648af53723116f7d392 (diff)
downloadskiboot-6c83380260ce318a07b209d44df55cac3e0b912f.zip
skiboot-6c83380260ce318a07b209d44df55cac3e0b912f.tar.gz
skiboot-6c83380260ce318a07b209d44df55cac3e0b912f.tar.bz2
gard: create: Allow creating arbitrary GARD records
Add a new sub-command that allows us to create GARD records for arbitrary chip units. There isn't a whole lot of constraints on this and that limits how useful it can be, but it does allow a user to GARD out individual DIMMs, chips or cores from the BMC (or host) if needed. There are a few caveats though: 1) Not everything can, or should, have a GARD record applied it to. 2) There is no validation that the unit actually exists. Doing that sort of validation requires something that understands the FAPI targeting information (I think) and adding support for it here would require some knowledge from the system XML file. 3) There's no way to get a list of paths in the system. 4) Although we can create a GARD record at runtime it won't be applied until the next IPL. Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--external/gard/gard.c79
-rw-r--r--external/gard/test/results/02-usage.err1
2 files changed, 76 insertions, 4 deletions
diff --git a/external/gard/gard.c b/external/gard/gard.c
index 108ee67..1ee54e6 100644
--- a/external/gard/gard.c
+++ b/external/gard/gard.c
@@ -25,6 +25,7 @@
#include <dirent.h>
#include <limits.h>
#include <inttypes.h>
+#include <ctype.h>
#include <ccan/array_size/array_size.h>
@@ -175,7 +176,7 @@ static int str_to_target_type(const char *path)
for (i = 0; i < chip_unit_count; i++) {
len = strlen(chip_units[i].desc);
- if (!strncmp(chip_units[i].desc, path, len))
+ if (!strncasecmp(chip_units[i].desc, path, len))
return chip_units[i].type; /* match! */
}
@@ -268,6 +269,7 @@ int parse_path(const char *str, struct entity_path *parsed)
int unit_id = str_to_target_type(++str); /* ++ skips the '/' */
long instance;
char *end;
+ size_t len;
if (unit_count > MAX_PATH_ELEMENTS - 1) {
fprintf(stderr, "Path has more than 10 components!\n");
@@ -283,8 +285,14 @@ int parse_path(const char *str, struct entity_path *parsed)
parsed->path_elements[unit_count].target_type = unit_id;
/* now parse the instance # */
- str += strlen(chip_units[unit_id].desc);
- instance = strtol(str, &end, 10);
+ len = strlen(chip_units[unit_id].desc);
+ instance = strtol(str + len, &end, 10);
+
+ if (!isdigit(*(str + len))) {
+ fprintf(stderr, "Missing instance number after '%s'\n",
+ str);
+ return -1;
+ }
if (*end != '\0' && *end != '/') {
fprintf(stderr, "Unable to parse instance after '%s'\n",
@@ -294,7 +302,7 @@ int parse_path(const char *str, struct entity_path *parsed)
if (instance > 15 || instance < 0) {
fprintf(stderr,
- "Instance %ld out of range should be 0 to 15\n",
+ "Instance %ld is invalid. Must be 0 to 15\n",
instance);
return -1;
}
@@ -613,6 +621,68 @@ static int do_clear(struct gard_ctx *ctx, int argc, char **argv)
return rc;
}
+static int do_create(struct gard_ctx *ctx, int argc, char **argv)
+{
+ int rc, pos, max_id = 0, last_pos = 0;
+ struct gard_record gard;
+ struct entity_path path;
+
+ if (argc < 2) {
+ fprintf(stderr, "create requires path to gard\n");
+ fprintf(stderr, "e.g.\n");
+ fprintf(stderr, " /Sys0/Node0/Proc0\n");
+ fprintf(stderr, " /Sys0/Node0/DIMM15\n");
+ return 0;
+ }
+
+ if (parse_path(argv[1], &path)) {
+ fprintf(stderr, "Unable to parse path\n");
+ return 0;
+ }
+
+ /* check if we already have a gard record applied to this path */
+ for_each_gard(ctx, pos, &gard, &rc) {
+ if (!memcmp(&path, &gard.target_id, sizeof(path))) {
+ fprintf(stderr,
+ "Unit %s is already GARDed by record %#08x\n",
+ argv[1], be32toh(gard.record_id));
+ return 0;
+ }
+
+ /*
+ * Keep track of the largest record ID seen so far,
+ * we'll give the new record the max + 1 to ensure
+ * that it's unique
+ */
+ if (be32toh(gard.record_id) > max_id)
+ max_id = be32toh(gard.record_id);
+
+ last_pos++;
+ }
+
+ /* do we have an empty record to write into? */
+ if (!rc && !is_valid_record(&gard)) {
+ int offset = last_pos * sizeof_gard(ctx);
+
+ memset(&gard, 0xff, sizeof(gard));
+
+ gard.record_id = be32toh(max_id + 1);
+ gard.error_type = GARD_MANUAL;
+ gard.target_id = path;
+ gard.errlog_eid = 0x0;
+
+ if (offset > ctx->gard_data_len - sizeof(gard)) {
+ fprintf(stderr, "No space in GUARD for a new record\n");
+ return 0;
+ }
+
+ rc = blocklevel_smart_write(ctx->bl,
+ ctx->gard_data_pos + offset, &gard, sizeof(gard));
+ }
+
+ return rc;
+}
+
static int check_gard_partition(struct gard_ctx *ctx)
{
int rc;
@@ -670,6 +740,7 @@ struct {
{ "list", "List current GARD records", do_list },
{ "show", "Show details of a GARD record", do_show },
{ "clear", "Clear GARD records", do_clear },
+ { "create", "Create a GARD record", do_create },
};
static void print_version(void)
diff --git a/external/gard/test/results/02-usage.err b/external/gard/test/results/02-usage.err
index ba3dc68..356625b 100644
--- a/external/gard/test/results/02-usage.err
+++ b/external/gard/test/results/02-usage.err
@@ -20,3 +20,4 @@ Where <command> is one of:
list List current GARD records
show Show details of a GARD record
clear Clear GARD records
+ create Create a GARD record