Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /*
3 : : * Manipulate GARD records in the GARD partition
4 : : *
5 : : * Copyright 2013-2019 IBM Corp.
6 : : */
7 : :
8 : : #include <fcntl.h>
9 : : #include <stdio.h>
10 : : #include <stdlib.h>
11 : : #include <errno.h>
12 : : #include <string.h>
13 : : #include <unistd.h>
14 : : #include <sys/mman.h>
15 : : #include <sys/stat.h>
16 : : #include <dirent.h>
17 : : #include <limits.h>
18 : : #include <inttypes.h>
19 : : #include <ctype.h>
20 : :
21 : : #include <ccan/array_size/array_size.h>
22 : :
23 : : #include <mtd/mtd-abi.h>
24 : :
25 : : #include <getopt.h>
26 : :
27 : : #include <libflash/libflash.h>
28 : : #include <libflash/libffs.h>
29 : : #include <libflash/file.h>
30 : : #include <libflash/blocklevel.h>
31 : : #include <common/arch_flash.h>
32 : :
33 : : #include "gard.h"
34 : :
35 : : #define FDT_PATH "/proc/device-tree"
36 : : #define FDT_FSP_NODE FDT_PATH"/fsps"
37 : : #define FDT_ACTIVE_FLASH_PATH FDT_PATH"/chosen/ibm,system-flash"
38 : : #define SYSFS_MTD_PATH "/sys/class/mtd/"
39 : : #define FLASH_GARD_PART "GUARD"
40 : :
41 : : #define VPNOR_GARD_DIR "/media/pnor-prsv"
42 : : #define VPNOR_GARD_FILE VPNOR_GARD_DIR"/GUARD"
43 : :
44 : : /* Full gard version number (possibly includes gitid). */
45 : : extern const char version[];
46 : :
47 : :
48 : : #define __unused __attribute__((unused))
49 : :
50 : : struct gard_ctx {
51 : : uint32_t f_size;
52 : : uint32_t f_pos;
53 : :
54 : : uint32_t gard_part_idx;
55 : : uint32_t gard_data_pos;
56 : : uint32_t gard_data_len;
57 : :
58 : : struct blocklevel_device *bl;
59 : : struct ffs_handle *ffs;
60 : : };
61 : :
62 : 0 : static void show_flash_err(int rc)
63 : : {
64 : 0 : switch (rc) {
65 : 0 : case FFS_ERR_BAD_MAGIC:
66 : 0 : fprintf(stderr, "libffs bad magic\n");
67 : : break;
68 : 0 : case FFS_ERR_BAD_VERSION:
69 : 0 : fprintf(stderr, "libffs bad version\n");
70 : : break;
71 : 0 : case FFS_ERR_BAD_CKSUM:
72 : 0 : fprintf(stderr, "libffs bad check sum\n");
73 : : break;
74 : 0 : case FFS_ERR_PART_NOT_FOUND:
75 : 0 : fprintf(stderr, "libffs flash partition not found\n");
76 : : break;
77 : : /* ------- */
78 : 0 : case FLASH_ERR_MALLOC_FAILED:
79 : 0 : fprintf(stderr, "libflash malloc failed\n");
80 : : break;
81 : 0 : case FLASH_ERR_CHIP_UNKNOWN:
82 : 0 : fprintf(stderr, "libflash unknown flash chip\n");
83 : : break;
84 : 0 : case FLASH_ERR_PARM_ERROR:
85 : 0 : fprintf(stderr, "libflash parameter error\n");
86 : : break;
87 : 0 : case FLASH_ERR_ERASE_BOUNDARY:
88 : 0 : fprintf(stderr, "libflash erase boundary error\n");
89 : : break;
90 : 0 : case FLASH_ERR_WREN_TIMEOUT:
91 : 0 : fprintf(stderr, "libflash WREN timeout\n");
92 : : break;
93 : 0 : case FLASH_ERR_WIP_TIMEOUT:
94 : 0 : fprintf(stderr, "libflash WIP timeout\n");
95 : : break;
96 : 0 : case FLASH_ERR_VERIFY_FAILURE:
97 : 0 : fprintf(stderr, "libflash verification failure\n");
98 : : break;
99 : 0 : case FLASH_ERR_4B_NOT_SUPPORTED:
100 : 0 : fprintf(stderr, "libflash 4byte mode not supported\n");
101 : : break;
102 : 0 : case FLASH_ERR_CTRL_CONFIG_MISMATCH:
103 : 0 : fprintf(stderr, "libflash control config mismatch\n");
104 : : break;
105 : 0 : case FLASH_ERR_CHIP_ER_NOT_SUPPORTED:
106 : 0 : fprintf(stderr, "libflash chip not supported\n");
107 : : break;
108 : 0 : case FLASH_ERR_CTRL_CMD_UNSUPPORTED:
109 : 0 : fprintf(stderr, "libflash unsupported control command\n");
110 : : break;
111 : 0 : case FLASH_ERR_CTRL_TIMEOUT:
112 : 0 : fprintf(stderr, "libflash control timeout\n");
113 : : break;
114 : 0 : case FLASH_ERR_ECC_INVALID:
115 : 0 : fprintf(stderr, "libflash ecc invalid\n");
116 : : break;
117 : 0 : default:
118 : 0 : fprintf(stderr, "A libflash/libffs error has occurred %d\n", rc);
119 : : }
120 : 0 : }
121 : :
122 : : const struct chip_unit_desc *chip_units;
123 : : int chip_unit_count;
124 : :
125 : 46 : static void set_chip_gen(const struct chip_unit_desc *c)
126 : : {
127 : 46 : chip_units = c;
128 : 46 : chip_unit_count = 0;
129 : :
130 : 3258 : while (strcmp("LAST_IN_RANGE", c->desc)) {
131 : 3212 : chip_unit_count++;
132 : 3212 : c++;
133 : : }
134 : 46 : }
135 : :
136 : : #ifdef __powerpc64__
137 : : static void guess_chip_gen(void)
138 : : {
139 : : /*
140 : : * Guesstimate what chip generation based on the PVR if we're running
141 : : * on ppc64.
142 : : */
143 : : uint32_t pvr;
144 : :
145 : : /* grab the chip type from the PVR SPR */
146 : : asm ("mfspr %0,0x11f" : "=r" (pvr));
147 : :
148 : : switch (pvr >> 16) {
149 : : case 0x004b: /* murano */
150 : : case 0x004c: /* naples */
151 : : case 0x004d: /* venice */
152 : : set_chip_gen(p8_chip_units);
153 : : return;
154 : :
155 : : case 0x004e: /* nimbus */
156 : : case 0x004f: /* axone */
157 : : set_chip_gen(p9_chip_units);
158 : : return;
159 : :
160 : : case 0x0080: /* power10 */
161 : : set_chip_gen(p10_chip_units);
162 : : return;
163 : :
164 : : default:
165 : : fprintf(stderr, "Unsupported processor (pvr %#x)! Set the processor generation manually with -8, -9 or -0\n", pvr);
166 : : exit(1);
167 : : }
168 : : }
169 : : #else
170 : 30 : static void guess_chip_gen(void)
171 : : {
172 : : #ifdef ASSUME_P8
173 : : set_chip_gen(p8_chip_units);
174 : : #else
175 : 30 : set_chip_gen(p9_chip_units);
176 : : #endif
177 : 30 : }
178 : : #endif
179 : :
180 : 194 : static const char *target_type_to_str(int type)
181 : : {
182 : 194 : int i;
183 : :
184 : 4658 : for (i = 0; i < chip_unit_count; i++)
185 : 4658 : if (chip_units[i].type == type)
186 : 194 : return chip_units[i].desc;
187 : :
188 : : return "UNKNOWN";
189 : : }
190 : :
191 : 72 : static int str_to_target_type(const char *path)
192 : : {
193 : 72 : int i, len;
194 : :
195 : 1826 : for (i = 0; i < chip_unit_count; i++) {
196 : 1822 : len = strlen(chip_units[i].desc);
197 : :
198 : 1822 : if (!strncasecmp(chip_units[i].desc, path, len))
199 : 68 : return chip_units[i].type; /* match! */
200 : : }
201 : :
202 : : return -1;
203 : : }
204 : :
205 : 18 : static const char *deconfig_reason_str(enum gard_reason reason)
206 : : {
207 : 18 : switch (reason) {
208 : : case GARD_NO_REASON:
209 : : return "None";
210 : 10 : case GARD_MANUAL:
211 : 10 : return "Manual";
212 : 0 : case GARD_UNRECOVERABLE:
213 : 0 : return "Unrecoverable";
214 : 2 : case GARD_FATAL:
215 : 2 : return "Fatal";
216 : 6 : case GARD_PREDICTIVE:
217 : 6 : return "Predictive";
218 : 0 : case GARD_POWER:
219 : 0 : return "Power"; // What does this even mean?
220 : 0 : case GARD_HYP:
221 : 0 : return "Hypervisor";
222 : 0 : case GARD_RECONFIG:
223 : 0 : return "Reconfig";
224 : 0 : default:
225 : 0 : return "Unknown";
226 : : }
227 : : };
228 : :
229 : 4 : static const char *path_type_to_str(enum path_type t)
230 : : {
231 : 4 : switch (t) {
232 : : case PATH_NA:
233 : : return "not applicable";
234 : 0 : case PATH_AFFINITY:
235 : 0 : return "affinity";
236 : 4 : case PATH_PHYSICAL:
237 : 4 : return "physical";
238 : 0 : case PATH_DEVICE:
239 : 0 : return "device";
240 : 0 : case PATH_POWER:
241 : 0 : return "power";
242 : : }
243 : 0 : return "Unknown";
244 : : }
245 : :
246 : : /*
247 : : * NB: buffer is assumped to be MAX_PATH_SIZE
248 : : */
249 : 28 : static char *format_path(struct entity_path *path, char *buffer)
250 : : {
251 : 28 : int elements = path->type_size & PATH_ELEMENTS_MASK;
252 : 28 : int i, offset = 0;
253 : :
254 : 140 : for (i = 0; i < elements; i++) {
255 : 112 : const struct path_element *e = &path->path_elements[i];
256 : :
257 : 112 : offset += sprintf(buffer + offset, "/%s%d",
258 : 112 : target_type_to_str(e->target_type),
259 : 112 : e->instance);
260 : : }
261 : :
262 : 28 : return buffer;
263 : : }
264 : :
265 : : /*
266 : : * parses a Path string into the entity_path structured provided.
267 : : *
268 : : * str - In param, String to parse
269 : : * parsed - Out param, resultant entity_path
270 : : *
271 : : * e.g.
272 : : *
273 : : * "/Sys0/Node0/Proc1" -> {
274 : : * type_size = 0x23,
275 : : *
276 : : * path_element[0] = {0, 0}
277 : : * path_element[1] = {1, 0}
278 : : * path_element[2] = {2, 1}
279 : : * }
280 : : */
281 : 18 : static int parse_path(const char *str, struct entity_path *parsed)
282 : : {
283 : 18 : int unit_count = 0;
284 : :
285 : 18 : memset(parsed, 0, sizeof(*parsed));
286 : :
287 : 82 : while (*str != '\0') {
288 : 72 : int unit_id = str_to_target_type(++str); /* ++ skips the '/' */
289 : 72 : long instance;
290 : 72 : char *end;
291 : 72 : size_t len;
292 : :
293 : 72 : if (unit_count > MAX_PATH_ELEMENTS - 1) {
294 : 2 : fprintf(stderr, "Path has more than 10 components!\n");
295 : 8 : return -1;
296 : : }
297 : :
298 : : /* find the type Id of this component */
299 : 70 : if (unit_id < 0) { /* unknown unit, bail out */
300 : 4 : fprintf(stderr, "Unknown unit at: '%s'\n", str);
301 : 4 : return -1;
302 : : }
303 : :
304 : 66 : parsed->path_elements[unit_count].target_type = unit_id;
305 : :
306 : : /* now parse the instance # */
307 : 66 : len = strlen(target_type_to_str(unit_id));
308 : 66 : instance = strtol(str + len, &end, 10);
309 : :
310 : 66 : if (!isdigit(*(str + len))) {
311 : 0 : fprintf(stderr, "Missing instance number after '%s'\n",
312 : : str);
313 : 0 : return -1;
314 : : }
315 : :
316 : 66 : if (*end != '\0' && *end != '/') {
317 : 0 : fprintf(stderr, "Unable to parse instance after '%s'\n",
318 : : str);
319 : 0 : return -1;
320 : : }
321 : :
322 : 66 : if (instance > 255 || instance < 0) {
323 : 2 : fprintf(stderr,
324 : : "Instance %ld is invalid. Must be 0 to 255\n",
325 : : instance);
326 : 2 : return -1;
327 : : }
328 : 64 : parsed->path_elements[unit_count].instance = instance;
329 : :
330 : 64 : str = end;
331 : 64 : unit_count++;
332 : : }
333 : :
334 : : /*
335 : : * We assume the path is a physical path because every gard record I've
336 : : * seen so far uses them. We might need to fix this later on, but lets
337 : : * cross the bridge when we have to.
338 : : */
339 : 10 : parsed->type_size = (unit_count & 0xf) |
340 : : (PATH_PHYSICAL << PATH_TYPE_SHIFT);
341 : :
342 : 10 : return 0;
343 : : }
344 : :
345 : : static struct gard_record blank_record;
346 : :
347 : 112 : static bool is_valid_record(struct gard_record *g)
348 : : {
349 : 112 : return memcmp(&blank_record, g, sizeof(*g));
350 : : }
351 : :
352 : 10 : static int do_iterate(struct gard_ctx *ctx,
353 : : int (*func)(struct gard_ctx *ctx, int pos,
354 : : struct gard_record *gard, void *priv),
355 : : void *priv)
356 : : {
357 : 10 : int rc = 0;
358 : 10 : unsigned int i;
359 : 10 : struct gard_record gard, null_gard;
360 : :
361 : 10 : memset(&null_gard, UINT_MAX, sizeof(gard));
362 : 22 : for (i = 0; i * sizeof(gard) < ctx->gard_data_len && rc == 0; i++) {
363 : 22 : memset(&gard, 0, sizeof(gard));
364 : :
365 : 22 : rc = blocklevel_read(ctx->bl, ctx->gard_data_pos + (i * sizeof(gard)),
366 : : &gard, sizeof(gard));
367 : : /* It isn't super clear what constitutes the end, this should do */
368 : 22 : if (rc || memcmp(&gard, &null_gard, sizeof(gard)) == 0)
369 : : break;
370 : :
371 : 12 : rc = func(ctx, i, &gard, priv);
372 : : }
373 : :
374 : 10 : return rc;
375 : : }
376 : :
377 : : /*
378 : : * read the next guard record into the supplied buffer (gard)
379 : : *
380 : : * returns the record id (nb: 1 based not zero)
381 : : *
382 : : */
383 : 104 : static int __gard_next(struct gard_ctx *ctx, int pos, struct gard_record *gard, int *rc)
384 : : {
385 : 104 : uint32_t offset = pos * sizeof(*gard);
386 : :
387 : 104 : if (offset > ctx->gard_data_len) /* too big */
388 : : return -1;
389 : :
390 : : /* you lose error handling information, *gruble* */
391 : 104 : memset(gard, 0, sizeof(*gard));
392 : 104 : *rc = blocklevel_read(ctx->bl, ctx->gard_data_pos + offset,
393 : : gard, sizeof(*gard));
394 : :
395 : 104 : if (!is_valid_record(gard))
396 : : return -1;
397 : :
398 : 56 : if (*rc)
399 : 0 : return -1;
400 : :
401 : : return pos;
402 : : }
403 : :
404 : : #define for_each_gard(ctx, pos, gard, rc) \
405 : : for (pos = __gard_next(ctx, 0, gard, rc); \
406 : : pos >= 0; pos = __gard_next(ctx, ++pos, gard, rc))
407 : :
408 : 6 : static int count_records(struct gard_ctx *ctx)
409 : : {
410 : 6 : struct gard_record record;
411 : 6 : int rc, pos, count = 0;
412 : :
413 : 14 : for_each_gard(ctx, pos, &record, &rc)
414 : 8 : count++;
415 : :
416 : 6 : return rc ? rc : count;
417 : : }
418 : :
419 : 14 : static int count_valid_records(struct gard_ctx *ctx)
420 : : {
421 : 14 : struct gard_record record;
422 : 14 : int rc, pos, count = 0;
423 : :
424 : 28 : for_each_gard(ctx, pos, &record, &rc)
425 : 14 : count++;
426 : :
427 : 14 : return rc ? rc : count;
428 : : }
429 : :
430 : 10 : static size_t find_longest_path(struct gard_ctx *ctx)
431 : : {
432 : 10 : char scratch[MAX_PATH_SIZE];
433 : 10 : struct gard_record gard;
434 : 10 : size_t len, longest = 0;
435 : 10 : int rc, pos;
436 : :
437 : 24 : for_each_gard(ctx, pos, &gard, &rc) {
438 : 14 : len = strlen(format_path(&gard.target_id, scratch));
439 : 14 : if (len > longest)
440 : : longest = len;
441 : : }
442 : :
443 : 10 : return longest;
444 : : }
445 : :
446 : 20 : static void draw_ruler(char c, int size)
447 : : {
448 : 20 : int i;
449 : :
450 : 1580 : for (i = 0; i < size; i++)
451 : 1560 : putchar(c);
452 : 20 : putchar('\n');
453 : 20 : }
454 : :
455 : 14 : static int do_list(struct gard_ctx *ctx, int argc __attribute__((unused)),
456 : : char **argv __attribute__((unused)))
457 : : {
458 : : /* This header matches the line formatting above in do_list_i() */
459 : 14 : const char *header = " ID | Error | Type | Path";
460 : 14 : size_t ruler_size;
461 : 14 : char scratch[MAX_PATH_SIZE];
462 : 14 : struct gard_record gard;
463 : 14 : int rc = 0, pos;
464 : :
465 : : /* No entries */
466 : 14 : if (count_valid_records(ctx) == 0) {
467 : 4 : printf("No GARD entries to display\n");
468 : 4 : return 0;
469 : : }
470 : :
471 : 10 : puts(header);
472 : :
473 : 10 : ruler_size = strlen(header) + find_longest_path(ctx);
474 : 10 : draw_ruler('-', ruler_size);
475 : :
476 : 24 : for_each_gard(ctx, pos, &gard, &rc) {
477 : 28 : printf(" %08x | %08x | %-10s | %s%s\n",
478 : : be32toh(gard.record_id),
479 : : be32toh(gard.errlog_eid),
480 : 14 : deconfig_reason_str(gard.error_type),
481 : : format_path(&gard.target_id, scratch),
482 : 14 : gard.record_id == 0xffffffff ? " *CLEARED*" : "");
483 : : }
484 : :
485 : 10 : draw_ruler('=', ruler_size);
486 : :
487 : 10 : return rc;
488 : : }
489 : :
490 : 6 : static int do_show_i(struct gard_ctx *ctx, int pos, struct gard_record *gard, void *priv)
491 : : {
492 : 6 : uint32_t id;
493 : :
494 : 6 : (void)ctx;
495 : 6 : (void)pos;
496 : :
497 : 6 : if (!priv || !gard)
498 : : return -1;
499 : :
500 : 6 : id = *(uint32_t *)priv;
501 : :
502 : 6 : if (be32toh(gard->record_id) == id) {
503 : 4 : unsigned int count, i;
504 : :
505 : 4 : printf("Record ID: 0x%08x%s\n", id, id == 0xffffffff ? " *CLEARED*" : "");
506 : 4 : printf("========================\n");
507 : 4 : printf("Error ID: 0x%08x\n", be32toh(gard->errlog_eid));
508 : 8 : printf("Error Type: %s (0x%02x)\n",
509 : : deconfig_reason_str(gard->error_type),
510 : 4 : gard->error_type);
511 : 4 : printf("Path Type: %s\n", path_type_to_str(gard->target_id.type_size >> PATH_TYPE_SHIFT));
512 : 4 : count = gard->target_id.type_size & PATH_ELEMENTS_MASK;
513 : 20 : for (i = 0; i < count && i < MAX_PATH_ELEMENTS; i++)
514 : 16 : printf("%*c%s, Instance #%d\n", i + 1, '>', target_type_to_str(gard->target_id.path_elements[i].target_type),
515 : 16 : gard->target_id.path_elements[i].instance);
516 : : }
517 : :
518 : : return 0;
519 : : }
520 : :
521 : 4 : static int do_show(struct gard_ctx *ctx, int argc, char **argv)
522 : : {
523 : 4 : uint32_t id;
524 : 4 : int rc;
525 : :
526 : 4 : if (argc != 2) {
527 : 0 : fprintf(stderr, "%s option requires a GARD record\n", argv[0]);
528 : 0 : return -1;
529 : : }
530 : :
531 : 4 : id = strtoul(argv[1], NULL, 16);
532 : :
533 : 4 : rc = do_iterate(ctx, &do_show_i, &id);
534 : :
535 : 4 : return rc;
536 : : }
537 : :
538 : 6 : static int do_clear_i(struct gard_ctx *ctx, int pos, struct gard_record *gard, void *priv)
539 : : {
540 : 6 : int largest, rc = 0;
541 : 6 : char *buf;
542 : 6 : struct gard_record null_gard;
543 : :
544 : 6 : if (!gard || !ctx || !priv)
545 : : return -1;
546 : :
547 : : /* Not this one */
548 : 6 : if (be32toh(gard->record_id) != *(uint32_t *)priv)
549 : : return 0;
550 : :
551 : 6 : memset(&null_gard, 0xFF, sizeof(null_gard));
552 : :
553 : 6 : largest = count_records(ctx);
554 : :
555 : 6 : printf("Clearing gard record 0x%08x...", be32toh(gard->record_id));
556 : :
557 : 6 : if (largest < 0 || pos > largest) {
558 : : /* Something went horribly wrong */
559 : 0 : fprintf(stderr, "largest index out of range %d\n", largest);
560 : 0 : return -1;
561 : : }
562 : :
563 : 6 : if (pos < largest) {
564 : : /* We're not clearing the last record, shift all the records up */
565 : 6 : int buf_len = ((largest - pos) * sizeof(struct gard_record));
566 : 6 : int buf_pos = ctx->gard_data_pos + ((pos + 1) * sizeof(struct gard_record));
567 : 6 : buf = malloc(buf_len);
568 : 6 : if (!buf)
569 : : return -ENOMEM;
570 : :
571 : 6 : rc = blocklevel_read(ctx->bl, buf_pos, buf, buf_len);
572 : 6 : if (rc) {
573 : 0 : free(buf);
574 : 0 : fprintf(stderr, "Couldn't read from flash at 0x%08x for len 0x%08x\n", buf_pos, buf_len);
575 : 0 : return rc;
576 : : }
577 : :
578 : 6 : rc = blocklevel_smart_write(ctx->bl, buf_pos - sizeof(*gard), buf, buf_len);
579 : 6 : free(buf);
580 : 6 : if (rc) {
581 : 0 : fprintf(stderr, "Couldn't write to flash at 0x%08x for len 0x%08x\n",
582 : : buf_pos - (int) sizeof(struct gard_record), buf_len);
583 : 0 : return rc;
584 : : }
585 : : }
586 : :
587 : : /* Now wipe the last record */
588 : 6 : rc = blocklevel_smart_write(ctx->bl, ctx->gard_data_pos + (largest * sizeof(null_gard)),
589 : : &null_gard, sizeof(null_gard));
590 : 6 : printf("done\n");
591 : :
592 : 6 : return rc;
593 : : }
594 : :
595 : 4 : static int reset_partition(struct gard_ctx *ctx)
596 : : {
597 : 4 : int no_ecc_len = (ctx->gard_data_len / 9) * 8;
598 : 4 : struct gard_record *gard;
599 : 4 : int rc = 0;
600 : :
601 : 4 : gard = malloc(ctx->gard_data_len);
602 : 4 : if (!gard) {
603 : : return FLASH_ERR_MALLOC_FAILED;
604 : : }
605 : 4 : memset(gard, 0xFF, ctx->gard_data_len);
606 : :
607 : 4 : rc = blocklevel_smart_erase(ctx->bl, ctx->gard_data_pos, ctx->gard_data_len);
608 : 4 : if (rc) {
609 : 0 : fprintf(stderr, "Couldn't erase the gard partition. Bailing out\n");
610 : 0 : goto out;
611 : : }
612 : :
613 : 4 : rc = blocklevel_write(ctx->bl, ctx->gard_data_pos, gard, no_ecc_len);
614 : 4 : if (rc)
615 : 0 : fprintf(stderr, "Couldn't reset the entire gard partition. Bailing out\n");
616 : :
617 : 4 : out:
618 : 4 : free(gard);
619 : 4 : return rc;
620 : : }
621 : :
622 : 10 : static int do_clear(struct gard_ctx *ctx, int argc, char **argv)
623 : : {
624 : 10 : int rc;
625 : 10 : uint32_t id;
626 : :
627 : 10 : if (argc != 2) {
628 : 0 : fprintf(stderr, "%s option requires a GARD record or 'all'\n", argv[0]);
629 : 0 : return -1;
630 : : }
631 : :
632 : 10 : if (strncmp(argv[1], "all", strlen("all")) == 0) {
633 : 4 : printf("Clearing the entire gard partition...");
634 : 4 : fflush(stdout);
635 : 4 : rc = reset_partition(ctx);
636 : 4 : printf("done\n");
637 : : } else {
638 : 6 : id = strtoul(argv[1], NULL, 16);
639 : 6 : rc = do_iterate(ctx, do_clear_i, &id);
640 : : }
641 : :
642 : : return rc;
643 : : }
644 : :
645 : 18 : static int do_create(struct gard_ctx *ctx, int argc, char **argv)
646 : : {
647 : 18 : int rc, pos, max_id = 0, last_pos = 0;
648 : 18 : struct gard_record gard;
649 : 18 : struct entity_path path;
650 : :
651 : 18 : if (argc < 2) {
652 : 0 : fprintf(stderr, "create requires path to gard\n");
653 : 0 : fprintf(stderr, "e.g.\n");
654 : 0 : fprintf(stderr, " /Sys0/Node0/Proc0\n");
655 : 0 : fprintf(stderr, " /Sys0/Node0/DIMM15\n");
656 : 0 : return -1;
657 : : }
658 : :
659 : 18 : if (parse_path(argv[1], &path)) {
660 : 8 : fprintf(stderr, "Unable to parse path\n");
661 : 8 : return -1;
662 : : }
663 : :
664 : : /* check if we already have a gard record applied to this path */
665 : 14 : for_each_gard(ctx, pos, &gard, &rc) {
666 : 6 : if (!memcmp(&path, &gard.target_id, sizeof(path))) {
667 : 2 : fprintf(stderr,
668 : : "Unit %s is already GARDed by record %#08x\n",
669 : : argv[1], be32toh(gard.record_id));
670 : 2 : return -1;
671 : : }
672 : :
673 : : /*
674 : : * Keep track of the largest record ID seen so far,
675 : : * we'll give the new record the max + 1 to ensure
676 : : * that it's unique
677 : : */
678 : 4 : if (be32toh(gard.record_id) > max_id)
679 : 4 : max_id = be32toh(gard.record_id);
680 : :
681 : 4 : last_pos++;
682 : : }
683 : :
684 : : /* do we have an empty record to write into? */
685 : 8 : if (!rc && !is_valid_record(&gard)) {
686 : 8 : int offset = last_pos * sizeof(gard);
687 : :
688 : 8 : memset(&gard, 0xff, sizeof(gard));
689 : :
690 : 8 : gard.record_id = be32toh(max_id + 1);
691 : 8 : gard.error_type = GARD_MANUAL;
692 : 8 : gard.target_id = path;
693 : 8 : gard.errlog_eid = 0x0;
694 : :
695 : 8 : if (offset > ctx->gard_data_len - sizeof(gard)) {
696 : 0 : fprintf(stderr, "No space in GUARD for a new record\n");
697 : 0 : return -1;
698 : : }
699 : :
700 : 8 : rc = blocklevel_smart_write(ctx->bl,
701 : 8 : ctx->gard_data_pos + offset, &gard, sizeof(gard));
702 : : }
703 : :
704 : 8 : return rc;
705 : : }
706 : :
707 : 46 : static int check_gard_partition(struct gard_ctx *ctx)
708 : : {
709 : 46 : int rc;
710 : 46 : struct gard_record gard;
711 : 46 : char msg[2];
712 : :
713 : 46 : if (ctx->gard_data_len == 0 || ctx->gard_data_len % sizeof(struct gard_record) != 0)
714 : : /* Just warn for now */
715 : 0 : fprintf(stderr, "The %s partition doesn't appear to be an exact multiple of"
716 : : "gard records in size: %zd vs %u (or partition is zero in length)\n",
717 : : FLASH_GARD_PART, sizeof(struct gard_record), ctx->gard_data_len);
718 : :
719 : : /*
720 : : * Attempt to read the first record, nothing can really operate if the
721 : : * first record is dead. There (currently) isn't a way to validate more
722 : : * than ECC correctness.
723 : : */
724 : 46 : rc = blocklevel_read(ctx->bl, ctx->gard_data_pos, &gard, sizeof(gard));
725 : 46 : if (rc == FLASH_ERR_ECC_INVALID) {
726 : 0 : fprintf(stderr, "The data at the GUARD partition does not appear to be valid gard data\n");
727 : 0 : fprintf(stderr, "Clear the entire GUARD partition? [y/N]\n");
728 : 0 : if (fgets(msg, sizeof(msg), stdin) == NULL) {
729 : 0 : fprintf(stderr, "Couldn't read from standard input\n");
730 : 0 : return -1;
731 : : }
732 : 0 : if (msg[0] == 'y') {
733 : 0 : rc = reset_partition(ctx);
734 : 0 : if (rc) {
735 : 0 : fprintf(stderr, "Couldn't reset the GUARD partition. Bailing out\n");
736 : 0 : return rc;
737 : : }
738 : : }
739 : : /*
740 : : * else leave rc as is so that the main bails out, not going to be
741 : : * able to do sensible anyway
742 : : */
743 : : }
744 : : return rc;
745 : : }
746 : :
747 : : __attribute__ ((unused))
748 : : static int do_nop(struct gard_ctx *ctx, int argc, char **argv)
749 : : {
750 : : (void)ctx;
751 : : (void)argc;
752 : : fprintf(stderr, "Unimplemented action '%s'\n", argv[0]);
753 : : return EXIT_SUCCESS;
754 : : }
755 : :
756 : : struct {
757 : : const char *name;
758 : : const char *desc;
759 : : int (*fn)(struct gard_ctx *, int, char **);
760 : : } actions[] = {
761 : : { "list", "List current GARD records", do_list },
762 : : { "show", "Show details of a GARD record", do_show },
763 : : { "clear", "Clear GARD records", do_clear },
764 : : { "create", "Create a GARD record", do_create },
765 : : };
766 : :
767 : 2 : static void print_version(void)
768 : : {
769 : 4 : printf("Open-Power GARD tool %s\n", version);
770 : : }
771 : :
772 : 2 : static void usage(const char *progname)
773 : : {
774 : 2 : unsigned int i;
775 : :
776 : 2 : print_version();
777 : 2 : fprintf(stderr, "Usage: %s [-a -e -f <file> -p] <command> [<args>]\n\n",
778 : : progname);
779 : 2 : fprintf(stderr, "-8 --p8\n");
780 : 2 : fprintf(stderr, "-9 --p9\n");
781 : 2 : fprintf(stderr, "-0 --p10\n\tSet the processor generation\n\n");
782 : 2 : fprintf(stderr, "-e --ecc\n\tForce reading/writing with ECC bytes.\n\n");
783 : 2 : fprintf(stderr, "-f --file <file>\n\tDon't search for MTD device,"
784 : : " read from <file>.\n\n");
785 : 2 : fprintf(stderr, "-p --part\n\tUsed in conjunction with -f to specify"
786 : : " that just\n");
787 : 2 : fprintf(stderr, "\tthe GUARD partition is in <file> and libffs\n");
788 : 2 : fprintf(stderr, "\tshouldn't be used.\n\n");
789 : :
790 : :
791 : 2 : fprintf(stderr, "Where <command> is one of:\n\n");
792 : :
793 : 12 : for (i = 0; i < ARRAY_SIZE(actions); i++) {
794 : 8 : fprintf(stderr, "\t%-7s\t%s\n",
795 : : actions[i].name, actions[i].desc);
796 : : }
797 : 2 : }
798 : :
799 : 48 : static bool is_fsp(void)
800 : : {
801 : 48 : return access(FDT_FSP_NODE, F_OK) == 0;
802 : : }
803 : :
804 : : static struct option global_options[] = {
805 : : { "file", required_argument, 0, 'f' },
806 : : { "part", no_argument, 0, 'p' },
807 : : { "ecc", no_argument, 0, 'e' },
808 : : { "p8", no_argument, 0, '8' },
809 : : { "p9", no_argument, 0, '9' },
810 : : { "p10", no_argument, 0, '0' },
811 : : { 0 },
812 : : };
813 : : static const char *global_optstring = "+ef:p890";
814 : :
815 : 48 : int main(int argc, char **argv)
816 : : {
817 : 48 : const char *action, *progname;
818 : 48 : char *filename = NULL;
819 : 48 : struct gard_ctx _ctx, *ctx;
820 : 48 : uint64_t bl_size;
821 : 48 : int rc, i = 0;
822 : 48 : bool part = 0;
823 : 48 : bool ecc = 0;
824 : :
825 : 48 : progname = argv[0];
826 : :
827 : 48 : ctx = &_ctx;
828 : 48 : memset(ctx, 0, sizeof(*ctx));
829 : 48 : memset(&blank_record, 0xff, sizeof(blank_record));
830 : :
831 : : /* process global options */
832 : 202 : for (;;) {
833 : 202 : int c;
834 : :
835 : 202 : c = getopt_long(argc, argv, global_optstring, global_options,
836 : : NULL);
837 : 202 : if (c == -1)
838 : : break;
839 : 154 : switch (c) {
840 : 46 : case 'e':
841 : 46 : ecc = true;
842 : 46 : break;
843 : 46 : case 'f':
844 : : /* If they specify -f twice */
845 : 46 : free(filename);
846 : :
847 : 46 : filename = strdup(optarg);
848 : 46 : if (!filename) {
849 : 0 : fprintf(stderr, "Out of memory\n");
850 : 0 : return EXIT_FAILURE;
851 : : }
852 : : break;
853 : 46 : case 'p':
854 : 46 : part = true;
855 : 46 : break;
856 : 10 : case '8':
857 : 10 : set_chip_gen(p8_chip_units);
858 : 10 : break;
859 : 6 : case '9':
860 : 6 : set_chip_gen(p9_chip_units);
861 : 6 : break;
862 : 0 : case '0':
863 : 0 : set_chip_gen(p10_chip_units);
864 : 0 : break;
865 : 0 : case '?':
866 : 0 : usage(progname);
867 : 0 : rc = EXIT_FAILURE;
868 : 0 : goto out_free;
869 : : }
870 : : }
871 : :
872 : :
873 : 48 : if (is_fsp() && !filename) {
874 : 0 : fprintf(stderr, "This is the OpenPower gard tool which does "
875 : : "not support FSP systems\n");
876 : 0 : return EXIT_FAILURE;
877 : : }
878 : :
879 : :
880 : : /*
881 : : * It doesn't make sense to specify that we have the gard partition but
882 : : * read from flash
883 : : */
884 : 48 : if (part && !filename) {
885 : 0 : usage(progname);
886 : 0 : fprintf(stderr, "-p only makes sense when used with -f!\n");
887 : 0 : return EXIT_FAILURE;
888 : : }
889 : :
890 : : /* do we have a command? */
891 : 48 : if (optind == argc) {
892 : 2 : usage(progname);
893 : 2 : rc = EXIT_FAILURE;
894 : 2 : goto out_free;
895 : : }
896 : :
897 : 46 : argc -= optind;
898 : 46 : argv += optind;
899 : 46 : action = argv[0];
900 : :
901 : : #ifdef __arm__
902 : : /*
903 : : * HACK: Look for a vPNOR GUARD file if we haven't been given anything
904 : : * explitly. If it exists then we can safely assume that:
905 : : * a) The host is a P9
906 : : * b) The file is ECC protected
907 : : * c) The file is a bare partition.
908 : : *
909 : : * This is a stupid hack, but there's not other sane place for it.
910 : : * arch_init_flash() always looks for a FFS formatted PNOR when
911 : : * filename is NULL
912 : : */
913 : : if (!filename) {
914 : : struct stat buf;
915 : :
916 : : if (!stat(VPNOR_GARD_FILE, &buf)) {
917 : : filename = strdup(VPNOR_GARD_FILE);
918 : : /* BUG: This ignores the command line settings */
919 : : part = true;
920 : : ecc = true;
921 : : } else if (!stat(VPNOR_GARD_DIR, &buf)) {
922 : : printf(VPNOR_GARD_FILE" is missing. Nothing to do\n");
923 : : return 0;
924 : : }
925 : : }
926 : : #endif
927 : :
928 : 46 : if (!chip_units)
929 : 30 : guess_chip_gen();
930 : :
931 : : /*
932 : : * Force libflash to do flash accesses via the MTD. Direct mode is
933 : : * generally unsafe since it fiddles with the flash controller state
934 : : * underneath the kernel. Anyone who needs direct mode can use pflash
935 : : * instead.
936 : : */
937 : 46 : arch_flash_access(ctx->bl, PNOR_MTD);
938 : :
939 : 46 : if (arch_flash_init(&(ctx->bl), filename, true)) {
940 : : /* Can fail for a few ways, most likely couldn't open MTD device */
941 : 0 : fprintf(stderr, "Can't open %s\n", filename ? filename : "MTD Device. Are you root?");
942 : 0 : rc = EXIT_FAILURE;
943 : 0 : goto out_free;
944 : : }
945 : :
946 : 46 : rc = blocklevel_get_info(ctx->bl, NULL, &bl_size, NULL);
947 : 46 : if (rc)
948 : 0 : goto out;
949 : :
950 : 46 : if (bl_size > UINT_MAX) {
951 : 0 : fprintf(stderr, "MTD device bigger than %i: size: %" PRIu64 "\n",
952 : : UINT_MAX, bl_size);
953 : 0 : rc = EXIT_FAILURE;
954 : 0 : goto out;
955 : : }
956 : 46 : ctx->f_size = bl_size;
957 : :
958 : 46 : if (!part) {
959 : 0 : rc = ffs_init(0, ctx->f_size, ctx->bl, &ctx->ffs, 1);
960 : 0 : if (rc)
961 : 0 : goto out;
962 : :
963 : 0 : rc = ffs_lookup_part(ctx->ffs, FLASH_GARD_PART, &ctx->gard_part_idx);
964 : 0 : if (rc)
965 : 0 : goto out;
966 : :
967 : 0 : rc = ffs_part_info(ctx->ffs, ctx->gard_part_idx, NULL, &(ctx->gard_data_pos),
968 : : &(ctx->gard_data_len), NULL, NULL);
969 : 0 : if (rc)
970 : 0 : goto out;
971 : : } else {
972 : 46 : if (ecc) {
973 : 46 : rc = blocklevel_ecc_protect(ctx->bl, 0, ctx->f_size);
974 : 46 : if (rc)
975 : 0 : goto out;
976 : : }
977 : :
978 : 46 : ctx->gard_data_pos = 0;
979 : 46 : ctx->gard_data_len = ctx->f_size;
980 : : }
981 : :
982 : 46 : rc = check_gard_partition(ctx);
983 : 46 : if (rc) {
984 : 0 : fprintf(stderr, "Does not appear to be sane gard data\n");
985 : 0 : goto out;
986 : : }
987 : :
988 : 124 : for (i = 0; i < ARRAY_SIZE(actions); i++) {
989 : 124 : if (!strcmp(actions[i].name, action)) {
990 : 46 : rc = actions[i].fn(ctx, argc, argv);
991 : 46 : break;
992 : : }
993 : : }
994 : :
995 : 0 : out:
996 : 46 : if (ctx->ffs)
997 : 0 : ffs_close(ctx->ffs);
998 : :
999 : 46 : file_exit_close(ctx->bl);
1000 : :
1001 : 46 : if (i == ARRAY_SIZE(actions)) {
1002 : 0 : fprintf(stderr, "%s: '%s' isn't a valid command\n", progname, action);
1003 : 0 : usage(progname);
1004 : 0 : rc = EXIT_FAILURE;
1005 : 0 : goto out_free;
1006 : : }
1007 : :
1008 : 46 : if (rc > 0) {
1009 : 0 : show_flash_err(rc);
1010 : 0 : if (filename && rc == FFS_ERR_BAD_MAGIC)
1011 : 0 : fprintf(stderr, "Maybe you didn't give a full flash image file?\nDid you mean '--part'?\n");
1012 : : }
1013 : :
1014 : 46 : out_free:
1015 : 48 : free(filename);
1016 : 48 : return rc;
1017 : : }
|