blob: 7fb4cdfc2a884ac440762e93127e3c95c8999711 [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>
Simon Glassc7694dd2019-08-01 09:46:46 -060016#include <env.h>
Kyungmin Park694a0b32008-11-19 11:47:05 +010017#include <exports.h>
Simon Glass6e295182015-09-02 17:24:57 -060018#include <memalign.h>
Miquel Raynalc58fb2c2018-09-29 12:58:29 +020019#include <mtd.h>
Kyungmin Park694a0b32008-11-19 11:47:05 +010020#include <nand.h>
21#include <onenand_uboot.h>
Simon Glass61b29b82020-02-03 07:36:15 -070022#include <dm/devres.h>
Kyungmin Park694a0b32008-11-19 11:47:05 +010023#include <linux/mtd/mtd.h>
24#include <linux/mtd/partitions.h>
Heiko Schocherff94bc42014-06-24 10:10:04 +020025#include <linux/err.h>
Kyungmin Park694a0b32008-11-19 11:47:05 +010026#include <ubi_uboot.h>
Masahiro Yamada1221ce42016-09-21 11:28:55 +090027#include <linux/errno.h>
Kyungmin Park694a0b32008-11-19 11:47:05 +010028#include <jffs2/load_kernel.h>
29
Joe Hershberger147162d2013-04-08 10:32:49 +000030#undef ubi_msg
31#define ubi_msg(fmt, ...) printf("UBI: " fmt "\n", ##__VA_ARGS__)
32
Kyungmin Park694a0b32008-11-19 11:47:05 +010033/* Private own data */
34static struct ubi_device *ubi;
Kyungmin Park694a0b32008-11-19 11:47:05 +010035
Stefan Roese2f15cfd2010-11-01 17:28:22 +010036#ifdef CONFIG_CMD_UBIFS
Tien Fong Chee10c20442018-07-06 16:25:12 +080037#include <ubifs_uboot.h>
Stefan Roese2f15cfd2010-11-01 17:28:22 +010038#endif
39
Kyungmin Park694a0b32008-11-19 11:47:05 +010040static void display_volume_info(struct ubi_device *ubi)
41{
42 int i;
43
44 for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
45 if (!ubi->volumes[i])
46 continue; /* Empty record */
47 ubi_dump_vol_info(ubi->volumes[i]);
48 }
49}
50
51static void display_ubi_info(struct ubi_device *ubi)
52{
53 ubi_msg("MTD device name: \"%s\"", ubi->mtd->name);
54 ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20);
55 ubi_msg("physical eraseblock size: %d bytes (%d KiB)",
56 ubi->peb_size, ubi->peb_size >> 10);
57 ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size);
58 ubi_msg("number of good PEBs: %d", ubi->good_peb_count);
59 ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count);
60 ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size);
61 ubi_msg("VID header offset: %d (aligned %d)",
62 ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
63 ubi_msg("data offset: %d", ubi->leb_start);
64 ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots);
65 ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD);
66 ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT);
67 ubi_msg("number of user volumes: %d",
68 ubi->vol_count - UBI_INT_VOL_COUNT);
69 ubi_msg("available PEBs: %d", ubi->avail_pebs);
70 ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs);
71 ubi_msg("number of PEBs reserved for bad PEB handling: %d",
72 ubi->beb_rsvd_pebs);
73 ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
74}
75
76static int ubi_info(int layout)
77{
78 if (layout)
79 display_volume_info(ubi);
80 else
81 display_ubi_info(ubi);
82
83 return 0;
84}
85
Heiko Schocherf9f4d802014-01-25 07:27:11 +010086static int ubi_check_volumename(const struct ubi_volume *vol, char *name)
87{
88 return strcmp(vol->name, name);
89}
90
91static int ubi_check(char *name)
92{
93 int i;
94
95 for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
96 if (!ubi->volumes[i])
97 continue; /* Empty record */
98
99 if (!ubi_check_volumename(ubi->volumes[i], name))
100 return 0;
101 }
102
Stefan Agner6d0f4522015-04-10 11:25:43 +0200103 return 1;
Heiko Schocherf9f4d802014-01-25 07:27:11 +0100104}
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
Quentin Schulz386f20c2019-09-12 16:41:01 +0200150static int ubi_create_vol(char *volume, int64_t size, int dynamic, int vol_id,
151 bool skipcheck)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100152{
153 struct ubi_mkvol_req req;
154 int err;
155
156 if (dynamic)
157 req.vol_type = UBI_DYNAMIC_VOLUME;
158 else
159 req.vol_type = UBI_STATIC_VOLUME;
160
Ladislav Michl00612422016-09-13 07:14:01 +0200161 req.vol_id = vol_id;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100162 req.alignment = 1;
163 req.bytes = size;
164
165 strcpy(req.name, volume);
166 req.name_len = strlen(volume);
167 req.name[req.name_len] = '\0';
Quentin Schulz386f20c2019-09-12 16:41:01 +0200168 req.flags = 0;
169 if (skipcheck)
170 req.flags |= UBI_VOL_SKIP_CRC_CHECK_FLG;
171
Kyungmin Park694a0b32008-11-19 11:47:05 +0100172 /* It's duplicated at drivers/mtd/ubi/cdev.c */
173 err = verify_mkvol_req(ubi, &req);
174 if (err) {
175 printf("verify_mkvol_req failed %d\n", err);
176 return err;
177 }
Paul Burtondd7185f2013-09-04 15:16:58 +0100178 printf("Creating %s volume %s of size %lld\n",
Kyungmin Park694a0b32008-11-19 11:47:05 +0100179 dynamic ? "dynamic" : "static", volume, size);
180 /* Call real ubi create volume */
181 return ubi_create_volume(ubi, &req);
182}
183
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100184static struct ubi_volume *ubi_find_volume(char *volume)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100185{
Peter Tyser3b653fd2010-04-04 22:40:50 -0500186 struct ubi_volume *vol = NULL;
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100187 int i;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100188
189 for (i = 0; i < ubi->vtbl_slots; i++) {
190 vol = ubi->volumes[i];
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100191 if (vol && !strcmp(vol->name, volume))
192 return vol;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100193 }
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100194
195 printf("Volume %s not found!\n", volume);
196 return NULL;
197}
198
199static int ubi_remove_vol(char *volume)
200{
201 int err, reserved_pebs, i;
202 struct ubi_volume *vol;
203
204 vol = ubi_find_volume(volume);
205 if (vol == NULL)
206 return ENODEV;
207
208 printf("Remove UBI volume %s (id %d)\n", vol->name, vol->vol_id);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100209
210 if (ubi->ro_mode) {
211 printf("It's read-only mode\n");
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100212 err = EROFS;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100213 goto out_err;
214 }
215
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100216 err = ubi_change_vtbl_record(ubi, vol->vol_id, NULL);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100217 if (err) {
218 printf("Error changing Vol tabel record err=%x\n", err);
219 goto out_err;
220 }
221 reserved_pebs = vol->reserved_pebs;
222 for (i = 0; i < vol->reserved_pebs; i++) {
223 err = ubi_eba_unmap_leb(ubi, vol, i);
224 if (err)
225 goto out_err;
226 }
227
228 kfree(vol->eba_tbl);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100229 ubi->volumes[vol->vol_id]->eba_tbl = NULL;
230 ubi->volumes[vol->vol_id] = NULL;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100231
232 ubi->rsvd_pebs -= reserved_pebs;
233 ubi->avail_pebs += reserved_pebs;
234 i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
235 if (i > 0) {
236 i = ubi->avail_pebs >= i ? i : ubi->avail_pebs;
237 ubi->avail_pebs -= i;
238 ubi->rsvd_pebs += i;
239 ubi->beb_rsvd_pebs += i;
240 if (i > 0)
241 ubi_msg("reserve more %d PEBs", i);
242 }
243 ubi->vol_count -= 1;
244
245 return 0;
246out_err:
Heiko Schocher0195a7b2015-10-22 06:19:21 +0200247 ubi_err(ubi, "cannot remove volume %s, error %d", volume, err);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100248 if (err < 0)
249 err = -err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100250 return err;
251}
252
Jeroen Hofstee0e350f82014-06-23 00:22:08 +0200253static int ubi_volume_continue_write(char *volume, void *buf, size_t size)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100254{
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100255 int err = 1;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100256 struct ubi_volume *vol;
257
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100258 vol = ubi_find_volume(volume);
259 if (vol == NULL)
260 return ENODEV;
261
Kyungmin Park694a0b32008-11-19 11:47:05 +0100262 err = ubi_more_update_data(ubi, vol, buf, size);
263 if (err < 0) {
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100264 printf("Couldnt or partially wrote data\n");
265 return -err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100266 }
267
268 if (err) {
269 size = err;
270
271 err = ubi_check_volume(ubi, vol->vol_id);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100272 if (err < 0)
273 return -err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100274
275 if (err) {
Heiko Schocher0195a7b2015-10-22 06:19:21 +0200276 ubi_warn(ubi, "volume %d on UBI device %d is corrupt",
277 vol->vol_id, ubi->ubi_num);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100278 vol->corrupted = 1;
279 }
280
281 vol->checked = 1;
282 ubi_gluebi_updated(vol);
283 }
284
285 return 0;
286}
287
Paul Burtoncc734f52013-09-04 15:16:59 +0100288int ubi_volume_begin_write(char *volume, void *buf, size_t size,
289 size_t full_size)
290{
291 int err = 1;
292 int rsvd_bytes = 0;
293 struct ubi_volume *vol;
294
295 vol = ubi_find_volume(volume);
296 if (vol == NULL)
297 return ENODEV;
298
299 rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad);
xypron.glpk@gmx.de18f41f22017-04-15 16:25:25 +0200300 if (size > rsvd_bytes) {
Paul Burtoncc734f52013-09-04 15:16:59 +0100301 printf("size > volume size! Aborting!\n");
302 return EINVAL;
303 }
304
305 err = ubi_start_update(ubi, vol, full_size);
306 if (err < 0) {
307 printf("Cannot start volume update\n");
308 return -err;
309 }
310
311 return ubi_volume_continue_write(volume, buf, size);
312}
313
314int ubi_volume_write(char *volume, void *buf, size_t size)
315{
316 return ubi_volume_begin_write(volume, buf, size, size);
317}
318
Joe Hershberger71829062013-04-08 10:32:47 +0000319int ubi_volume_read(char *volume, char *buf, size_t size)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100320{
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100321 int err, lnum, off, len, tbuf_size;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100322 void *tbuf;
323 unsigned long long tmp;
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100324 struct ubi_volume *vol;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100325 loff_t offp = 0;
Holger Dengler985fa932017-08-30 18:38:52 +0200326 size_t len_read;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100327
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100328 vol = ubi_find_volume(volume);
329 if (vol == NULL)
330 return ENODEV;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100331
Kyungmin Park694a0b32008-11-19 11:47:05 +0100332 if (vol->updating) {
333 printf("updating");
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100334 return EBUSY;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100335 }
336 if (vol->upd_marker) {
337 printf("damaged volume, update marker is set");
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100338 return EBADF;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100339 }
340 if (offp == vol->used_bytes)
341 return 0;
342
343 if (size == 0) {
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100344 printf("No size specified -> Using max size (%lld)\n", vol->used_bytes);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100345 size = vol->used_bytes;
346 }
347
Tom Rini13415332018-07-26 11:17:24 -0400348 printf("Read %zu bytes from volume %s to %p\n", size, volume, buf);
Stefan Agner68c70252018-06-25 11:19:12 +0200349
Kyungmin Park694a0b32008-11-19 11:47:05 +0100350 if (vol->corrupted)
351 printf("read from corrupted volume %d", vol->vol_id);
352 if (offp + size > vol->used_bytes)
Marek Vasut2984fd12011-09-30 12:13:25 +0200353 size = vol->used_bytes - offp;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100354
355 tbuf_size = vol->usable_leb_size;
356 if (size < tbuf_size)
357 tbuf_size = ALIGN(size, ubi->min_io_size);
Marcel Ziswiler45196682015-08-18 13:06:37 +0200358 tbuf = malloc_cache_aligned(tbuf_size);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100359 if (!tbuf) {
360 printf("NO MEM\n");
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100361 return ENOMEM;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100362 }
363 len = size > tbuf_size ? tbuf_size : size;
364
365 tmp = offp;
366 off = do_div(tmp, vol->usable_leb_size);
367 lnum = tmp;
Holger Dengler985fa932017-08-30 18:38:52 +0200368 len_read = size;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100369 do {
370 if (off + len >= vol->usable_leb_size)
371 len = vol->usable_leb_size - off;
372
373 err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0);
374 if (err) {
375 printf("read err %x\n", err);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100376 err = -err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100377 break;
378 }
379 off += len;
380 if (off == vol->usable_leb_size) {
381 lnum += 1;
382 off -= vol->usable_leb_size;
383 }
384
385 size -= len;
386 offp += len;
387
Kyungmin Park694a0b32008-11-19 11:47:05 +0100388 memcpy(buf, tbuf, len);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100389
390 buf += len;
391 len = size > tbuf_size ? tbuf_size : size;
392 } while (size);
393
Holger Dengler985fa932017-08-30 18:38:52 +0200394 if (!size)
395 env_set_hex("filesize", len_read);
396
Kyungmin Park694a0b32008-11-19 11:47:05 +0100397 free(tbuf);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100398 return err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100399}
400
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200401static int ubi_dev_scan(struct mtd_info *info, const char *vid_header_offset)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100402{
Simon Kagstrom25c8f402009-07-07 16:59:46 +0200403 char ubi_mtd_param_buffer[80];
Kyungmin Park694a0b32008-11-19 11:47:05 +0100404 int err;
405
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200406 if (!vid_header_offset)
407 sprintf(ubi_mtd_param_buffer, "%s", info->name);
408 else
409 sprintf(ubi_mtd_param_buffer, "%s,%s", info->name,
410 vid_header_offset);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100411
Simon Kagstrom25c8f402009-07-07 16:59:46 +0200412 err = ubi_mtd_param_parse(ubi_mtd_param_buffer, NULL);
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200413 if (err)
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100414 return -err;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100415
416 err = ubi_init();
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200417 if (err)
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100418 return -err;
Stefan Roese2ee951b2008-11-27 14:07:09 +0100419
Kyungmin Park694a0b32008-11-19 11:47:05 +0100420 return 0;
421}
422
Stefan Roesee6661cf2019-09-17 09:17:53 +0200423static int ubi_set_skip_check(char *volume, bool skip_check)
424{
425 struct ubi_vtbl_record vtbl_rec;
426 struct ubi_volume *vol;
427
428 vol = ubi_find_volume(volume);
429 if (!vol)
430 return ENODEV;
431
432 printf("%sing skip_check on volume %s\n",
433 skip_check ? "Sett" : "Clear", volume);
434
435 vtbl_rec = ubi->vtbl[vol->vol_id];
436 if (skip_check) {
437 vtbl_rec.flags |= UBI_VTBL_SKIP_CRC_CHECK_FLG;
438 vol->skip_check = 1;
439 } else {
440 vtbl_rec.flags &= ~UBI_VTBL_SKIP_CRC_CHECK_FLG;
441 vol->skip_check = 0;
442 }
443
444 return ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
445}
446
Stefan Roesed821e5e2018-10-31 12:37:20 +0100447static int ubi_detach(void)
Kyungmin Park694a0b32008-11-19 11:47:05 +0100448{
Joe Hershberger71829062013-04-08 10:32:47 +0000449#ifdef CONFIG_CMD_UBIFS
450 /*
451 * Automatically unmount UBIFS partition when user
452 * changes the UBI device. Otherwise the following
453 * UBIFS commands will crash.
454 */
455 if (ubifs_is_mounted())
456 cmd_ubifs_umount();
457#endif
458
Joe Hershberger71829062013-04-08 10:32:47 +0000459 /*
460 * Call ubi_exit() before re-initializing the UBI subsystem
461 */
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200462 if (ubi)
Joe Hershberger71829062013-04-08 10:32:47 +0000463 ubi_exit();
Joe Hershberger71829062013-04-08 10:32:47 +0000464
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200465 ubi = NULL;
466
Heiko Schochercddfc972016-06-07 08:55:40 +0200467 return 0;
468}
469
470int ubi_part(char *part_name, const char *vid_header_offset)
471{
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200472 struct mtd_info *mtd;
Heiko Schochercddfc972016-06-07 08:55:40 +0200473 int err = 0;
Heiko Schochercddfc972016-06-07 08:55:40 +0200474
475 ubi_detach();
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200476
477 mtd_probe_devices();
478 mtd = get_mtd_device_nm(part_name);
479 if (IS_ERR(mtd)) {
Joe Hershberger71829062013-04-08 10:32:47 +0000480 printf("Partition %s not found!\n", part_name);
481 return 1;
482 }
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200483 put_mtd_device(mtd);
Joe Hershberger71829062013-04-08 10:32:47 +0000484
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200485 err = ubi_dev_scan(mtd, vid_header_offset);
Joe Hershberger71829062013-04-08 10:32:47 +0000486 if (err) {
487 printf("UBI init error %d\n", err);
Stefan Roese4a94e532018-06-26 08:12:32 +0200488 printf("Please check, if the correct MTD partition is used (size big enough?)\n");
Joe Hershberger71829062013-04-08 10:32:47 +0000489 return err;
490 }
491
492 ubi = ubi_devices[0];
493
494 return 0;
495}
496
497static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
498{
Paul Burtondd7185f2013-09-04 15:16:58 +0100499 int64_t size = 0;
Joe Hershberger71829062013-04-08 10:32:47 +0000500 ulong addr = 0;
Quentin Schulz386f20c2019-09-12 16:41:01 +0200501 bool skipcheck = false;
Joe Hershberger71829062013-04-08 10:32:47 +0000502
503 if (argc < 2)
504 return CMD_RET_USAGE;
505
Heinrich Schuchardt76428562019-01-06 12:26:28 +0100506 if (strcmp(argv[1], "detach") == 0)
Heiko Schochercddfc972016-06-07 08:55:40 +0200507 return ubi_detach();
Heiko Schochercddfc972016-06-07 08:55:40 +0200508
Kyungmin Park694a0b32008-11-19 11:47:05 +0100509 if (strcmp(argv[1], "part") == 0) {
Simon Kagstrom25c8f402009-07-07 16:59:46 +0200510 const char *vid_header_offset = NULL;
Stefan Roese2d579e52009-04-24 20:24:19 +0200511
Kyungmin Park694a0b32008-11-19 11:47:05 +0100512 /* Print current partition */
513 if (argc == 2) {
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200514 if (!ubi) {
515 printf("Error, no UBI device selected!\n");
Kyungmin Park694a0b32008-11-19 11:47:05 +0100516 return 1;
517 }
518
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200519 printf("Device %d: %s, MTD partition %s\n",
520 ubi->ubi_num, ubi->ubi_name, ubi->mtd->name);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100521 return 0;
522 }
523
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200524 if (argc < 3)
Simon Glass4c12eeb2011-12-10 08:44:01 +0000525 return CMD_RET_USAGE;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100526
Simon Kagstrom25c8f402009-07-07 16:59:46 +0200527 if (argc > 3)
528 vid_header_offset = argv[3];
Kyungmin Park694a0b32008-11-19 11:47:05 +0100529
Joe Hershberger71829062013-04-08 10:32:47 +0000530 return ubi_part(argv[2], vid_header_offset);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100531 }
532
Miquel Raynalc58fb2c2018-09-29 12:58:29 +0200533 if ((strcmp(argv[1], "part") != 0) && !ubi) {
534 printf("Error, no UBI device selected!\n");
Kyungmin Park694a0b32008-11-19 11:47:05 +0100535 return 1;
536 }
537
538 if (strcmp(argv[1], "info") == 0) {
539 int layout = 0;
540 if (argc > 2 && !strncmp(argv[2], "l", 1))
541 layout = 1;
542 return ubi_info(layout);
543 }
544
Heiko Schocherf9f4d802014-01-25 07:27:11 +0100545 if (strcmp(argv[1], "check") == 0) {
546 if (argc > 2)
547 return ubi_check(argv[2]);
548
549 printf("Error, no volume name passed\n");
550 return 1;
551 }
552
Kyungmin Park694a0b32008-11-19 11:47:05 +0100553 if (strncmp(argv[1], "create", 6) == 0) {
554 int dynamic = 1; /* default: dynamic volume */
Ladislav Michl00612422016-09-13 07:14:01 +0200555 int id = UBI_VOL_NUM_AUTO;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100556
557 /* Use maximum available size */
558 size = 0;
559
Quentin Schulz386f20c2019-09-12 16:41:01 +0200560 /* E.g., create volume with "skipcheck" bit set */
561 if (argc == 7) {
562 skipcheck = strncmp(argv[6], "--skipcheck", 11) == 0;
563 argc--;
564 }
565
Ladislav Michl00612422016-09-13 07:14:01 +0200566 /* E.g., create volume size type vol_id */
567 if (argc == 6) {
568 id = simple_strtoull(argv[5], NULL, 16);
569 argc--;
570 }
571
Kyungmin Park694a0b32008-11-19 11:47:05 +0100572 /* E.g., create volume size type */
573 if (argc == 5) {
574 if (strncmp(argv[4], "s", 1) == 0)
575 dynamic = 0;
576 else if (strncmp(argv[4], "d", 1) != 0) {
577 printf("Incorrect type\n");
578 return 1;
579 }
580 argc--;
581 }
582 /* E.g., create volume size */
583 if (argc == 4) {
Ladislav Michlf59f07e2017-01-19 11:45:35 +0100584 if (argv[3][0] != '-')
585 size = simple_strtoull(argv[3], NULL, 16);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100586 argc--;
587 }
588 /* Use maximum available size */
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100589 if (!size) {
Paul Burtondd7185f2013-09-04 15:16:58 +0100590 size = (int64_t)ubi->avail_pebs * ubi->leb_size;
591 printf("No size specified -> Using max size (%lld)\n", size);
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100592 }
Kyungmin Park694a0b32008-11-19 11:47:05 +0100593 /* E.g., create volume */
Quentin Schulz386f20c2019-09-12 16:41:01 +0200594 if (argc == 3) {
595 return ubi_create_vol(argv[2], size, dynamic, id,
596 skipcheck);
597 }
Kyungmin Park694a0b32008-11-19 11:47:05 +0100598 }
599
600 if (strncmp(argv[1], "remove", 6) == 0) {
601 /* E.g., remove volume */
602 if (argc == 3)
603 return ubi_remove_vol(argv[2]);
604 }
605
Stefan Roesee6661cf2019-09-17 09:17:53 +0200606 if (strncmp(argv[1], "skipcheck", 9) == 0) {
607 /* E.g., change skip_check flag */
608 if (argc == 4) {
609 skipcheck = strncmp(argv[3], "on", 2) == 0;
610 return ubi_set_skip_check(argv[2], skipcheck);
611 }
612 }
613
Kyungmin Park694a0b32008-11-19 11:47:05 +0100614 if (strncmp(argv[1], "write", 5) == 0) {
Joe Hershberger71829062013-04-08 10:32:47 +0000615 int ret;
616
Kyungmin Park694a0b32008-11-19 11:47:05 +0100617 if (argc < 5) {
618 printf("Please see usage\n");
619 return 1;
620 }
621
622 addr = simple_strtoul(argv[2], NULL, 16);
Stefan Roesea5c40672008-11-24 08:31:16 +0100623 size = simple_strtoul(argv[4], NULL, 16);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100624
Paul Burtoncc734f52013-09-04 15:16:59 +0100625 if (strlen(argv[1]) == 10 &&
626 strncmp(argv[1] + 5, ".part", 5) == 0) {
627 if (argc < 6) {
628 ret = ubi_volume_continue_write(argv[3],
629 (void *)addr, size);
630 } else {
631 size_t full_size;
632 full_size = simple_strtoul(argv[5], NULL, 16);
633 ret = ubi_volume_begin_write(argv[3],
634 (void *)addr, size, full_size);
635 }
636 } else {
637 ret = ubi_volume_write(argv[3], (void *)addr, size);
638 }
Joe Hershberger71829062013-04-08 10:32:47 +0000639 if (!ret) {
Paul Burtondd7185f2013-09-04 15:16:58 +0100640 printf("%lld bytes written to volume %s\n", size,
Joe Hershberger71829062013-04-08 10:32:47 +0000641 argv[3]);
642 }
643
644 return ret;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100645 }
646
647 if (strncmp(argv[1], "read", 4) == 0) {
648 size = 0;
649
650 /* E.g., read volume size */
651 if (argc == 5) {
Stefan Roesea5c40672008-11-24 08:31:16 +0100652 size = simple_strtoul(argv[4], NULL, 16);
Kyungmin Park694a0b32008-11-19 11:47:05 +0100653 argc--;
654 }
655
656 /* E.g., read volume */
657 if (argc == 4) {
658 addr = simple_strtoul(argv[2], NULL, 16);
659 argc--;
660 }
661
Joe Hershberger71829062013-04-08 10:32:47 +0000662 if (argc == 3) {
Kyungmin Park694a0b32008-11-19 11:47:05 +0100663 return ubi_volume_read(argv[3], (char *)addr, size);
Joe Hershberger71829062013-04-08 10:32:47 +0000664 }
Kyungmin Park694a0b32008-11-19 11:47:05 +0100665 }
666
667 printf("Please see usage\n");
Stefan Roese7f5d8a42011-03-14 14:34:21 +0100668 return 1;
Kyungmin Park694a0b32008-11-19 11:47:05 +0100669}
670
Frans Meulenbroeks388a29d2010-07-31 15:01:53 +0200671U_BOOT_CMD(
Quentin Schulz386f20c2019-09-12 16:41:01 +0200672 ubi, 7, 1, do_ubi,
Peter Tyser2fb26042009-01-27 18:03:12 -0600673 "ubi commands",
Heiko Schochercddfc972016-06-07 08:55:40 +0200674 "detach"
675 " - detach ubi from a mtd partition\n"
676 "ubi part [part] [offset]\n"
Simon Kagstrom25c8f402009-07-07 16:59:46 +0200677 " - Show or set current partition (with optional VID"
678 " header offset)\n"
Kyungmin Park694a0b32008-11-19 11:47:05 +0100679 "ubi info [l[ayout]]"
680 " - Display volume and ubi layout information\n"
Heiko Schocherf9f4d802014-01-25 07:27:11 +0100681 "ubi check volumename"
682 " - check if volumename exists\n"
Quentin Schulz386f20c2019-09-12 16:41:01 +0200683 "ubi create[vol] volume [size] [type] [id] [--skipcheck]\n"
Ladislav Michlf59f07e2017-01-19 11:45:35 +0100684 " - create volume name with size ('-' for maximum"
685 " available size)\n"
Kyungmin Park694a0b32008-11-19 11:47:05 +0100686 "ubi write[vol] address volume size"
687 " - Write volume from address with size\n"
Paul Burtoncc734f52013-09-04 15:16:59 +0100688 "ubi write.part address volume size [fullsize]\n"
689 " - Write part of a volume from address\n"
Kyungmin Park694a0b32008-11-19 11:47:05 +0100690 "ubi read[vol] address volume [size]"
691 " - Read volume to address with size\n"
692 "ubi remove[vol] volume"
693 " - Remove volume\n"
Stefan Roesee6661cf2019-09-17 09:17:53 +0200694 "ubi skipcheck volume on/off - Set or clear skip_check flag in volume header\n"
Kyungmin Park694a0b32008-11-19 11:47:05 +0100695 "[Legends]\n"
Andrzej Wolskif6ca3b72009-07-17 22:26:54 +0200696 " volume: character name\n"
697 " size: specified in bytes\n"
Wolfgang Denka89c33d2009-05-24 17:06:54 +0200698 " type: s[tatic] or d[ynamic] (default=dynamic)"
Kyungmin Park694a0b32008-11-19 11:47:05 +0100699);