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