1/*
2 * Unsorted Block Image commands
3 *
4 *  Copyright (C) 2008 Samsung Electronics
5 *  Kyungmin Park <kyungmin.park@samsung.com>
6 *
7 * Copyright 2008-2009 Stefan Roese <sr@denx.de>, DENX Software Engineering
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <common.h>
15#include <command.h>
16#include <env.h>
17#include <exports.h>
18#include <malloc.h>
19#include <memalign.h>
20#include <mtd.h>
21#include <nand.h>
22#include <onenand_uboot.h>
23#include <dm/devres.h>
24#include <linux/mtd/mtd.h>
25#include <linux/mtd/partitions.h>
26#include <linux/err.h>
27#include <ubi_uboot.h>
28#include <linux/errno.h>
29#include <jffs2/load_kernel.h>
30#include <linux/log2.h>
31
32#undef ubi_msg
33#define ubi_msg(fmt, ...) printf("UBI: " fmt "\n", ##__VA_ARGS__)
34
35/* Private own data */
36static struct ubi_device *ubi;
37
38#ifdef CONFIG_CMD_UBIFS
39#include <ubifs_uboot.h>
40#endif
41
42static void display_volume_info(struct ubi_device *ubi)
43{
44	int i;
45
46	for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
47		if (!ubi->volumes[i])
48			continue;	/* Empty record */
49		ubi_dump_vol_info(ubi->volumes[i]);
50	}
51}
52
53static void display_ubi_info(struct ubi_device *ubi)
54{
55	ubi_msg("MTD device name:            \"%s\"", ubi->mtd->name);
56	ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
57	ubi_msg("physical eraseblock size:   %d bytes (%d KiB)",
58			ubi->peb_size, ubi->peb_size >> 10);
59	ubi_msg("logical eraseblock size:    %d bytes", ubi->leb_size);
60	ubi_msg("number of good PEBs:        %d", ubi->good_peb_count);
61	ubi_msg("number of bad PEBs:         %d", ubi->bad_peb_count);
62	ubi_msg("smallest flash I/O unit:    %d", ubi->min_io_size);
63	ubi_msg("VID header offset:          %d (aligned %d)",
64			ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
65	ubi_msg("data offset:                %d", ubi->leb_start);
66	ubi_msg("max. allowed volumes:       %d", ubi->vtbl_slots);
67	ubi_msg("wear-leveling threshold:    %d", CONFIG_MTD_UBI_WL_THRESHOLD);
68	ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT);
69	ubi_msg("number of user volumes:     %d",
70			ubi->vol_count - UBI_INT_VOL_COUNT);
71	ubi_msg("available PEBs:             %d", ubi->avail_pebs);
72	ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs);
73	ubi_msg("number of PEBs reserved for bad PEB handling: %d",
74			ubi->beb_rsvd_pebs);
75	ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
76}
77
78static int ubi_info(int layout)
79{
80	if (layout)
81		display_volume_info(ubi);
82	else
83		display_ubi_info(ubi);
84
85	return 0;
86}
87
88static int ubi_list(const char *var, int numeric)
89{
90	size_t namelen, len, size;
91	char *str, *str2;
92	int i;
93
94	if (!var) {
95		for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
96			if (!ubi->volumes[i])
97				continue;
98			if (ubi->volumes[i]->vol_id >= UBI_INTERNAL_VOL_START)
99				continue;
100			printf("%d: %s\n",
101			       ubi->volumes[i]->vol_id,
102			       ubi->volumes[i]->name);
103		}
104		return 0;
105	}
106
107	len = 0;
108	size = 16;
109	str = malloc(size);
110	if (!str)
111		return 1;
112
113	for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
114		if (!ubi->volumes[i])
115			continue;
116		if (ubi->volumes[i]->vol_id >= UBI_INTERNAL_VOL_START)
117			continue;
118
119		if (numeric)
120			namelen = 10; /* strlen(stringify(INT_MAX)) */
121		else
122			namelen = strlen(ubi->volumes[i]->name);
123
124		if (len + namelen + 1 > size) {
125			size = roundup_pow_of_two(len + namelen + 1) * 2;
126			str2 = realloc(str, size);
127			if (!str2) {
128				free(str);
129				return 1;
130			}
131			str = str2;
132		}
133
134		if (len)
135			str[len++] = ' ';
136
137		if (numeric) {
138			len += sprintf(str + len, "%d", ubi->volumes[i]->vol_id) + 1;
139		} else {
140			memcpy(str + len, ubi->volumes[i]->name, namelen);
141			len += namelen;
142			str[len] = 0;
143		}
144	}
145
146	env_set(var, str);
147	free(str);
148
149	return 0;
150}
151
152static int ubi_check_volumename(const struct ubi_volume *vol, char *name)
153{
154	return strcmp(vol->name, name);
155}
156
157static int ubi_check(char *name)
158{
159	int i;
160
161	for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
162		if (!ubi->volumes[i])
163			continue;	/* Empty record */
164
165		if (!ubi_check_volumename(ubi->volumes[i], name))
166			return 0;
167	}
168
169	return 1;
170}
171
172static int verify_mkvol_req(const struct ubi_device *ubi,
173			    const struct ubi_mkvol_req *req)
174{
175	int n, err = EINVAL;
176
177	if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 ||
178	    req->name_len < 0)
179		goto bad;
180
181	if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) &&
182	    req->vol_id != UBI_VOL_NUM_AUTO)
183		goto bad;
184
185	if (req->alignment == 0)
186		goto bad;
187
188	if (req->bytes == 0) {
189		printf("No space left in UBI device!\n");
190		err = ENOMEM;
191		goto bad;
192	}
193
194	if (req->vol_type != UBI_DYNAMIC_VOLUME &&
195	    req->vol_type != UBI_STATIC_VOLUME)
196		goto bad;
197
198	if (req->alignment > ubi->leb_size)
199		goto bad;
200
201	n = req->alignment % ubi->min_io_size;
202	if (req->alignment != 1 && n)
203		goto bad;
204
205	if (req->name_len > UBI_VOL_NAME_MAX) {
206		printf("Name too long!\n");
207		err = ENAMETOOLONG;
208		goto bad;
209	}
210
211	return 0;
212bad:
213	return err;
214}
215
216static int ubi_create_vol(char *volume, int64_t size, int dynamic, int vol_id,
217			  bool skipcheck)
218{
219	struct ubi_mkvol_req req;
220	int err;
221
222	if (dynamic)
223		req.vol_type = UBI_DYNAMIC_VOLUME;
224	else
225		req.vol_type = UBI_STATIC_VOLUME;
226
227	req.vol_id = vol_id;
228	req.alignment = 1;
229	req.bytes = size;
230
231	strcpy(req.name, volume);
232	req.name_len = strlen(volume);
233	req.name[req.name_len] = '\0';
234	req.flags = 0;
235	if (skipcheck)
236		req.flags |= UBI_VOL_SKIP_CRC_CHECK_FLG;
237
238	/* It's duplicated at drivers/mtd/ubi/cdev.c */
239	err = verify_mkvol_req(ubi, &req);
240	if (err) {
241		printf("verify_mkvol_req failed %d\n", err);
242		return err;
243	}
244	printf("Creating %s volume %s of size %lld\n",
245		dynamic ? "dynamic" : "static", volume, size);
246	/* Call real ubi create volume */
247	return ubi_create_volume(ubi, &req);
248}
249
250static struct ubi_volume *ubi_find_volume(char *volume)
251{
252	struct ubi_volume *vol = NULL;
253	int i;
254
255	for (i = 0; i < ubi->vtbl_slots; i++) {
256		vol = ubi->volumes[i];
257		if (vol && !strcmp(vol->name, volume))
258			return vol;
259	}
260
261	printf("Volume %s not found!\n", volume);
262	return NULL;
263}
264
265static int ubi_remove_vol(char *volume)
266{
267	int err, reserved_pebs, i;
268	struct ubi_volume *vol;
269
270	vol = ubi_find_volume(volume);
271	if (vol == NULL)
272		return ENODEV;
273
274	printf("Remove UBI volume %s (id %d)\n", vol->name, vol->vol_id);
275
276	if (ubi->ro_mode) {
277		printf("It's read-only mode\n");
278		err = EROFS;
279		goto out_err;
280	}
281
282	err = ubi_change_vtbl_record(ubi, vol->vol_id, NULL);
283	if (err) {
284		printf("Error changing Vol tabel record err=%x\n", err);
285		goto out_err;
286	}
287	reserved_pebs = vol->reserved_pebs;
288	for (i = 0; i < vol->reserved_pebs; i++) {
289		err = ubi_eba_unmap_leb(ubi, vol, i);
290		if (err)
291			goto out_err;
292	}
293
294	kfree(vol->eba_tbl);
295	ubi->volumes[vol->vol_id]->eba_tbl = NULL;
296	ubi->volumes[vol->vol_id] = NULL;
297
298	ubi->rsvd_pebs -= reserved_pebs;
299	ubi->avail_pebs += reserved_pebs;
300	i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
301	if (i > 0) {
302		i = ubi->avail_pebs >= i ? i : ubi->avail_pebs;
303		ubi->avail_pebs -= i;
304		ubi->rsvd_pebs += i;
305		ubi->beb_rsvd_pebs += i;
306		if (i > 0)
307			ubi_msg("reserve more %d PEBs", i);
308	}
309	ubi->vol_count -= 1;
310
311	return 0;
312out_err:
313	ubi_err(ubi, "cannot remove volume %s, error %d", volume, err);
314	if (err < 0)
315		err = -err;
316	return err;
317}
318
319static int ubi_rename_vol(char *oldname, char *newname)
320{
321	struct ubi_volume *vol;
322	struct ubi_rename_entry rename;
323	struct ubi_volume_desc desc;
324	struct list_head list;
325
326	vol = ubi_find_volume(oldname);
327	if (!vol) {
328		printf("%s: volume %s doesn't exist\n", __func__, oldname);
329		return ENODEV;
330	}
331
332	if (!ubi_check(newname)) {
333		printf("%s: volume %s already exist\n", __func__, newname);
334		return EINVAL;
335	}
336
337	printf("Rename UBI volume %s to %s\n", oldname, newname);
338
339	if (ubi->ro_mode) {
340		printf("%s: ubi device is in read-only mode\n", __func__);
341		return EROFS;
342	}
343
344	rename.new_name_len = strlen(newname);
345	strcpy(rename.new_name, newname);
346	rename.remove = 0;
347	desc.vol = vol;
348	desc.mode = 0;
349	rename.desc = &desc;
350	INIT_LIST_HEAD(&rename.list);
351	INIT_LIST_HEAD(&list);
352	list_add(&rename.list, &list);
353
354	return ubi_rename_volumes(ubi, &list);
355}
356
357static int ubi_volume_continue_write(char *volume, void *buf, size_t size)
358{
359	int err = 1;
360	struct ubi_volume *vol;
361
362	vol = ubi_find_volume(volume);
363	if (vol == NULL)
364		return ENODEV;
365
366	err = ubi_more_update_data(ubi, vol, buf, size);
367	if (err < 0) {
368		printf("Couldnt or partially wrote data\n");
369		return -err;
370	}
371
372	if (err) {
373		size = err;
374
375		err = ubi_check_volume(ubi, vol->vol_id);
376		if (err < 0)
377			return -err;
378
379		if (err) {
380			ubi_warn(ubi, "volume %d on UBI device %d is corrupt",
381				 vol->vol_id, ubi->ubi_num);
382			vol->corrupted = 1;
383		}
384
385		vol->checked = 1;
386		ubi_gluebi_updated(vol);
387	}
388
389	return 0;
390}
391
392int ubi_volume_begin_write(char *volume, void *buf, size_t size,
393	size_t full_size)
394{
395	int err = 1;
396	int rsvd_bytes = 0;
397	struct ubi_volume *vol;
398
399	vol = ubi_find_volume(volume);
400	if (vol == NULL)
401		return ENODEV;
402
403	rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad);
404	if (size > rsvd_bytes) {
405		printf("size > volume size! Aborting!\n");
406		return EINVAL;
407	}
408
409	err = ubi_start_update(ubi, vol, full_size);
410	if (err < 0) {
411		printf("Cannot start volume update\n");
412		return -err;
413	}
414
415	return ubi_volume_continue_write(volume, buf, size);
416}
417
418int ubi_volume_write(char *volume, void *buf, size_t size)
419{
420	return ubi_volume_begin_write(volume, buf, size, size);
421}
422
423int ubi_volume_read(char *volume, char *buf, size_t size)
424{
425	int err, lnum, off, len, tbuf_size;
426	void *tbuf;
427	unsigned long long tmp;
428	struct ubi_volume *vol;
429	loff_t offp = 0;
430	size_t len_read;
431
432	vol = ubi_find_volume(volume);
433	if (vol == NULL)
434		return ENODEV;
435
436	if (vol->updating) {
437		printf("updating");
438		return EBUSY;
439	}
440	if (vol->upd_marker) {
441		printf("damaged volume, update marker is set");
442		return EBADF;
443	}
444	if (offp == vol->used_bytes)
445		return 0;
446
447	if (size == 0) {
448		printf("No size specified -> Using max size (%lld)\n", vol->used_bytes);
449		size = vol->used_bytes;
450	}
451
452	printf("Read %zu bytes from volume %s to %p\n", size, volume, buf);
453
454	if (vol->corrupted)
455		printf("read from corrupted volume %d", vol->vol_id);
456	if (offp + size > vol->used_bytes)
457		size = vol->used_bytes - offp;
458
459	tbuf_size = vol->usable_leb_size;
460	if (size < tbuf_size)
461		tbuf_size = ALIGN(size, ubi->min_io_size);
462	tbuf = malloc_cache_aligned(tbuf_size);
463	if (!tbuf) {
464		printf("NO MEM\n");
465		return ENOMEM;
466	}
467	len = size > tbuf_size ? tbuf_size : size;
468
469	tmp = offp;
470	off = do_div(tmp, vol->usable_leb_size);
471	lnum = tmp;
472	len_read = size;
473	do {
474		if (off + len >= vol->usable_leb_size)
475			len = vol->usable_leb_size - off;
476
477		err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0);
478		if (err) {
479			printf("read err %x\n", err);
480			err = -err;
481			break;
482		}
483		off += len;
484		if (off == vol->usable_leb_size) {
485			lnum += 1;
486			off -= vol->usable_leb_size;
487		}
488
489		size -= len;
490		offp += len;
491
492		memcpy(buf, tbuf, len);
493
494		buf += len;
495		len = size > tbuf_size ? tbuf_size : size;
496	} while (size);
497
498	if (!size)
499		env_set_hex("filesize", len_read);
500
501	free(tbuf);
502	return err;
503}
504
505static int ubi_dev_scan(struct mtd_info *info, const char *vid_header_offset)
506{
507	char ubi_mtd_param_buffer[80];
508	int err;
509
510	if (!vid_header_offset)
511		sprintf(ubi_mtd_param_buffer, "%s", info->name);
512	else
513		sprintf(ubi_mtd_param_buffer, "%s,%s", info->name,
514			vid_header_offset);
515
516	err = ubi_mtd_param_parse(ubi_mtd_param_buffer, NULL);
517	if (err)
518		return -err;
519
520	err = ubi_init();
521	if (err)
522		return -err;
523
524	return 0;
525}
526
527static int ubi_set_skip_check(char *volume, bool skip_check)
528{
529	struct ubi_vtbl_record vtbl_rec;
530	struct ubi_volume *vol;
531
532	vol = ubi_find_volume(volume);
533	if (!vol)
534		return ENODEV;
535
536	printf("%sing skip_check on volume %s\n",
537	       skip_check ? "Sett" : "Clear", volume);
538
539	vtbl_rec = ubi->vtbl[vol->vol_id];
540	if (skip_check) {
541		vtbl_rec.flags |= UBI_VTBL_SKIP_CRC_CHECK_FLG;
542		vol->skip_check = 1;
543	} else {
544		vtbl_rec.flags &= ~UBI_VTBL_SKIP_CRC_CHECK_FLG;
545		vol->skip_check = 0;
546	}
547
548	return ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
549}
550
551static int ubi_detach(void)
552{
553#ifdef CONFIG_CMD_UBIFS
554	/*
555	 * Automatically unmount UBIFS partition when user
556	 * changes the UBI device. Otherwise the following
557	 * UBIFS commands will crash.
558	 */
559	if (ubifs_is_mounted())
560		cmd_ubifs_umount();
561#endif
562
563	/*
564	 * Call ubi_exit() before re-initializing the UBI subsystem
565	 */
566	if (ubi)
567		ubi_exit();
568
569	ubi = NULL;
570
571	return 0;
572}
573
574int ubi_part(char *part_name, const char *vid_header_offset)
575{
576	struct mtd_info *mtd;
577	int err = 0;
578
579	if (ubi && ubi->mtd && !strcmp(ubi->mtd->name, part_name)) {
580		printf("UBI partition '%s' already selected\n", part_name);
581		return 0;
582	}
583
584	ubi_detach();
585
586	mtd_probe_devices();
587	mtd = get_mtd_device_nm(part_name);
588	if (IS_ERR(mtd)) {
589		printf("Partition %s not found!\n", part_name);
590		return 1;
591	}
592	put_mtd_device(mtd);
593
594	err = ubi_dev_scan(mtd, vid_header_offset);
595	if (err) {
596		printf("UBI init error %d\n", err);
597		printf("Please check, if the correct MTD partition is used (size big enough?)\n");
598		return err;
599	}
600
601	ubi = ubi_devices[0];
602
603	return 0;
604}
605
606static int do_ubi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
607{
608	int64_t size = 0;
609	ulong addr = 0;
610	bool skipcheck = false;
611
612	if (argc < 2)
613		return CMD_RET_USAGE;
614
615	if (strcmp(argv[1], "detach") == 0)
616		return ubi_detach();
617
618	if (strcmp(argv[1], "part") == 0) {
619		const char *vid_header_offset = NULL;
620
621		/* Print current partition */
622		if (argc == 2) {
623			if (!ubi) {
624				printf("Error, no UBI device selected!\n");
625				return 1;
626			}
627
628			printf("Device %d: %s, MTD partition %s\n",
629			       ubi->ubi_num, ubi->ubi_name, ubi->mtd->name);
630			return 0;
631		}
632
633		if (argc < 3)
634			return CMD_RET_USAGE;
635
636		if (argc > 3)
637			vid_header_offset = argv[3];
638
639		return ubi_part(argv[2], vid_header_offset);
640	}
641
642	if ((strcmp(argv[1], "part") != 0) && !ubi) {
643		printf("Error, no UBI device selected!\n");
644		return 1;
645	}
646
647	if (strcmp(argv[1], "info") == 0) {
648		int layout = 0;
649		if (argc > 2 && !strncmp(argv[2], "l", 1))
650			layout = 1;
651		return ubi_info(layout);
652	}
653
654	if (strcmp(argv[1], "list") == 0) {
655		int numeric = 0;
656		if (argc >= 3 && argv[2][0] == '-') {
657			if (strcmp(argv[2], "-numeric") == 0)
658				numeric = 1;
659			else
660				return CMD_RET_USAGE;
661		}
662		if (!numeric && argc != 2 && argc != 3)
663			return CMD_RET_USAGE;
664		if (numeric && argc != 3 && argc != 4)
665			return CMD_RET_USAGE;
666		return ubi_list(argv[numeric ? 3 : 2], numeric);
667	}
668
669	if (strcmp(argv[1], "check") == 0) {
670		if (argc > 2)
671			return ubi_check(argv[2]);
672
673		printf("Error, no volume name passed\n");
674		return 1;
675	}
676
677	if (strncmp(argv[1], "create", 6) == 0) {
678		int dynamic = 1;	/* default: dynamic volume */
679		int id = UBI_VOL_NUM_AUTO;
680
681		/* Use maximum available size */
682		size = 0;
683
684		/* E.g., create volume with "skipcheck" bit set */
685		if (argc == 7) {
686			skipcheck = strncmp(argv[6], "--skipcheck", 11) == 0;
687			argc--;
688		}
689
690		/* E.g., create volume size type vol_id */
691		if (argc == 6) {
692			id = simple_strtoull(argv[5], NULL, 16);
693			argc--;
694		}
695
696		/* E.g., create volume size type */
697		if (argc == 5) {
698			if (strncmp(argv[4], "s", 1) == 0)
699				dynamic = 0;
700			else if (strncmp(argv[4], "d", 1) != 0) {
701				printf("Incorrect type\n");
702				return 1;
703			}
704			argc--;
705		}
706		/* E.g., create volume size */
707		if (argc == 4) {
708			if (argv[3][0] != '-')
709				size = simple_strtoull(argv[3], NULL, 16);
710			argc--;
711		}
712		/* Use maximum available size */
713		if (!size) {
714			size = (int64_t)ubi->avail_pebs * ubi->leb_size;
715			printf("No size specified -> Using max size (%lld)\n", size);
716		}
717		/* E.g., create volume */
718		if (argc == 3) {
719			return ubi_create_vol(argv[2], size, dynamic, id,
720					      skipcheck);
721		}
722	}
723
724	if (strncmp(argv[1], "remove", 6) == 0) {
725		/* E.g., remove volume */
726		if (argc == 3)
727			return ubi_remove_vol(argv[2]);
728	}
729
730	if (IS_ENABLED(CONFIG_CMD_UBI_RENAME) && !strncmp(argv[1], "rename", 6))
731		return ubi_rename_vol(argv[2], argv[3]);
732
733	if (strncmp(argv[1], "skipcheck", 9) == 0) {
734		/* E.g., change skip_check flag */
735		if (argc == 4) {
736			skipcheck = strncmp(argv[3], "on", 2) == 0;
737			return ubi_set_skip_check(argv[2], skipcheck);
738		}
739	}
740
741	if (strncmp(argv[1], "write", 5) == 0) {
742		int ret;
743
744		if (argc < 5) {
745			printf("Please see usage\n");
746			return 1;
747		}
748
749		addr = hextoul(argv[2], NULL);
750		size = hextoul(argv[4], NULL);
751
752		if (strlen(argv[1]) == 10 &&
753		    strncmp(argv[1] + 5, ".part", 5) == 0) {
754			if (argc < 6) {
755				ret = ubi_volume_continue_write(argv[3],
756						(void *)addr, size);
757			} else {
758				size_t full_size;
759				full_size = hextoul(argv[5], NULL);
760				ret = ubi_volume_begin_write(argv[3],
761						(void *)addr, size, full_size);
762			}
763		} else {
764			ret = ubi_volume_write(argv[3], (void *)addr, size);
765		}
766		if (!ret) {
767			printf("%lld bytes written to volume %s\n", size,
768			       argv[3]);
769		}
770
771		return ret;
772	}
773
774	if (strncmp(argv[1], "read", 4) == 0) {
775		size = 0;
776
777		/* E.g., read volume size */
778		if (argc == 5) {
779			size = hextoul(argv[4], NULL);
780			argc--;
781		}
782
783		/* E.g., read volume */
784		if (argc == 4) {
785			addr = hextoul(argv[2], NULL);
786			argc--;
787		}
788
789		if (argc == 3) {
790			return ubi_volume_read(argv[3], (char *)addr, size);
791		}
792	}
793
794	printf("Please see usage\n");
795	return 1;
796}
797
798U_BOOT_CMD(
799	ubi, 7, 1, do_ubi,
800	"ubi commands",
801	"detach"
802		" - detach ubi from a mtd partition\n"
803	"ubi part [part] [offset]\n"
804		" - Show or set current partition (with optional VID"
805		" header offset)\n"
806	"ubi info [l[ayout]]"
807		" - Display volume and ubi layout information\n"
808	"ubi list [flags]"
809		" - print the list of volumes\n"
810	"ubi list [flags] <varname>"
811		" - set environment variable to the list of volumes"
812		" (flags can be -numeric)\n"
813	"ubi check volumename"
814		" - check if volumename exists\n"
815	"ubi create[vol] volume [size] [type] [id] [--skipcheck]\n"
816		" - create volume name with size ('-' for maximum"
817		" available size)\n"
818	"ubi write[vol] address volume size"
819		" - Write volume from address with size\n"
820	"ubi write.part address volume size [fullsize]\n"
821		" - Write part of a volume from address\n"
822	"ubi read[vol] address volume [size]"
823		" - Read volume to address with size\n"
824	"ubi remove[vol] volume"
825		" - Remove volume\n"
826#if IS_ENABLED(CONFIG_CMD_UBI_RENAME)
827	"ubi rename oldname newname\n"
828#endif
829	"ubi skipcheck volume on/off - Set or clear skip_check flag in volume header\n"
830	"[Legends]\n"
831	" volume: character name\n"
832	" size: specified in bytes\n"
833	" type: s[tatic] or d[ynamic] (default=dynamic)"
834);
835