xref: /OK3568_Linux_fs/u-boot/cmd/ubi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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