blob: bb8f97fc2815220ddfc99ba4ffc5e6e66fc5d0c4 [file] [log] [blame]
Kyungmin Park694a0b32008-11-19 11:47:05 +01001/*
2 * Unsorted Block Image commands
3 *
4 * Copyright (C) 2008 Samsung Electronics
5 * Kyungmin Park <kyungmin.park@samsung.com>
6 *
Stefan Roese2d579e52009-04-24 20:24:19 +02007 * Copyright 2008-2009 Stefan Roese <sr@denx.de>, DENX Software Engineering
Kyungmin Park694a0b32008-11-19 11:47:05 +01008 *
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 <exports.h>
Simon Glass6e295182015-09-02 17:24:57 -060017#include <memalign.h>
Miquel Raynalc58fb2c2018-09-29 12:58:29 +020018#include <mtd.h>
Kyungmin Park694a0b32008-11-19 11:47:05 +010019#include <nand.h>
20#include <onenand_uboot.h>
21#include <linux/mtd/mtd.h>
22#include <linux/mtd/partitions.h>
Heiko Schocherff94bc42014-06-24 10:10:04 +020023#include <linux/err.h>
Kyungmin Park694a0b32008-11-19 11:47:05 +010024#include <ubi_uboot.h>
Masahiro Yamada1221ce42016-09-21 11:28:55 +090025#include <linux/errno.h>
Kyungmin Park694a0b32008-11-19 11:47:05 +010026#include <jffs2/load_kernel.h>
27
Joe Hershberger147162d2013-04-08 10:32:49 +000028#undef ubi_msg
29#define ubi_msg(fmt, ...) printf("UBI: " fmt "\n", ##__VA_ARGS__)
30
Kyungmin Park694a0b32008-11-19 11:47:05 +010031/* Private own data */
32static struct ubi_device *ubi;
Kyungmin Park694a0b32008-11-19 11:47:05 +010033
Stefan Roese2f15cfd2010-11-01 17:28:22 +010034#ifdef CONFIG_CMD_UBIFS
35int ubifs_is_mounted(void);
36void cmd_ubifs_umount(void);
37#endif
38
Kyungmin Park694a0b32008-11-19 11:47:05 +010039static void display_volume_info(struct ubi_device *ubi)
40{
41 int i;
42
43 for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
44 if (!ubi->volumes[i])
45 continue; /* Empty record */
46 ubi_dump_vol_info(ubi->volumes[i]);
47 }
48}
49
50static void display_ubi_info(struct ubi_device *ubi)
51{
52 ubi_msg("MTD device name: \"%s\"", ubi->mtd->name);
53 ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20);
54 ubi_msg("physical eraseblock size: %d bytes (%d KiB)",
55 ubi->peb_size, ubi->peb_size >> 10);
56 ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size);
57 ubi_msg("number of good PEBs: %d", ubi->good_peb_count);
58 ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count);
59 ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size);
60 ubi_msg("VID header offset: %d (aligned %d)",
61 ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
62 ubi_msg("data offset: %d", ubi->leb_start);
63 ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots);
64 ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD);
65 ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT);
66 ubi_msg("number of user volumes: %d",
67 ubi->vol_count - UBI_INT_VOL_COUNT);
68 ubi_msg("available PEBs: %d", ubi->avail_pebs);
69 ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs);
70 ubi_msg("number of PEBs reserved for bad PEB handling: %d",
71 ubi->beb_rsvd_pebs);
72 ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
73}
74
75static int ubi_info(int layout)
76{
77 if (layout)
78 display_volume_info(ubi);
79 else
80 display_ubi_info(ubi);
81
82 return 0;
83}
84
Heiko Schocherf9f4d802014-01-25 07:27:11 +010085static int ubi_check_volumename(const struct ubi_volume *vol, char *name)
86{
87 return strcmp(vol->name, name);
88}
89
90static int ubi_check(char *name)
91{
92 int i;
93
94 for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
95 if (!ubi->volumes[i])
96 continue; /* Empty record */
97
98 if (!ubi_check_volumename(ubi->volumes[i], name))
99 return 0;
100 }
101
Stefan Agner6d0f4522015-04-10 11:25:43 +0200102 return 1;
Heiko Schocherf9f4d802014-01-25 07:27:11 +0100103}
104
105
Kyungmin Park694a0b32008-11-19 11:47:05 +0100106static int verify_mkvol_req(const struct ubi_device *ubi,
107 const struct ubi_mkvol_req *req)
108{
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100109 int n, err = EINVAL;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100110
111 if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 ||
112 req->name_len < 0)
113 goto bad;
114
115 if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) &&
116 req->vol_id != UBI_VOL_NUM_AUTO)
117 goto bad;
118
119 if (req->alignment == 0)
120 goto bad;
121
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100122 if (req->bytes == 0) {
123 printf("No space left in UBI device!\n");
124 err = ENOMEM;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100125 goto bad;
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100126 }
Kyungmin Park694a0b32008-11-19 11:47:05 +0100127
128 if (req->vol_type != UBI_DYNAMIC_VOLUME &&
129 req->vol_type != UBI_STATIC_VOLUME)
130 goto bad;
131
132 if (req->alignment > ubi->leb_size)
133 goto bad;
134
135 n = req->alignment % ubi->min_io_size;
136 if (req->alignment != 1 && n)
137 goto bad;
138
139 if (req->name_len > UBI_VOL_NAME_MAX) {
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100140 printf("Name too long!\n");
141 err = ENAMETOOLONG;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100142 goto bad;
143 }
144
145 return 0;
146bad:
Kyungmin Park694a0b32008-11-19 11:47:05 +0100147 return err;
148}
149
Ladislav Michl00612422016-09-13 07:14:01 +0200150static int ubi_create_vol(char *volume, int64_t size, int dynamic, int vol_id)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100151{
152 struct ubi_mkvol_req req;
153 int err;
154
155 if (dynamic)
156 req.vol_type = UBI_DYNAMIC_VOLUME;
157 else
158 req.vol_type = UBI_STATIC_VOLUME;
159
Ladislav Michl00612422016-09-13 07:14:01 +0200160 req.vol_id = vol_id;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100161 req.alignment = 1;
162 req.bytes = size;
163
164 strcpy(req.name, volume);
165 req.name_len = strlen(volume);
166 req.name[req.name_len] = '\0';
167 req.padding1 = 0;
168 /* It's duplicated at drivers/mtd/ubi/cdev.c */
169 err = verify_mkvol_req(ubi, &req);
170 if (err) {
171 printf("verify_mkvol_req failed %d\n", err);
172 return err;
173 }
Paul Burtondd7185f2013-09-04 15:16:58 +0100174 printf("Creating %s volume %s of size %lld\n",
Kyungmin Park694a0b32008-11-19 11:47:05 +0100175 dynamic ? "dynamic" : "static", volume, size);
176 /* Call real ubi create volume */
177 return ubi_create_volume(ubi, &req);
178}
179
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100180static struct ubi_volume *ubi_find_volume(char *volume)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100181{
Peter Tyser3b653fd2010-04-04 22:40:50 -0500182 struct ubi_volume *vol = NULL;
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100183 int i;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100184
185 for (i = 0; i < ubi->vtbl_slots; i++) {
186 vol = ubi->volumes[i];
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100187 if (vol && !strcmp(vol->name, volume))
188 return vol;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100189 }
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100190
191 printf("Volume %s not found!\n", volume);
192 return NULL;
193}
194
195static int ubi_remove_vol(char *volume)
196{
197 int err, reserved_pebs, i;
198 struct ubi_volume *vol;
199
200 vol = ubi_find_volume(volume);
201 if (vol == NULL)
202 return ENODEV;
203
204 printf("Remove UBI volume %s (id %d)\n", vol->name, vol->vol_id);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100205
206 if (ubi->ro_mode) {
207 printf("It's read-only mode\n");
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100208 err = EROFS;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100209 goto out_err;
210 }
211
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100212 err = ubi_change_vtbl_record(ubi, vol->vol_id, NULL);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100213 if (err) {
214 printf("Error changing Vol tabel record err=%x\n", err);
215 goto out_err;
216 }
217 reserved_pebs = vol->reserved_pebs;
218 for (i = 0; i < vol->reserved_pebs; i++) {
219 err = ubi_eba_unmap_leb(ubi, vol, i);
220 if (err)
221 goto out_err;
222 }
223
224 kfree(vol->eba_tbl);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100225 ubi->volumes[vol->vol_id]->eba_tbl = NULL;
226 ubi->volumes[vol->vol_id] = NULL;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100227
228 ubi->rsvd_pebs -= reserved_pebs;
229 ubi->avail_pebs += reserved_pebs;
230 i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
231 if (i > 0) {
232 i = ubi->avail_pebs >= i ? i : ubi->avail_pebs;
233 ubi->avail_pebs -= i;
234 ubi->rsvd_pebs += i;
235 ubi->beb_rsvd_pebs += i;
236 if (i > 0)
237 ubi_msg("reserve more %d PEBs", i);
238 }
239 ubi->vol_count -= 1;
240
241 return 0;
242out_err:
Heiko Schocher0195a7b2015-10-22 06:19:21 +0200243 ubi_err(ubi, "cannot remove volume %s, error %d", volume, err);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100244 if (err < 0)
245 err = -err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100246 return err;
247}
248
Jeroen Hofstee0e350f82014-06-23 00:22:08 +0200249static int ubi_volume_continue_write(char *volume, void *buf, size_t size)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100250{
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100251 int err = 1;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100252 struct ubi_volume *vol;
253
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100254 vol = ubi_find_volume(volume);
255 if (vol == NULL)
256 return ENODEV;
257
Kyungmin Park694a0b32008-11-19 11:47:05 +0100258 err = ubi_more_update_data(ubi, vol, buf, size);
259 if (err < 0) {
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100260 printf("Couldnt or partially wrote data\n");
261 return -err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100262 }
263
264 if (err) {
265 size = err;
266
267 err = ubi_check_volume(ubi, vol->vol_id);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100268 if (err < 0)
269 return -err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100270
271 if (err) {
Heiko Schocher0195a7b2015-10-22 06:19:21 +0200272 ubi_warn(ubi, "volume %d on UBI device %d is corrupt",
273 vol->vol_id, ubi->ubi_num);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100274 vol->corrupted = 1;
275 }
276
277 vol->checked = 1;
278 ubi_gluebi_updated(vol);
279 }
280
281 return 0;
282}
283
Paul Burtoncc734f52013-09-04 15:16:59 +0100284int ubi_volume_begin_write(char *volume, void *buf, size_t size,
285 size_t full_size)
286{
287 int err = 1;
288 int rsvd_bytes = 0;
289 struct ubi_volume *vol;
290
291 vol = ubi_find_volume(volume);
292 if (vol == NULL)
293 return ENODEV;
294
295 rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad);
xypron.glpk@gmx.de18f41f22017-04-15 16:25:25 +0200296 if (size > rsvd_bytes) {
Paul Burtoncc734f52013-09-04 15:16:59 +0100297 printf("size > volume size! Aborting!\n");
298 return EINVAL;
299 }
300
301 err = ubi_start_update(ubi, vol, full_size);
302 if (err < 0) {
303 printf("Cannot start volume update\n");
304 return -err;
305 }
306
307 return ubi_volume_continue_write(volume, buf, size);
308}
309
310int ubi_volume_write(char *volume, void *buf, size_t size)
311{
312 return ubi_volume_begin_write(volume, buf, size, size);
313}
314
Joe Hershberger71829062013-04-08 10:32:47 +0000315int ubi_volume_read(char *volume, char *buf, size_t size)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100316{
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100317 int err, lnum, off, len, tbuf_size;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100318 void *tbuf;
319 unsigned long long tmp;
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100320 struct ubi_volume *vol;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100321 loff_t offp = 0;
Holger Dengler985fa932017-08-30 18:38:52 +0200322 size_t len_read;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100323
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100324 vol = ubi_find_volume(volume);
325 if (vol == NULL)
326 return ENODEV;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100327
Kyungmin Park694a0b32008-11-19 11:47:05 +0100328 if (vol->updating) {
329 printf("updating");
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100330 return EBUSY;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100331 }
332 if (vol->upd_marker) {
333 printf("damaged volume, update marker is set");
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100334 return EBADF;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100335 }
336 if (offp == vol->used_bytes)
337 return 0;
338
339 if (size == 0) {
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100340 printf("No size specified -> Using max size (%lld)\n", vol->used_bytes);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100341 size = vol->used_bytes;
342 }
343
Tom Rini13415332018-07-26 11:17:24 -0400344 printf("Read %zu bytes from volume %s to %p\n", size, volume, buf);
Stefan Agner68c70252018-06-25 11:19:12 +0200345
Kyungmin Park694a0b32008-11-19 11:47:05 +0100346 if (vol->corrupted)
347 printf("read from corrupted volume %d", vol->vol_id);
348 if (offp + size > vol->used_bytes)
Marek Vasut2984fd12011-09-30 12:13:25 +0200349 size = vol->used_bytes - offp;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100350
351 tbuf_size = vol->usable_leb_size;
352 if (size < tbuf_size)
353 tbuf_size = ALIGN(size, ubi->min_io_size);
Marcel Ziswiler45196682015-08-18 13:06:37 +0200354 tbuf = malloc_cache_aligned(tbuf_size);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100355 if (!tbuf) {
356 printf("NO MEM\n");
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100357 return ENOMEM;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100358 }
359 len = size > tbuf_size ? tbuf_size : size;
360
361 tmp = offp;
362 off = do_div(tmp, vol->usable_leb_size);
363 lnum = tmp;
Holger Dengler985fa932017-08-30 18:38:52 +0200364 len_read = size;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100365 do {
366 if (off + len >= vol->usable_leb_size)
367 len = vol->usable_leb_size - off;
368
369 err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0);
370 if (err) {
371 printf("read err %x\n", err);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100372 err = -err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100373 break;
374 }
375 off += len;
376 if (off == vol->usable_leb_size) {
377 lnum += 1;
378 off -= vol->usable_leb_size;
379 }
380
381 size -= len;
382 offp += len;
383
Kyungmin Park694a0b32008-11-19 11:47:05 +0100384 memcpy(buf, tbuf, len);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100385
386 buf += len;
387 len = size > tbuf_size ? tbuf_size : size;
388 } while (size);
389
Holger Dengler985fa932017-08-30 18:38:52 +0200390 if (!size)
391 env_set_hex("filesize", len_read);
392
Kyungmin Park694a0b32008-11-19 11:47:05 +0100393 free(tbuf);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100394 return err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100395}
396
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200397static int ubi_dev_scan(struct mtd_info *info, const char *vid_header_offset)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100398{
Simon Kagstrom25c8f402009-07-07 16:59:46 +0200399 char ubi_mtd_param_buffer[80];
Kyungmin Park694a0b32008-11-19 11:47:05 +0100400 int err;
401
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200402 if (!vid_header_offset)
403 sprintf(ubi_mtd_param_buffer, "%s", info->name);
404 else
405 sprintf(ubi_mtd_param_buffer, "%s,%s", info->name,
406 vid_header_offset);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100407
Simon Kagstrom25c8f402009-07-07 16:59:46 +0200408 err = ubi_mtd_param_parse(ubi_mtd_param_buffer, NULL);
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200409 if (err)
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100410 return -err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100411
412 err = ubi_init();
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200413 if (err)
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100414 return -err;
Stefan Roese2ee951b2008-11-27 14:07:09 +0100415
Kyungmin Park694a0b32008-11-19 11:47:05 +0100416 return 0;
417}
418
Heiko Schochercddfc972016-06-07 08:55:40 +0200419int ubi_detach(void)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100420{
Andreas Huberc203ef52009-04-02 17:15:34 +0200421 if (mtdparts_init() != 0) {
422 printf("Error initializing mtdparts!\n");
423 return 1;
424 }
425
Joe Hershberger71829062013-04-08 10:32:47 +0000426#ifdef CONFIG_CMD_UBIFS
427 /*
428 * Automatically unmount UBIFS partition when user
429 * changes the UBI device. Otherwise the following
430 * UBIFS commands will crash.
431 */
432 if (ubifs_is_mounted())
433 cmd_ubifs_umount();
434#endif
435
Joe Hershberger71829062013-04-08 10:32:47 +0000436 /*
437 * Call ubi_exit() before re-initializing the UBI subsystem
438 */
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200439 if (ubi)
Joe Hershberger71829062013-04-08 10:32:47 +0000440 ubi_exit();
Joe Hershberger71829062013-04-08 10:32:47 +0000441
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200442 ubi = NULL;
443
Heiko Schochercddfc972016-06-07 08:55:40 +0200444 return 0;
445}
446
447int ubi_part(char *part_name, const char *vid_header_offset)
448{
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200449 struct mtd_info *mtd;
Heiko Schochercddfc972016-06-07 08:55:40 +0200450 int err = 0;
Heiko Schochercddfc972016-06-07 08:55:40 +0200451
452 ubi_detach();
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200453
454 mtd_probe_devices();
455 mtd = get_mtd_device_nm(part_name);
456 if (IS_ERR(mtd)) {
Joe Hershberger71829062013-04-08 10:32:47 +0000457 printf("Partition %s not found!\n", part_name);
458 return 1;
459 }
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200460 put_mtd_device(mtd);
Joe Hershberger71829062013-04-08 10:32:47 +0000461
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200462 err = ubi_dev_scan(mtd, vid_header_offset);
Joe Hershberger71829062013-04-08 10:32:47 +0000463 if (err) {
464 printf("UBI init error %d\n", err);
Stefan Roese4a94e532018-06-26 08:12:32 +0200465 printf("Please check, if the correct MTD partition is used (size big enough?)\n");
Joe Hershberger71829062013-04-08 10:32:47 +0000466 return err;
467 }
468
469 ubi = ubi_devices[0];
470
471 return 0;
472}
473
474static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
475{
Paul Burtondd7185f2013-09-04 15:16:58 +0100476 int64_t size = 0;
Joe Hershberger71829062013-04-08 10:32:47 +0000477 ulong addr = 0;
478
479 if (argc < 2)
480 return CMD_RET_USAGE;
481
Heiko Schochercddfc972016-06-07 08:55:40 +0200482
483 if (strcmp(argv[1], "detach") == 0) {
484 if (argc < 2)
485 return CMD_RET_USAGE;
486
487 return ubi_detach();
488 }
489
490
Kyungmin Park694a0b32008-11-19 11:47:05 +0100491 if (strcmp(argv[1], "part") == 0) {
Simon Kagstrom25c8f402009-07-07 16:59:46 +0200492 const char *vid_header_offset = NULL;
Stefan Roese2d579e52009-04-24 20:24:19 +0200493
Kyungmin Park694a0b32008-11-19 11:47:05 +0100494 /* Print current partition */
495 if (argc == 2) {
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200496 if (!ubi) {
497 printf("Error, no UBI device selected!\n");
Kyungmin Park694a0b32008-11-19 11:47:05 +0100498 return 1;
499 }
500
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200501 printf("Device %d: %s, MTD partition %s\n",
502 ubi->ubi_num, ubi->ubi_name, ubi->mtd->name);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100503 return 0;
504 }
505
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200506 if (argc < 3)
Simon Glass4c12eeb2011-12-10 08:44:01 +0000507 return CMD_RET_USAGE;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100508
Simon Kagstrom25c8f402009-07-07 16:59:46 +0200509 if (argc > 3)
510 vid_header_offset = argv[3];
Kyungmin Park694a0b32008-11-19 11:47:05 +0100511
Joe Hershberger71829062013-04-08 10:32:47 +0000512 return ubi_part(argv[2], vid_header_offset);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100513 }
514
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200515 if ((strcmp(argv[1], "part") != 0) && !ubi) {
516 printf("Error, no UBI device selected!\n");
Kyungmin Park694a0b32008-11-19 11:47:05 +0100517 return 1;
518 }
519
520 if (strcmp(argv[1], "info") == 0) {
521 int layout = 0;
522 if (argc > 2 && !strncmp(argv[2], "l", 1))
523 layout = 1;
524 return ubi_info(layout);
525 }
526
Heiko Schocherf9f4d802014-01-25 07:27:11 +0100527 if (strcmp(argv[1], "check") == 0) {
528 if (argc > 2)
529 return ubi_check(argv[2]);
530
531 printf("Error, no volume name passed\n");
532 return 1;
533 }
534
Kyungmin Park694a0b32008-11-19 11:47:05 +0100535 if (strncmp(argv[1], "create", 6) == 0) {
536 int dynamic = 1; /* default: dynamic volume */
Ladislav Michl00612422016-09-13 07:14:01 +0200537 int id = UBI_VOL_NUM_AUTO;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100538
539 /* Use maximum available size */
540 size = 0;
541
Ladislav Michl00612422016-09-13 07:14:01 +0200542 /* E.g., create volume size type vol_id */
543 if (argc == 6) {
544 id = simple_strtoull(argv[5], NULL, 16);
545 argc--;
546 }
547
Kyungmin Park694a0b32008-11-19 11:47:05 +0100548 /* E.g., create volume size type */
549 if (argc == 5) {
550 if (strncmp(argv[4], "s", 1) == 0)
551 dynamic = 0;
552 else if (strncmp(argv[4], "d", 1) != 0) {
553 printf("Incorrect type\n");
554 return 1;
555 }
556 argc--;
557 }
558 /* E.g., create volume size */
559 if (argc == 4) {
Ladislav Michlf59f07e2017-01-19 11:45:35 +0100560 if (argv[3][0] != '-')
561 size = simple_strtoull(argv[3], NULL, 16);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100562 argc--;
563 }
564 /* Use maximum available size */
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100565 if (!size) {
Paul Burtondd7185f2013-09-04 15:16:58 +0100566 size = (int64_t)ubi->avail_pebs * ubi->leb_size;
567 printf("No size specified -> Using max size (%lld)\n", size);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100568 }
Kyungmin Park694a0b32008-11-19 11:47:05 +0100569 /* E.g., create volume */
570 if (argc == 3)
Ladislav Michl00612422016-09-13 07:14:01 +0200571 return ubi_create_vol(argv[2], size, dynamic, id);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100572 }
573
574 if (strncmp(argv[1], "remove", 6) == 0) {
575 /* E.g., remove volume */
576 if (argc == 3)
577 return ubi_remove_vol(argv[2]);
578 }
579
580 if (strncmp(argv[1], "write", 5) == 0) {
Joe Hershberger71829062013-04-08 10:32:47 +0000581 int ret;
582
Kyungmin Park694a0b32008-11-19 11:47:05 +0100583 if (argc < 5) {
584 printf("Please see usage\n");
585 return 1;
586 }
587
588 addr = simple_strtoul(argv[2], NULL, 16);
Stefan Roesea5c40672008-11-24 08:31:16 +0100589 size = simple_strtoul(argv[4], NULL, 16);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100590
Paul Burtoncc734f52013-09-04 15:16:59 +0100591 if (strlen(argv[1]) == 10 &&
592 strncmp(argv[1] + 5, ".part", 5) == 0) {
593 if (argc < 6) {
594 ret = ubi_volume_continue_write(argv[3],
595 (void *)addr, size);
596 } else {
597 size_t full_size;
598 full_size = simple_strtoul(argv[5], NULL, 16);
599 ret = ubi_volume_begin_write(argv[3],
600 (void *)addr, size, full_size);
601 }
602 } else {
603 ret = ubi_volume_write(argv[3], (void *)addr, size);
604 }
Joe Hershberger71829062013-04-08 10:32:47 +0000605 if (!ret) {
Paul Burtondd7185f2013-09-04 15:16:58 +0100606 printf("%lld bytes written to volume %s\n", size,
Joe Hershberger71829062013-04-08 10:32:47 +0000607 argv[3]);
608 }
609
610 return ret;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100611 }
612
613 if (strncmp(argv[1], "read", 4) == 0) {
614 size = 0;
615
616 /* E.g., read volume size */
617 if (argc == 5) {
Stefan Roesea5c40672008-11-24 08:31:16 +0100618 size = simple_strtoul(argv[4], NULL, 16);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100619 argc--;
620 }
621
622 /* E.g., read volume */
623 if (argc == 4) {
624 addr = simple_strtoul(argv[2], NULL, 16);
625 argc--;
626 }
627
Joe Hershberger71829062013-04-08 10:32:47 +0000628 if (argc == 3) {
Kyungmin Park694a0b32008-11-19 11:47:05 +0100629 return ubi_volume_read(argv[3], (char *)addr, size);
Joe Hershberger71829062013-04-08 10:32:47 +0000630 }
Kyungmin Park694a0b32008-11-19 11:47:05 +0100631 }
632
633 printf("Please see usage\n");
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100634 return 1;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100635}
636
Frans Meulenbroeks388a29d2010-07-31 15:01:53 +0200637U_BOOT_CMD(
638 ubi, 6, 1, do_ubi,
Peter Tyser2fb26042009-01-27 18:03:12 -0600639 "ubi commands",
Heiko Schochercddfc972016-06-07 08:55:40 +0200640 "detach"
641 " - detach ubi from a mtd partition\n"
642 "ubi part [part] [offset]\n"
Simon Kagstrom25c8f402009-07-07 16:59:46 +0200643 " - Show or set current partition (with optional VID"
644 " header offset)\n"
Kyungmin Park694a0b32008-11-19 11:47:05 +0100645 "ubi info [l[ayout]]"
646 " - Display volume and ubi layout information\n"
Heiko Schocherf9f4d802014-01-25 07:27:11 +0100647 "ubi check volumename"
648 " - check if volumename exists\n"
Ladislav Michlf59f07e2017-01-19 11:45:35 +0100649 "ubi create[vol] volume [size] [type] [id]\n"
650 " - create volume name with size ('-' for maximum"
651 " available size)\n"
Kyungmin Park694a0b32008-11-19 11:47:05 +0100652 "ubi write[vol] address volume size"
653 " - Write volume from address with size\n"
Paul Burtoncc734f52013-09-04 15:16:59 +0100654 "ubi write.part address volume size [fullsize]\n"
655 " - Write part of a volume from address\n"
Kyungmin Park694a0b32008-11-19 11:47:05 +0100656 "ubi read[vol] address volume [size]"
657 " - Read volume to address with size\n"
658 "ubi remove[vol] volume"
659 " - Remove volume\n"
660 "[Legends]\n"
Andrzej Wolskif6ca3b72009-07-17 22:26:54 +0200661 " volume: character name\n"
662 " size: specified in bytes\n"
Wolfgang Denka89c33d2009-05-24 17:06:54 +0200663 " type: s[tatic] or d[ynamic] (default=dynamic)"
Kyungmin Park694a0b32008-11-19 11:47:05 +0100664);