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