ubispl: add support for loading volumes by name
[oweals/u-boot.git] / cmd / mtd.c
1 // SPDX-License-Identifier:  GPL-2.0+
2 /*
3  * mtd.c
4  *
5  * Generic command to handle basic operations on any memory device.
6  *
7  * Copyright: Bootlin, 2018
8  * Author: Miquèl Raynal <miquel.raynal@bootlin.com>
9  */
10
11 #include <command.h>
12 #include <common.h>
13 #include <console.h>
14 #include <malloc.h>
15 #include <mapmem.h>
16 #include <mtd.h>
17
18 #include <linux/ctype.h>
19
20 static struct mtd_info *get_mtd_by_name(const char *name)
21 {
22         struct mtd_info *mtd;
23
24         mtd_probe_devices();
25
26         mtd = get_mtd_device_nm(name);
27         if (IS_ERR_OR_NULL(mtd))
28                 printf("MTD device %s not found, ret %ld\n", name,
29                        PTR_ERR(mtd));
30
31         return mtd;
32 }
33
34 static uint mtd_len_to_pages(struct mtd_info *mtd, u64 len)
35 {
36         do_div(len, mtd->writesize);
37
38         return len;
39 }
40
41 static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size)
42 {
43         return !do_div(size, mtd->writesize);
44 }
45
46 static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
47 {
48         return !do_div(size, mtd->erasesize);
49 }
50
51 static void mtd_dump_buf(const u8 *buf, uint len, uint offset)
52 {
53         int i, j;
54
55         for (i = 0; i < len; ) {
56                 printf("0x%08x:\t", offset + i);
57                 for (j = 0; j < 8; j++)
58                         printf("%02x ", buf[i + j]);
59                 printf(" ");
60                 i += 8;
61                 for (j = 0; j < 8; j++)
62                         printf("%02x ", buf[i + j]);
63                 printf("\n");
64                 i += 8;
65         }
66 }
67
68 static void mtd_dump_device_buf(struct mtd_info *mtd, u64 start_off,
69                                 const u8 *buf, u64 len, bool woob)
70 {
71         bool has_pages = mtd->type == MTD_NANDFLASH ||
72                 mtd->type == MTD_MLCNANDFLASH;
73         int npages = mtd_len_to_pages(mtd, len);
74         uint page;
75
76         if (has_pages) {
77                 for (page = 0; page < npages; page++) {
78                         u64 data_off = page * mtd->writesize;
79
80                         printf("\nDump %d data bytes from 0x%08llx:\n",
81                                mtd->writesize, start_off + data_off);
82                         mtd_dump_buf(&buf[data_off],
83                                      mtd->writesize, start_off + data_off);
84
85                         if (woob) {
86                                 u64 oob_off = page * mtd->oobsize;
87
88                                 printf("Dump %d OOB bytes from page at 0x%08llx:\n",
89                                        mtd->oobsize, start_off + data_off);
90                                 mtd_dump_buf(&buf[len + oob_off],
91                                              mtd->oobsize, 0);
92                         }
93                 }
94         } else {
95                 printf("\nDump %lld data bytes from 0x%llx:\n",
96                        len, start_off);
97                 mtd_dump_buf(buf, len, start_off);
98         }
99 }
100
101 static void mtd_show_parts(struct mtd_info *mtd, int level)
102 {
103         struct mtd_info *part;
104         int i;
105
106         list_for_each_entry(part, &mtd->partitions, node) {
107                 for (i = 0; i < level; i++)
108                         printf("\t");
109                 printf("  - 0x%012llx-0x%012llx : \"%s\"\n",
110                        part->offset, part->offset + part->size, part->name);
111
112                 mtd_show_parts(part, level + 1);
113         }
114 }
115
116 static void mtd_show_device(struct mtd_info *mtd)
117 {
118         /* Device */
119         printf("* %s\n", mtd->name);
120 #if defined(CONFIG_DM)
121         if (mtd->dev) {
122                 printf("  - device: %s\n", mtd->dev->name);
123                 printf("  - parent: %s\n", mtd->dev->parent->name);
124                 printf("  - driver: %s\n", mtd->dev->driver->name);
125         }
126 #endif
127
128         /* MTD device information */
129         printf("  - type: ");
130         switch (mtd->type) {
131         case MTD_RAM:
132                 printf("RAM\n");
133                 break;
134         case MTD_ROM:
135                 printf("ROM\n");
136                 break;
137         case MTD_NORFLASH:
138                 printf("NOR flash\n");
139                 break;
140         case MTD_NANDFLASH:
141                 printf("NAND flash\n");
142                 break;
143         case MTD_DATAFLASH:
144                 printf("Data flash\n");
145                 break;
146         case MTD_UBIVOLUME:
147                 printf("UBI volume\n");
148                 break;
149         case MTD_MLCNANDFLASH:
150                 printf("MLC NAND flash\n");
151                 break;
152         case MTD_ABSENT:
153         default:
154                 printf("Unknown\n");
155                 break;
156         }
157
158         printf("  - block size: 0x%x bytes\n", mtd->erasesize);
159         printf("  - min I/O: 0x%x bytes\n", mtd->writesize);
160
161         if (mtd->oobsize) {
162                 printf("  - OOB size: %u bytes\n", mtd->oobsize);
163                 printf("  - OOB available: %u bytes\n", mtd->oobavail);
164         }
165
166         if (mtd->ecc_strength) {
167                 printf("  - ECC strength: %u bits\n", mtd->ecc_strength);
168                 printf("  - ECC step size: %u bytes\n", mtd->ecc_step_size);
169                 printf("  - bitflip threshold: %u bits\n",
170                        mtd->bitflip_threshold);
171         }
172
173         printf("  - 0x%012llx-0x%012llx : \"%s\"\n",
174                mtd->offset, mtd->offset + mtd->size, mtd->name);
175
176         /* MTD partitions, if any */
177         mtd_show_parts(mtd, 1);
178 }
179
180 /* Logic taken from fs/ubifs/recovery.c:is_empty() */
181 static bool mtd_oob_write_is_empty(struct mtd_oob_ops *op)
182 {
183         int i;
184
185         for (i = 0; i < op->len; i++)
186                 if (op->datbuf[i] != 0xff)
187                         return false;
188
189         for (i = 0; i < op->ooblen; i++)
190                 if (op->oobbuf[i] != 0xff)
191                         return false;
192
193         return true;
194 }
195
196 static int do_mtd_list(cmd_tbl_t *cmdtp, int flag, int argc,
197                        char * const argv[])
198 {
199         struct mtd_info *mtd;
200         int dev_nb = 0;
201
202         /* Ensure all devices (and their partitions) are probed */
203         mtd_probe_devices();
204
205         printf("List of MTD devices:\n");
206         mtd_for_each_device(mtd) {
207                 if (!mtd_is_partition(mtd))
208                         mtd_show_device(mtd);
209
210                 dev_nb++;
211         }
212
213         if (!dev_nb) {
214                 printf("No MTD device found\n");
215                 return CMD_RET_FAILURE;
216         }
217
218         return CMD_RET_SUCCESS;
219 }
220
221 static int mtd_special_write_oob(struct mtd_info *mtd, u64 off,
222                                  struct mtd_oob_ops *io_op,
223                                  bool write_empty_pages, bool woob)
224 {
225         int ret = 0;
226
227         /*
228          * By default, do not write an empty page.
229          * Skip it by simulating a successful write.
230          */
231         if (!write_empty_pages && mtd_oob_write_is_empty(io_op)) {
232                 io_op->retlen = mtd->writesize;
233                 io_op->oobretlen = woob ? mtd->oobsize : 0;
234         } else {
235                 ret = mtd_write_oob(mtd, off, io_op);
236         }
237
238         return ret;
239 }
240
241 static int do_mtd_io(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
242 {
243         bool dump, read, raw, woob, write_empty_pages, has_pages = false;
244         u64 start_off, off, len, remaining, default_len;
245         struct mtd_oob_ops io_op = {};
246         uint user_addr = 0, npages;
247         const char *cmd = argv[0];
248         struct mtd_info *mtd;
249         u32 oob_len;
250         u8 *buf;
251         int ret;
252
253         if (argc < 2)
254                 return CMD_RET_USAGE;
255
256         mtd = get_mtd_by_name(argv[1]);
257         if (IS_ERR_OR_NULL(mtd))
258                 return CMD_RET_FAILURE;
259
260         if (mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH)
261                 has_pages = true;
262
263         dump = !strncmp(cmd, "dump", 4);
264         read = dump || !strncmp(cmd, "read", 4);
265         raw = strstr(cmd, ".raw");
266         woob = strstr(cmd, ".oob");
267         write_empty_pages = !has_pages || strstr(cmd, ".dontskipff");
268
269         argc -= 2;
270         argv += 2;
271
272         if (!dump) {
273                 if (!argc) {
274                         ret = CMD_RET_USAGE;
275                         goto out_put_mtd;
276                 }
277
278                 user_addr = simple_strtoul(argv[0], NULL, 16);
279                 argc--;
280                 argv++;
281         }
282
283         start_off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
284         if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) {
285                 printf("Offset not aligned with a page (0x%x)\n",
286                        mtd->writesize);
287                 ret = CMD_RET_FAILURE;
288                 goto out_put_mtd;
289         }
290
291         default_len = dump ? mtd->writesize : mtd->size;
292         len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : default_len;
293         if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
294                 len = round_up(len, mtd->writesize);
295                 printf("Size not on a page boundary (0x%x), rounding to 0x%llx\n",
296                        mtd->writesize, len);
297         }
298
299         remaining = len;
300         npages = mtd_len_to_pages(mtd, len);
301         oob_len = woob ? npages * mtd->oobsize : 0;
302
303         if (dump)
304                 buf = kmalloc(len + oob_len, GFP_KERNEL);
305         else
306                 buf = map_sysmem(user_addr, 0);
307
308         if (!buf) {
309                 printf("Could not map/allocate the user buffer\n");
310                 ret = CMD_RET_FAILURE;
311                 goto out_put_mtd;
312         }
313
314         if (has_pages)
315                 printf("%s %lld byte(s) (%d page(s)) at offset 0x%08llx%s%s%s\n",
316                        read ? "Reading" : "Writing", len, npages, start_off,
317                        raw ? " [raw]" : "", woob ? " [oob]" : "",
318                        !read && write_empty_pages ? " [dontskipff]" : "");
319         else
320                 printf("%s %lld byte(s) at offset 0x%08llx\n",
321                        read ? "Reading" : "Writing", len, start_off);
322
323         io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
324         io_op.len = has_pages ? mtd->writesize : len;
325         io_op.ooblen = woob ? mtd->oobsize : 0;
326         io_op.datbuf = buf;
327         io_op.oobbuf = woob ? &buf[len] : NULL;
328
329         /* Search for the first good block after the given offset */
330         off = start_off;
331         while (mtd_block_isbad(mtd, off))
332                 off += mtd->erasesize;
333
334         /* Loop over the pages to do the actual read/write */
335         while (remaining) {
336                 /* Skip the block if it is bad */
337                 if (mtd_is_aligned_with_block_size(mtd, off) &&
338                     mtd_block_isbad(mtd, off)) {
339                         off += mtd->erasesize;
340                         continue;
341                 }
342
343                 if (read)
344                         ret = mtd_read_oob(mtd, off, &io_op);
345                 else
346                         ret = mtd_special_write_oob(mtd, off, &io_op,
347                                                     write_empty_pages, woob);
348
349                 if (ret) {
350                         printf("Failure while %s at offset 0x%llx\n",
351                                read ? "reading" : "writing", off);
352                         break;
353                 }
354
355                 off += io_op.retlen;
356                 remaining -= io_op.retlen;
357                 io_op.datbuf += io_op.retlen;
358                 io_op.oobbuf += io_op.oobretlen;
359         }
360
361         if (!ret && dump)
362                 mtd_dump_device_buf(mtd, start_off, buf, len, woob);
363
364         if (dump)
365                 kfree(buf);
366         else
367                 unmap_sysmem(buf);
368
369         if (ret) {
370                 printf("%s on %s failed with error %d\n",
371                        read ? "Read" : "Write", mtd->name, ret);
372                 ret = CMD_RET_FAILURE;
373         } else {
374                 ret = CMD_RET_SUCCESS;
375         }
376
377 out_put_mtd:
378         put_mtd_device(mtd);
379
380         return ret;
381 }
382
383 static int do_mtd_erase(cmd_tbl_t *cmdtp, int flag, int argc,
384                         char * const argv[])
385 {
386         struct erase_info erase_op = {};
387         struct mtd_info *mtd;
388         u64 off, len;
389         bool scrub;
390         int ret;
391
392         if (argc < 2)
393                 return CMD_RET_USAGE;
394
395         mtd = get_mtd_by_name(argv[1]);
396         if (IS_ERR_OR_NULL(mtd))
397                 return CMD_RET_FAILURE;
398
399         scrub = strstr(argv[0], ".dontskipbad");
400
401         argc -= 2;
402         argv += 2;
403
404         off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
405         len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : mtd->size;
406
407         if (!mtd_is_aligned_with_block_size(mtd, off)) {
408                 printf("Offset not aligned with a block (0x%x)\n",
409                        mtd->erasesize);
410                 ret = CMD_RET_FAILURE;
411                 goto out_put_mtd;
412         }
413
414         if (!mtd_is_aligned_with_block_size(mtd, len)) {
415                 printf("Size not a multiple of a block (0x%x)\n",
416                        mtd->erasesize);
417                 ret = CMD_RET_FAILURE;
418                 goto out_put_mtd;
419         }
420
421         printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n",
422                off, off + len - 1, mtd_div_by_eb(len, mtd));
423
424         erase_op.mtd = mtd;
425         erase_op.addr = off;
426         erase_op.len = len;
427         erase_op.scrub = scrub;
428
429         while (erase_op.len) {
430                 ret = mtd_erase(mtd, &erase_op);
431
432                 /* Abort if its not a bad block error */
433                 if (ret != -EIO)
434                         break;
435
436                 printf("Skipping bad block at 0x%08llx\n", erase_op.fail_addr);
437
438                 /* Skip bad block and continue behind it */
439                 erase_op.len -= erase_op.fail_addr - erase_op.addr;
440                 erase_op.len -= mtd->erasesize;
441                 erase_op.addr = erase_op.fail_addr + mtd->erasesize;
442         }
443
444         if (ret && ret != -EIO)
445                 ret = CMD_RET_FAILURE;
446         else
447                 ret = CMD_RET_SUCCESS;
448
449 out_put_mtd:
450         put_mtd_device(mtd);
451
452         return ret;
453 }
454
455 static int do_mtd_bad(cmd_tbl_t *cmdtp, int flag, int argc,
456                       char * const argv[])
457 {
458         struct mtd_info *mtd;
459         loff_t off;
460
461         if (argc < 2)
462                 return CMD_RET_USAGE;
463
464         mtd = get_mtd_by_name(argv[1]);
465         if (IS_ERR_OR_NULL(mtd))
466                 return CMD_RET_FAILURE;
467
468         if (!mtd_can_have_bb(mtd)) {
469                 printf("Only NAND-based devices can have bad blocks\n");
470                 goto out_put_mtd;
471         }
472
473         printf("MTD device %s bad blocks list:\n", mtd->name);
474         for (off = 0; off < mtd->size; off += mtd->erasesize) {
475                 if (mtd_block_isbad(mtd, off))
476                         printf("\t0x%08llx\n", off);
477         }
478
479 out_put_mtd:
480         put_mtd_device(mtd);
481
482         return CMD_RET_SUCCESS;
483 }
484
485 #ifdef CONFIG_AUTO_COMPLETE
486 static int mtd_name_complete(int argc, char * const argv[], char last_char,
487                              int maxv, char *cmdv[])
488 {
489         int len = 0, n_found = 0;
490         struct mtd_info *mtd;
491
492         argc--;
493         argv++;
494
495         if (argc > 1 ||
496             (argc == 1 && (last_char == '\0' || isblank(last_char))))
497                 return 0;
498
499         if (argc)
500                 len = strlen(argv[0]);
501
502         mtd_for_each_device(mtd) {
503                 if (argc &&
504                     (len > strlen(mtd->name) ||
505                      strncmp(argv[0], mtd->name, len)))
506                         continue;
507
508                 if (n_found >= maxv - 2) {
509                         cmdv[n_found++] = "...";
510                         break;
511                 }
512
513                 cmdv[n_found++] = mtd->name;
514         }
515
516         cmdv[n_found] = NULL;
517
518         return n_found;
519 }
520 #endif /* CONFIG_AUTO_COMPLETE */
521
522 #ifdef CONFIG_SYS_LONGHELP
523 static char mtd_help_text[] =
524         "- generic operations on memory technology devices\n\n"
525         "mtd list\n"
526         "mtd read[.raw][.oob]                  <name> <addr> [<off> [<size>]]\n"
527         "mtd dump[.raw][.oob]                  <name>        [<off> [<size>]]\n"
528         "mtd write[.raw][.oob][.dontskipff]    <name> <addr> [<off> [<size>]]\n"
529         "mtd erase[.dontskipbad]               <name>        [<off> [<size>]]\n"
530         "\n"
531         "Specific functions:\n"
532         "mtd bad                               <name>\n"
533         "\n"
534         "With:\n"
535         "\t<name>: NAND partition/chip name\n"
536         "\t<addr>: user address from/to which data will be retrieved/stored\n"
537         "\t<off>: offset in <name> in bytes (default: start of the part)\n"
538         "\t\t* must be block-aligned for erase\n"
539         "\t\t* must be page-aligned otherwise\n"
540         "\t<size>: length of the operation in bytes (default: the entire device)\n"
541         "\t\t* must be a multiple of a block for erase\n"
542         "\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n"
543         "\n"
544         "The .dontskipff option forces writing empty pages, don't use it if unsure.\n";
545 #endif
546
547 U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text,
548                 U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list),
549                 U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io,
550                                              mtd_name_complete),
551                 U_BOOT_SUBCMD_MKENT_COMPLETE(write, 5, 0, do_mtd_io,
552                                              mtd_name_complete),
553                 U_BOOT_SUBCMD_MKENT_COMPLETE(dump, 4, 0, do_mtd_io,
554                                              mtd_name_complete),
555                 U_BOOT_SUBCMD_MKENT_COMPLETE(erase, 4, 0, do_mtd_erase,
556                                              mtd_name_complete),
557                 U_BOOT_SUBCMD_MKENT_COMPLETE(bad, 2, 1, do_mtd_bad,
558                                              mtd_name_complete));