1affae2bfSwdenk /* 2affae2bfSwdenk * (C) Copyright 2001 3affae2bfSwdenk * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4affae2bfSwdenk * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 6affae2bfSwdenk */ 7affae2bfSwdenk 8affae2bfSwdenk #include <common.h> 9affae2bfSwdenk #include <command.h> 1096e5b03cSSimon Glass #include <errno.h> 11affae2bfSwdenk #include <ide.h> 1210a37fd7SStephen Warren #include <malloc.h> 13735dd97bSGrant Likely #include <part.h> 14251cee0dSHans de Goede #include <ubifs_uboot.h> 15affae2bfSwdenk 16affae2bfSwdenk #undef PART_DEBUG 17affae2bfSwdenk 18affae2bfSwdenk #ifdef PART_DEBUG 19affae2bfSwdenk #define PRINTF(fmt,args...) printf (fmt ,##args) 20affae2bfSwdenk #else 21affae2bfSwdenk #define PRINTF(fmt,args...) 22affae2bfSwdenk #endif 23affae2bfSwdenk 24735dd97bSGrant Likely struct block_drvr { 25735dd97bSGrant Likely char *name; 264101f687SSimon Glass struct blk_desc* (*get_dev)(int dev); 27336b6f90SStephen Warren int (*select_hwpart)(int dev_num, int hwpart); 28735dd97bSGrant Likely }; 29735dd97bSGrant Likely 30735dd97bSGrant Likely static const struct block_drvr block_drvr[] = { 31cde5c64dSJon Loeliger #if defined(CONFIG_CMD_IDE) 32735dd97bSGrant Likely { .name = "ide", .get_dev = ide_get_dev, }, 33735dd97bSGrant Likely #endif 34c7057b52SDave Liu #if defined(CONFIG_CMD_SATA) 35c7057b52SDave Liu {.name = "sata", .get_dev = sata_get_dev, }, 36c7057b52SDave Liu #endif 37cde5c64dSJon Loeliger #if defined(CONFIG_CMD_SCSI) 38735dd97bSGrant Likely { .name = "scsi", .get_dev = scsi_get_dev, }, 39735dd97bSGrant Likely #endif 40cde5c64dSJon Loeliger #if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) 41735dd97bSGrant Likely { .name = "usb", .get_dev = usb_stor_get_dev, }, 42735dd97bSGrant Likely #endif 43735dd97bSGrant Likely #if defined(CONFIG_MMC) 44d2356284SStephen Warren { 45d2356284SStephen Warren .name = "mmc", 46d2356284SStephen Warren .get_dev = mmc_get_dev, 47d2356284SStephen Warren .select_hwpart = mmc_select_hwpart, 48d2356284SStephen Warren }, 49735dd97bSGrant Likely #endif 50735dd97bSGrant Likely #if defined(CONFIG_SYSTEMACE) 51735dd97bSGrant Likely { .name = "ace", .get_dev = systemace_get_dev, }, 52735dd97bSGrant Likely #endif 53f4d8de48SHenrik Nordström #if defined(CONFIG_SANDBOX) 54f4d8de48SHenrik Nordström { .name = "host", .get_dev = host_get_dev, }, 55f4d8de48SHenrik Nordström #endif 56735dd97bSGrant Likely { }, 57735dd97bSGrant Likely }; 58735dd97bSGrant Likely 59751bb571SStefan Roese DECLARE_GLOBAL_DATA_PTR; 60751bb571SStefan Roese 610c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 6296e5b03cSSimon Glass static struct part_driver *part_driver_lookup_type(int part_type) 6396e5b03cSSimon Glass { 6496e5b03cSSimon Glass struct part_driver *drv = 6596e5b03cSSimon Glass ll_entry_start(struct part_driver, part_driver); 6696e5b03cSSimon Glass const int n_ents = ll_entry_count(struct part_driver, part_driver); 6796e5b03cSSimon Glass struct part_driver *entry; 6896e5b03cSSimon Glass 6996e5b03cSSimon Glass for (entry = drv; entry != drv + n_ents; entry++) { 7096e5b03cSSimon Glass if (part_type == entry->part_type) 7196e5b03cSSimon Glass return entry; 7296e5b03cSSimon Glass } 7396e5b03cSSimon Glass 7496e5b03cSSimon Glass /* Not found */ 7596e5b03cSSimon Glass return NULL; 7696e5b03cSSimon Glass } 7796e5b03cSSimon Glass 784101f687SSimon Glass static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 79735dd97bSGrant Likely { 80735dd97bSGrant Likely const struct block_drvr *drvr = block_drvr; 814101f687SSimon Glass struct blk_desc* (*reloc_get_dev)(int dev); 82336b6f90SStephen Warren int (*select_hwpart)(int dev_num, int hwpart); 8323090dacSHeiko Schocher char *name; 84336b6f90SStephen Warren int ret; 85751bb571SStefan Roese 867e71dc68STim Kientzle if (!ifname) 877e71dc68STim Kientzle return NULL; 887e71dc68STim Kientzle 8923090dacSHeiko Schocher name = drvr->name; 902e5167ccSWolfgang Denk #ifdef CONFIG_NEEDS_MANUAL_RELOC 9123090dacSHeiko Schocher name += gd->reloc_off; 9223090dacSHeiko Schocher #endif 93b16aadf4SLei Wen while (drvr->name) { 9423090dacSHeiko Schocher name = drvr->name; 95521af04dSPeter Tyser reloc_get_dev = drvr->get_dev; 96336b6f90SStephen Warren select_hwpart = drvr->select_hwpart; 972e5167ccSWolfgang Denk #ifdef CONFIG_NEEDS_MANUAL_RELOC 9823090dacSHeiko Schocher name += gd->reloc_off; 99521af04dSPeter Tyser reloc_get_dev += gd->reloc_off; 100336b6f90SStephen Warren if (select_hwpart) 101336b6f90SStephen Warren select_hwpart += gd->reloc_off; 102521af04dSPeter Tyser #endif 103336b6f90SStephen Warren if (strncmp(ifname, name, strlen(name)) == 0) { 1044101f687SSimon Glass struct blk_desc *dev_desc = reloc_get_dev(dev); 105336b6f90SStephen Warren if (!dev_desc) 106336b6f90SStephen Warren return NULL; 107ecdd57e2SStephen Warren if (hwpart == 0 && !select_hwpart) 108336b6f90SStephen Warren return dev_desc; 109336b6f90SStephen Warren if (!select_hwpart) 110336b6f90SStephen Warren return NULL; 111336b6f90SStephen Warren ret = select_hwpart(dev_desc->dev, hwpart); 112336b6f90SStephen Warren if (ret < 0) 113336b6f90SStephen Warren return NULL; 114336b6f90SStephen Warren return dev_desc; 115336b6f90SStephen Warren } 116735dd97bSGrant Likely drvr++; 117735dd97bSGrant Likely } 118735dd97bSGrant Likely return NULL; 119735dd97bSGrant Likely } 120336b6f90SStephen Warren 121db1d9e78SSimon Glass struct blk_desc *blk_get_dev(const char *ifname, int dev) 122336b6f90SStephen Warren { 123ecdd57e2SStephen Warren return get_dev_hwpart(ifname, dev, 0); 124336b6f90SStephen Warren } 125735dd97bSGrant Likely #else 1264101f687SSimon Glass struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 127336b6f90SStephen Warren { 128336b6f90SStephen Warren return NULL; 129336b6f90SStephen Warren } 130336b6f90SStephen Warren 131db1d9e78SSimon Glass struct blk_desc *blk_get_dev(const char *ifname, int dev) 132735dd97bSGrant Likely { 133735dd97bSGrant Likely return NULL; 134735dd97bSGrant Likely } 135735dd97bSGrant Likely #endif 136735dd97bSGrant Likely 1370c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 138735dd97bSGrant Likely 139affae2bfSwdenk /* ------------------------------------------------------------------------- */ 140affae2bfSwdenk /* 141affae2bfSwdenk * reports device info to the user 142affae2bfSwdenk */ 14369a2a4d9SSergei Trofimovich 14469a2a4d9SSergei Trofimovich #ifdef CONFIG_LBA48 14569a2a4d9SSergei Trofimovich typedef uint64_t lba512_t; 14669a2a4d9SSergei Trofimovich #else 14769a2a4d9SSergei Trofimovich typedef lbaint_t lba512_t; 14869a2a4d9SSergei Trofimovich #endif 14969a2a4d9SSergei Trofimovich 15069a2a4d9SSergei Trofimovich /* 15169a2a4d9SSergei Trofimovich * Overflowless variant of (block_count * mul_by / div_by) 15269a2a4d9SSergei Trofimovich * when div_by > mul_by 15369a2a4d9SSergei Trofimovich */ 15469a2a4d9SSergei Trofimovich static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, lba512_t div_by) 15569a2a4d9SSergei Trofimovich { 15669a2a4d9SSergei Trofimovich lba512_t bc_quot, bc_rem; 15769a2a4d9SSergei Trofimovich 15869a2a4d9SSergei Trofimovich /* x * m / d == x / d * m + (x % d) * m / d */ 15969a2a4d9SSergei Trofimovich bc_quot = block_count / div_by; 16069a2a4d9SSergei Trofimovich bc_rem = block_count - div_by * bc_quot; 16169a2a4d9SSergei Trofimovich return bc_quot * mul_by + (bc_rem * mul_by) / div_by; 16269a2a4d9SSergei Trofimovich } 16369a2a4d9SSergei Trofimovich 1644101f687SSimon Glass void dev_print (struct blk_desc *dev_desc) 165affae2bfSwdenk { 16669a2a4d9SSergei Trofimovich lba512_t lba512; /* number of blocks if 512bytes block size */ 167affae2bfSwdenk 168af75a45dSWolfgang Denk if (dev_desc->type == DEV_TYPE_UNKNOWN) { 169af75a45dSWolfgang Denk puts ("not available\n"); 170af75a45dSWolfgang Denk return; 171af75a45dSWolfgang Denk } 172af75a45dSWolfgang Denk 1738ec6e332STor Krill switch (dev_desc->if_type) { 174574b3195SDetlev Zundel case IF_TYPE_SCSI: 175574b3195SDetlev Zundel printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n", 176574b3195SDetlev Zundel dev_desc->target,dev_desc->lun, 177affae2bfSwdenk dev_desc->vendor, 178affae2bfSwdenk dev_desc->product, 179affae2bfSwdenk dev_desc->revision); 180574b3195SDetlev Zundel break; 1816e24a1ebSRemy Bohmer case IF_TYPE_ATAPI: 182574b3195SDetlev Zundel case IF_TYPE_IDE: 183574b3195SDetlev Zundel case IF_TYPE_SATA: 184574b3195SDetlev Zundel printf ("Model: %s Firm: %s Ser#: %s\n", 185574b3195SDetlev Zundel dev_desc->vendor, 186574b3195SDetlev Zundel dev_desc->revision, 187574b3195SDetlev Zundel dev_desc->product); 188574b3195SDetlev Zundel break; 1896e24a1ebSRemy Bohmer case IF_TYPE_SD: 1906e24a1ebSRemy Bohmer case IF_TYPE_MMC: 19147bebe34SNícolas Carneiro Lebedenco case IF_TYPE_USB: 19247bebe34SNícolas Carneiro Lebedenco printf ("Vendor: %s Rev: %s Prod: %s\n", 19347bebe34SNícolas Carneiro Lebedenco dev_desc->vendor, 19447bebe34SNícolas Carneiro Lebedenco dev_desc->revision, 19547bebe34SNícolas Carneiro Lebedenco dev_desc->product); 19647bebe34SNícolas Carneiro Lebedenco break; 1976e24a1ebSRemy Bohmer case IF_TYPE_DOC: 1986e24a1ebSRemy Bohmer puts("device type DOC\n"); 1996e24a1ebSRemy Bohmer return; 2008ec6e332STor Krill case IF_TYPE_UNKNOWN: 2016e24a1ebSRemy Bohmer puts("device type unknown\n"); 2026e24a1ebSRemy Bohmer return; 203574b3195SDetlev Zundel default: 2046e24a1ebSRemy Bohmer printf("Unhandled device type: %i\n", dev_desc->if_type); 205574b3195SDetlev Zundel return; 206affae2bfSwdenk } 207affae2bfSwdenk puts (" Type: "); 208affae2bfSwdenk if (dev_desc->removable) 209affae2bfSwdenk puts ("Removable "); 210affae2bfSwdenk switch (dev_desc->type & 0x1F) { 211726c0f1eSDetlev Zundel case DEV_TYPE_HARDDISK: 212726c0f1eSDetlev Zundel puts ("Hard Disk"); 213affae2bfSwdenk break; 214726c0f1eSDetlev Zundel case DEV_TYPE_CDROM: 215726c0f1eSDetlev Zundel puts ("CD ROM"); 216affae2bfSwdenk break; 217726c0f1eSDetlev Zundel case DEV_TYPE_OPDISK: 218726c0f1eSDetlev Zundel puts ("Optical Device"); 219affae2bfSwdenk break; 220726c0f1eSDetlev Zundel case DEV_TYPE_TAPE: 221726c0f1eSDetlev Zundel puts ("Tape"); 222affae2bfSwdenk break; 223726c0f1eSDetlev Zundel default: 224726c0f1eSDetlev Zundel printf ("# %02X #", dev_desc->type & 0x1F); 225affae2bfSwdenk break; 226affae2bfSwdenk } 227affae2bfSwdenk puts ("\n"); 22833699df1SJerry Huang if (dev_desc->lba > 0L && dev_desc->blksz > 0L) { 229affae2bfSwdenk ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem; 230c40b2956Swdenk lbaint_t lba; 2316e592385Swdenk 232c40b2956Swdenk lba = dev_desc->lba; 233affae2bfSwdenk 234c40b2956Swdenk lba512 = (lba * (dev_desc->blksz/512)); 235affae2bfSwdenk /* round to 1 digit */ 236214b3f31SPavel Machek /* 2048 = (1024 * 1024) / 512 MB */ 237214b3f31SPavel Machek mb = lba512_muldiv(lba512, 10, 2048); 23869a2a4d9SSergei Trofimovich 239affae2bfSwdenk mb_quot = mb / 10; 240affae2bfSwdenk mb_rem = mb - (10 * mb_quot); 241affae2bfSwdenk 242affae2bfSwdenk gb = mb / 1024; 243affae2bfSwdenk gb_quot = gb / 10; 244affae2bfSwdenk gb_rem = gb - (10 * gb_quot); 24542dfe7a1Swdenk #ifdef CONFIG_LBA48 2466e592385Swdenk if (dev_desc->lba48) 247c40b2956Swdenk printf (" Supports 48-bit addressing\n"); 248c40b2956Swdenk #endif 2494b142febSHeiko Schocher #if defined(CONFIG_SYS_64BIT_LBA) 2506c6166f5SMike Frysinger printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n", 251c40b2956Swdenk mb_quot, mb_rem, 252c40b2956Swdenk gb_quot, gb_rem, 253c40b2956Swdenk lba, 254c40b2956Swdenk dev_desc->blksz); 255c40b2956Swdenk #else 256affae2bfSwdenk printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n", 257affae2bfSwdenk mb_quot, mb_rem, 258affae2bfSwdenk gb_quot, gb_rem, 259c40b2956Swdenk (ulong)lba, 260affae2bfSwdenk dev_desc->blksz); 261c40b2956Swdenk #endif 262affae2bfSwdenk } else { 263affae2bfSwdenk puts (" Capacity: not available\n"); 264affae2bfSwdenk } 265affae2bfSwdenk } 266b3aff0cbSJon Loeliger #endif 267affae2bfSwdenk 2680c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 269affae2bfSwdenk 270*3e8bd469SSimon Glass void part_init(struct blk_desc *dev_desc) 271affae2bfSwdenk { 27296e5b03cSSimon Glass struct part_driver *drv = 27396e5b03cSSimon Glass ll_entry_start(struct part_driver, part_driver); 27496e5b03cSSimon Glass const int n_ents = ll_entry_count(struct part_driver, part_driver); 27596e5b03cSSimon Glass struct part_driver *entry; 276affae2bfSwdenk 27799d2c205SRob Herring dev_desc->part_type = PART_TYPE_UNKNOWN; 27896e5b03cSSimon Glass for (entry = drv; entry != drv + n_ents; entry++) { 27996e5b03cSSimon Glass int ret; 28096e5b03cSSimon Glass 28196e5b03cSSimon Glass ret = entry->test(dev_desc); 28296e5b03cSSimon Glass debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret); 28396e5b03cSSimon Glass if (!ret) { 28496e5b03cSSimon Glass dev_desc->part_type = entry->part_type; 28596e5b03cSSimon Glass break; 28696e5b03cSSimon Glass } 28796e5b03cSSimon Glass } 288affae2bfSwdenk } 289affae2bfSwdenk 29096e5b03cSSimon Glass static void print_part_header(const char *type, struct blk_desc *dev_desc) 29196e5b03cSSimon Glass { 2920c9c8fb5SGabe Black #if defined(CONFIG_MAC_PARTITION) || \ 2930c9c8fb5SGabe Black defined(CONFIG_DOS_PARTITION) || \ 2940c9c8fb5SGabe Black defined(CONFIG_ISO_PARTITION) || \ 2950c9c8fb5SGabe Black defined(CONFIG_AMIGA_PARTITION) || \ 2960c9c8fb5SGabe Black defined(CONFIG_EFI_PARTITION) 297affae2bfSwdenk puts ("\nPartition Map for "); 298affae2bfSwdenk switch (dev_desc->if_type) { 299726c0f1eSDetlev Zundel case IF_TYPE_IDE: 300726c0f1eSDetlev Zundel puts ("IDE"); 301affae2bfSwdenk break; 302726c0f1eSDetlev Zundel case IF_TYPE_SATA: 303726c0f1eSDetlev Zundel puts ("SATA"); 304c7057b52SDave Liu break; 305726c0f1eSDetlev Zundel case IF_TYPE_SCSI: 306726c0f1eSDetlev Zundel puts ("SCSI"); 307affae2bfSwdenk break; 308726c0f1eSDetlev Zundel case IF_TYPE_ATAPI: 309726c0f1eSDetlev Zundel puts ("ATAPI"); 310affae2bfSwdenk break; 311726c0f1eSDetlev Zundel case IF_TYPE_USB: 312726c0f1eSDetlev Zundel puts ("USB"); 313affae2bfSwdenk break; 314726c0f1eSDetlev Zundel case IF_TYPE_DOC: 315726c0f1eSDetlev Zundel puts ("DOC"); 316affae2bfSwdenk break; 3178f3b9642SLei Wen case IF_TYPE_MMC: 3188f3b9642SLei Wen puts ("MMC"); 3198f3b9642SLei Wen break; 320f4d8de48SHenrik Nordström case IF_TYPE_HOST: 321f4d8de48SHenrik Nordström puts("HOST"); 322f4d8de48SHenrik Nordström break; 323726c0f1eSDetlev Zundel default: 324726c0f1eSDetlev Zundel puts ("UNKNOWN"); 325affae2bfSwdenk break; 326affae2bfSwdenk } 327affae2bfSwdenk printf (" device %d -- Partition Type: %s\n\n", 328affae2bfSwdenk dev_desc->dev, type); 3290c9c8fb5SGabe Black #endif /* any CONFIG_..._PARTITION */ 33096e5b03cSSimon Glass } 3310c9c8fb5SGabe Black 332*3e8bd469SSimon Glass void part_print(struct blk_desc *dev_desc) 333affae2bfSwdenk { 33496e5b03cSSimon Glass struct part_driver *drv; 335affae2bfSwdenk 33696e5b03cSSimon Glass drv = part_driver_lookup_type(dev_desc->part_type); 33796e5b03cSSimon Glass if (!drv) { 33896e5b03cSSimon Glass printf("## Unknown partition table type %x\n", 33996e5b03cSSimon Glass dev_desc->part_type); 340affae2bfSwdenk return; 341affae2bfSwdenk } 34296e5b03cSSimon Glass 34396e5b03cSSimon Glass PRINTF("## Testing for valid %s partition ##\n", drv->name); 34496e5b03cSSimon Glass print_part_header(drv->name, dev_desc); 34596e5b03cSSimon Glass if (drv->print) 34696e5b03cSSimon Glass drv->print(dev_desc); 347affae2bfSwdenk } 348affae2bfSwdenk 3490c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 3502f501646SStephen Warren 351*3e8bd469SSimon Glass int part_get_info(struct blk_desc *dev_desc, int part, 3523f9eb6e1SPavel Machek disk_partition_t *info) 3532f501646SStephen Warren { 3540c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 35596e5b03cSSimon Glass struct part_driver *drv; 3562f501646SStephen Warren 357894bfbbfSStephen Warren #ifdef CONFIG_PARTITION_UUIDS 358894bfbbfSStephen Warren /* The common case is no UUID support */ 359894bfbbfSStephen Warren info->uuid[0] = 0; 360894bfbbfSStephen Warren #endif 3617561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 3627561b258SPatrick Delaunay info->type_guid[0] = 0; 3637561b258SPatrick Delaunay #endif 364894bfbbfSStephen Warren 36596e5b03cSSimon Glass drv = part_driver_lookup_type(dev_desc->part_type); 36696e5b03cSSimon Glass if (!drv) { 36796e5b03cSSimon Glass debug("## Unknown partition table type %x\n", 36896e5b03cSSimon Glass dev_desc->part_type); 36996e5b03cSSimon Glass return -EPROTONOSUPPORT; 3702f501646SStephen Warren } 37196e5b03cSSimon Glass if (!drv->get_info) { 37296e5b03cSSimon Glass PRINTF("## Driver %s does not have the get_info() method\n"); 37396e5b03cSSimon Glass return -ENOSYS; 3742f501646SStephen Warren } 37596e5b03cSSimon Glass if (drv->get_info(dev_desc, part, info) == 0) { 37696e5b03cSSimon Glass PRINTF("## Valid %s partition found ##\n", drv->name); 3772f501646SStephen Warren return 0; 3782f501646SStephen Warren } 3790c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 3802f501646SStephen Warren 3812f501646SStephen Warren return -1; 3822f501646SStephen Warren } 38399d2c205SRob Herring 384ebac37cfSSimon Glass int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, 3854101f687SSimon Glass struct blk_desc **dev_desc) 3862023e608SStephen Warren { 3872023e608SStephen Warren char *ep; 388336b6f90SStephen Warren char *dup_str = NULL; 389336b6f90SStephen Warren const char *dev_str, *hwpart_str; 390336b6f90SStephen Warren int dev, hwpart; 391336b6f90SStephen Warren 392336b6f90SStephen Warren hwpart_str = strchr(dev_hwpart_str, '.'); 393336b6f90SStephen Warren if (hwpart_str) { 394336b6f90SStephen Warren dup_str = strdup(dev_hwpart_str); 395336b6f90SStephen Warren dup_str[hwpart_str - dev_hwpart_str] = 0; 396336b6f90SStephen Warren dev_str = dup_str; 397336b6f90SStephen Warren hwpart_str++; 398336b6f90SStephen Warren } else { 399336b6f90SStephen Warren dev_str = dev_hwpart_str; 400ecdd57e2SStephen Warren hwpart = 0; 401336b6f90SStephen Warren } 4022023e608SStephen Warren 4032023e608SStephen Warren dev = simple_strtoul(dev_str, &ep, 16); 4042023e608SStephen Warren if (*ep) { 4052023e608SStephen Warren printf("** Bad device specification %s %s **\n", 4062023e608SStephen Warren ifname, dev_str); 407336b6f90SStephen Warren dev = -1; 408336b6f90SStephen Warren goto cleanup; 4092023e608SStephen Warren } 4102023e608SStephen Warren 411336b6f90SStephen Warren if (hwpart_str) { 412336b6f90SStephen Warren hwpart = simple_strtoul(hwpart_str, &ep, 16); 413336b6f90SStephen Warren if (*ep) { 414336b6f90SStephen Warren printf("** Bad HW partition specification %s %s **\n", 415336b6f90SStephen Warren ifname, hwpart_str); 416336b6f90SStephen Warren dev = -1; 417336b6f90SStephen Warren goto cleanup; 418336b6f90SStephen Warren } 419336b6f90SStephen Warren } 420336b6f90SStephen Warren 421336b6f90SStephen Warren *dev_desc = get_dev_hwpart(ifname, dev, hwpart); 4222023e608SStephen Warren if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { 423336b6f90SStephen Warren printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); 424336b6f90SStephen Warren dev = -1; 425336b6f90SStephen Warren goto cleanup; 4262023e608SStephen Warren } 4272023e608SStephen Warren 42899e7fc8aSErik Tideman #ifdef HAVE_BLOCK_DEVICE 42999e7fc8aSErik Tideman /* 43099e7fc8aSErik Tideman * Updates the partition table for the specified hw partition. 43199e7fc8aSErik Tideman * Does not need to be done for hwpart 0 since it is default and 43299e7fc8aSErik Tideman * already loaded. 43399e7fc8aSErik Tideman */ 43499e7fc8aSErik Tideman if(hwpart != 0) 435*3e8bd469SSimon Glass part_init(*dev_desc); 43699e7fc8aSErik Tideman #endif 43799e7fc8aSErik Tideman 438336b6f90SStephen Warren cleanup: 439336b6f90SStephen Warren free(dup_str); 4402023e608SStephen Warren return dev; 4412023e608SStephen Warren } 4422023e608SStephen Warren 44310a37fd7SStephen Warren #define PART_UNSPECIFIED -2 44410a37fd7SStephen Warren #define PART_AUTO -1 44510a37fd7SStephen Warren #define MAX_SEARCH_PARTITIONS 16 446e35929e4SSimon Glass int blk_get_device_part_str(const char *ifname, const char *dev_part_str, 4474101f687SSimon Glass struct blk_desc **dev_desc, 44810a37fd7SStephen Warren disk_partition_t *info, int allow_whole_dev) 44999d2c205SRob Herring { 45010a37fd7SStephen Warren int ret = -1; 45110a37fd7SStephen Warren const char *part_str; 45210a37fd7SStephen Warren char *dup_str = NULL; 45310a37fd7SStephen Warren const char *dev_str; 45499d2c205SRob Herring int dev; 45510a37fd7SStephen Warren char *ep; 45610a37fd7SStephen Warren int p; 45710a37fd7SStephen Warren int part; 45810a37fd7SStephen Warren disk_partition_t tmpinfo; 45999d2c205SRob Herring 460251cee0dSHans de Goede #if defined CONFIG_SANDBOX && defined CONFIG_CMD_UBIFS 461251cee0dSHans de Goede #error Only one of CONFIG_SANDBOX and CONFIG_CMD_UBIFS may be selected 462251cee0dSHans de Goede #endif 463251cee0dSHans de Goede 464afc1744eSHans de Goede #ifdef CONFIG_SANDBOX 4654d907025SStephen Warren /* 4663f9eb6e1SPavel Machek * Special-case a pseudo block device "hostfs", to allow access to the 4674d907025SStephen Warren * host's own filesystem. 4684d907025SStephen Warren */ 4694d907025SStephen Warren if (0 == strcmp(ifname, "hostfs")) { 4704d907025SStephen Warren *dev_desc = NULL; 4714d907025SStephen Warren info->start = 0; 4724d907025SStephen Warren info->size = 0; 4734d907025SStephen Warren info->blksz = 0; 4744d907025SStephen Warren info->bootable = 0; 4754d907025SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 4764d907025SStephen Warren strcpy((char *)info->name, "Sandbox host"); 4774d907025SStephen Warren #ifdef CONFIG_PARTITION_UUIDS 4784d907025SStephen Warren info->uuid[0] = 0; 4794d907025SStephen Warren #endif 4807561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 4817561b258SPatrick Delaunay info->type_guid[0] = 0; 4827561b258SPatrick Delaunay #endif 4834d907025SStephen Warren 4844d907025SStephen Warren return 0; 4854d907025SStephen Warren } 486afc1744eSHans de Goede #endif 4874d907025SStephen Warren 488251cee0dSHans de Goede #ifdef CONFIG_CMD_UBIFS 489251cee0dSHans de Goede /* 490251cee0dSHans de Goede * Special-case ubi, ubi goes through a mtd, rathen then through 491251cee0dSHans de Goede * a regular block device. 492251cee0dSHans de Goede */ 493251cee0dSHans de Goede if (0 == strcmp(ifname, "ubi")) { 494251cee0dSHans de Goede if (!ubifs_is_mounted()) { 495251cee0dSHans de Goede printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); 496251cee0dSHans de Goede return -1; 497251cee0dSHans de Goede } 498251cee0dSHans de Goede 499251cee0dSHans de Goede *dev_desc = NULL; 500251cee0dSHans de Goede memset(info, 0, sizeof(*info)); 501251cee0dSHans de Goede strcpy((char *)info->type, BOOT_PART_TYPE); 502251cee0dSHans de Goede strcpy((char *)info->name, "UBI"); 503251cee0dSHans de Goede #ifdef CONFIG_PARTITION_UUIDS 504251cee0dSHans de Goede info->uuid[0] = 0; 505251cee0dSHans de Goede #endif 506251cee0dSHans de Goede return 0; 507251cee0dSHans de Goede } 508251cee0dSHans de Goede #endif 509251cee0dSHans de Goede 51010a37fd7SStephen Warren /* If no dev_part_str, use bootdevice environment variable */ 511a10973e7SStephen Warren if (!dev_part_str || !strlen(dev_part_str) || 512a10973e7SStephen Warren !strcmp(dev_part_str, "-")) 51310a37fd7SStephen Warren dev_part_str = getenv("bootdevice"); 51499d2c205SRob Herring 51510a37fd7SStephen Warren /* If still no dev_part_str, it's an error */ 51610a37fd7SStephen Warren if (!dev_part_str) { 51710a37fd7SStephen Warren printf("** No device specified **\n"); 51810a37fd7SStephen Warren goto cleanup; 51999d2c205SRob Herring } 52099d2c205SRob Herring 52110a37fd7SStephen Warren /* Separate device and partition ID specification */ 52210a37fd7SStephen Warren part_str = strchr(dev_part_str, ':'); 52310a37fd7SStephen Warren if (part_str) { 52410a37fd7SStephen Warren dup_str = strdup(dev_part_str); 52510a37fd7SStephen Warren dup_str[part_str - dev_part_str] = 0; 52610a37fd7SStephen Warren dev_str = dup_str; 52710a37fd7SStephen Warren part_str++; 52810a37fd7SStephen Warren } else { 52910a37fd7SStephen Warren dev_str = dev_part_str; 53099d2c205SRob Herring } 53110a37fd7SStephen Warren 53210a37fd7SStephen Warren /* Look up the device */ 533ebac37cfSSimon Glass dev = blk_get_device_by_str(ifname, dev_str, dev_desc); 53410a37fd7SStephen Warren if (dev < 0) 53510a37fd7SStephen Warren goto cleanup; 53610a37fd7SStephen Warren 53710a37fd7SStephen Warren /* Convert partition ID string to number */ 53810a37fd7SStephen Warren if (!part_str || !*part_str) { 53910a37fd7SStephen Warren part = PART_UNSPECIFIED; 54010a37fd7SStephen Warren } else if (!strcmp(part_str, "auto")) { 54110a37fd7SStephen Warren part = PART_AUTO; 54210a37fd7SStephen Warren } else { 54310a37fd7SStephen Warren /* Something specified -> use exactly that */ 54410a37fd7SStephen Warren part = (int)simple_strtoul(part_str, &ep, 16); 54510a37fd7SStephen Warren /* 54610a37fd7SStephen Warren * Less than whole string converted, 54710a37fd7SStephen Warren * or request for whole device, but caller requires partition. 54810a37fd7SStephen Warren */ 54910a37fd7SStephen Warren if (*ep || (part == 0 && !allow_whole_dev)) { 55010a37fd7SStephen Warren printf("** Bad partition specification %s %s **\n", 55110a37fd7SStephen Warren ifname, dev_part_str); 55210a37fd7SStephen Warren goto cleanup; 55310a37fd7SStephen Warren } 55410a37fd7SStephen Warren } 55510a37fd7SStephen Warren 55610a37fd7SStephen Warren /* 55710a37fd7SStephen Warren * No partition table on device, 55810a37fd7SStephen Warren * or user requested partition 0 (entire device). 55910a37fd7SStephen Warren */ 56010a37fd7SStephen Warren if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 56110a37fd7SStephen Warren (part == 0)) { 56210a37fd7SStephen Warren if (!(*dev_desc)->lba) { 56310a37fd7SStephen Warren printf("** Bad device size - %s %s **\n", ifname, 56410a37fd7SStephen Warren dev_str); 56510a37fd7SStephen Warren goto cleanup; 56610a37fd7SStephen Warren } 56710a37fd7SStephen Warren 56810a37fd7SStephen Warren /* 56910a37fd7SStephen Warren * If user specified a partition ID other than 0, 57010a37fd7SStephen Warren * or the calling command only accepts partitions, 57110a37fd7SStephen Warren * it's an error. 57210a37fd7SStephen Warren */ 57310a37fd7SStephen Warren if ((part > 0) || (!allow_whole_dev)) { 57410a37fd7SStephen Warren printf("** No partition table - %s %s **\n", ifname, 57510a37fd7SStephen Warren dev_str); 57610a37fd7SStephen Warren goto cleanup; 57710a37fd7SStephen Warren } 57810a37fd7SStephen Warren 57950ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 58050ffc3b6SLan Yixun (dlan) 58199d2c205SRob Herring info->start = 0; 58210a37fd7SStephen Warren info->size = (*dev_desc)->lba; 58310a37fd7SStephen Warren info->blksz = (*dev_desc)->blksz; 58410a37fd7SStephen Warren info->bootable = 0; 5856ab6a650SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 5866ab6a650SStephen Warren strcpy((char *)info->name, "Whole Disk"); 58710a37fd7SStephen Warren #ifdef CONFIG_PARTITION_UUIDS 58810a37fd7SStephen Warren info->uuid[0] = 0; 58910a37fd7SStephen Warren #endif 5907561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 5917561b258SPatrick Delaunay info->type_guid[0] = 0; 5927561b258SPatrick Delaunay #endif 59399d2c205SRob Herring 59410a37fd7SStephen Warren ret = 0; 59510a37fd7SStephen Warren goto cleanup; 59699d2c205SRob Herring } 59799d2c205SRob Herring 59810a37fd7SStephen Warren /* 59910a37fd7SStephen Warren * Now there's known to be a partition table, 60010a37fd7SStephen Warren * not specifying a partition means to pick partition 1. 60110a37fd7SStephen Warren */ 60210a37fd7SStephen Warren if (part == PART_UNSPECIFIED) 60310a37fd7SStephen Warren part = 1; 60499d2c205SRob Herring 60510a37fd7SStephen Warren /* 60610a37fd7SStephen Warren * If user didn't specify a partition number, or did specify something 60710a37fd7SStephen Warren * other than "auto", use that partition number directly. 60810a37fd7SStephen Warren */ 60910a37fd7SStephen Warren if (part != PART_AUTO) { 610*3e8bd469SSimon Glass ret = part_get_info(*dev_desc, part, info); 61199d2c205SRob Herring if (ret) { 61210a37fd7SStephen Warren printf("** Invalid partition %d **\n", part); 61310a37fd7SStephen Warren goto cleanup; 61410a37fd7SStephen Warren } 61510a37fd7SStephen Warren } else { 61610a37fd7SStephen Warren /* 61710a37fd7SStephen Warren * Find the first bootable partition. 61810a37fd7SStephen Warren * If none are bootable, fall back to the first valid partition. 61910a37fd7SStephen Warren */ 62010a37fd7SStephen Warren part = 0; 62110a37fd7SStephen Warren for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 622*3e8bd469SSimon Glass ret = part_get_info(*dev_desc, p, info); 62310a37fd7SStephen Warren if (ret) 62410a37fd7SStephen Warren continue; 62510a37fd7SStephen Warren 62610a37fd7SStephen Warren /* 62710a37fd7SStephen Warren * First valid partition, or new better partition? 62810a37fd7SStephen Warren * If so, save partition ID. 62910a37fd7SStephen Warren */ 63010a37fd7SStephen Warren if (!part || info->bootable) 63110a37fd7SStephen Warren part = p; 63210a37fd7SStephen Warren 63310a37fd7SStephen Warren /* Best possible partition? Stop searching. */ 63410a37fd7SStephen Warren if (info->bootable) 63510a37fd7SStephen Warren break; 63610a37fd7SStephen Warren 63710a37fd7SStephen Warren /* 63810a37fd7SStephen Warren * We now need to search further for best possible. 63910a37fd7SStephen Warren * If we what we just queried was the best so far, 64010a37fd7SStephen Warren * save the info since we over-write it next loop. 64110a37fd7SStephen Warren */ 64210a37fd7SStephen Warren if (part == p) 64310a37fd7SStephen Warren tmpinfo = *info; 64410a37fd7SStephen Warren } 64510a37fd7SStephen Warren /* If we found any acceptable partition */ 64610a37fd7SStephen Warren if (part) { 64710a37fd7SStephen Warren /* 64810a37fd7SStephen Warren * If we searched all possible partition IDs, 64910a37fd7SStephen Warren * return the first valid partition we found. 65010a37fd7SStephen Warren */ 65110a37fd7SStephen Warren if (p == MAX_SEARCH_PARTITIONS + 1) 65210a37fd7SStephen Warren *info = tmpinfo; 65310a37fd7SStephen Warren } else { 65410a37fd7SStephen Warren printf("** No valid partitions found **\n"); 65571bba424SStephen Warren ret = -1; 65610a37fd7SStephen Warren goto cleanup; 65710a37fd7SStephen Warren } 65899d2c205SRob Herring } 65999d2c205SRob Herring if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 66099d2c205SRob Herring printf("** Invalid partition type \"%.32s\"" 66199d2c205SRob Herring " (expect \"" BOOT_PART_TYPE "\")\n", 66299d2c205SRob Herring info->type); 66310a37fd7SStephen Warren ret = -1; 66410a37fd7SStephen Warren goto cleanup; 66599d2c205SRob Herring } 66699d2c205SRob Herring 66750ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 66850ffc3b6SLan Yixun (dlan) 66910a37fd7SStephen Warren ret = part; 67010a37fd7SStephen Warren goto cleanup; 67199d2c205SRob Herring 67210a37fd7SStephen Warren cleanup: 67310a37fd7SStephen Warren free(dup_str); 67410a37fd7SStephen Warren return ret; 67599d2c205SRob Herring } 676