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 24751bb571SStefan Roese DECLARE_GLOBAL_DATA_PTR; 25751bb571SStefan Roese 260c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 2796e5b03cSSimon Glass static struct part_driver *part_driver_lookup_type(int part_type) 2896e5b03cSSimon Glass { 2996e5b03cSSimon Glass struct part_driver *drv = 3096e5b03cSSimon Glass ll_entry_start(struct part_driver, part_driver); 3196e5b03cSSimon Glass const int n_ents = ll_entry_count(struct part_driver, part_driver); 3296e5b03cSSimon Glass struct part_driver *entry; 3396e5b03cSSimon Glass 3496e5b03cSSimon Glass for (entry = drv; entry != drv + n_ents; entry++) { 3596e5b03cSSimon Glass if (part_type == entry->part_type) 3696e5b03cSSimon Glass return entry; 3796e5b03cSSimon Glass } 3896e5b03cSSimon Glass 3996e5b03cSSimon Glass /* Not found */ 4096e5b03cSSimon Glass return NULL; 4196e5b03cSSimon Glass } 4296e5b03cSSimon Glass 434101f687SSimon Glass static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 44735dd97bSGrant Likely { 45a6331fa8SSimon Glass struct blk_desc *dev_desc; 466dd9faf8SSimon Glass int ret; 47a6331fa8SSimon Glass 486dd9faf8SSimon Glass dev_desc = blk_get_devnum_by_typename(ifname, dev); 496dd9faf8SSimon Glass if (!dev_desc) { 506dd9faf8SSimon Glass debug("%s: No device for iface '%s', dev %d\n", __func__, 516dd9faf8SSimon Glass ifname, dev); 52336b6f90SStephen Warren return NULL; 536dd9faf8SSimon Glass } 546dd9faf8SSimon Glass ret = blk_dselect_hwpart(dev_desc, hwpart); 556dd9faf8SSimon Glass if (ret) { 566dd9faf8SSimon Glass debug("%s: Failed to select h/w partition: err-%d\n", __func__, 576dd9faf8SSimon Glass ret); 58336b6f90SStephen Warren return NULL; 596dd9faf8SSimon Glass } 606dd9faf8SSimon Glass 61336b6f90SStephen Warren return dev_desc; 62336b6f90SStephen Warren } 63336b6f90SStephen Warren 64db1d9e78SSimon Glass struct blk_desc *blk_get_dev(const char *ifname, int dev) 65336b6f90SStephen Warren { 66ecdd57e2SStephen Warren return get_dev_hwpart(ifname, dev, 0); 67336b6f90SStephen Warren } 68735dd97bSGrant Likely #else 694101f687SSimon Glass struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 70336b6f90SStephen Warren { 71336b6f90SStephen Warren return NULL; 72336b6f90SStephen Warren } 73336b6f90SStephen Warren 74db1d9e78SSimon Glass struct blk_desc *blk_get_dev(const char *ifname, int dev) 75735dd97bSGrant Likely { 76735dd97bSGrant Likely return NULL; 77735dd97bSGrant Likely } 78735dd97bSGrant Likely #endif 79735dd97bSGrant Likely 800c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 81735dd97bSGrant Likely 82affae2bfSwdenk /* ------------------------------------------------------------------------- */ 83affae2bfSwdenk /* 84affae2bfSwdenk * reports device info to the user 85affae2bfSwdenk */ 8669a2a4d9SSergei Trofimovich 8769a2a4d9SSergei Trofimovich #ifdef CONFIG_LBA48 8869a2a4d9SSergei Trofimovich typedef uint64_t lba512_t; 8969a2a4d9SSergei Trofimovich #else 9069a2a4d9SSergei Trofimovich typedef lbaint_t lba512_t; 9169a2a4d9SSergei Trofimovich #endif 9269a2a4d9SSergei Trofimovich 9369a2a4d9SSergei Trofimovich /* 9469a2a4d9SSergei Trofimovich * Overflowless variant of (block_count * mul_by / div_by) 9569a2a4d9SSergei Trofimovich * when div_by > mul_by 9669a2a4d9SSergei Trofimovich */ 9769a2a4d9SSergei Trofimovich static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, lba512_t div_by) 9869a2a4d9SSergei Trofimovich { 9969a2a4d9SSergei Trofimovich lba512_t bc_quot, bc_rem; 10069a2a4d9SSergei Trofimovich 10169a2a4d9SSergei Trofimovich /* x * m / d == x / d * m + (x % d) * m / d */ 10269a2a4d9SSergei Trofimovich bc_quot = block_count / div_by; 10369a2a4d9SSergei Trofimovich bc_rem = block_count - div_by * bc_quot; 10469a2a4d9SSergei Trofimovich return bc_quot * mul_by + (bc_rem * mul_by) / div_by; 10569a2a4d9SSergei Trofimovich } 10669a2a4d9SSergei Trofimovich 1074101f687SSimon Glass void dev_print (struct blk_desc *dev_desc) 108affae2bfSwdenk { 10969a2a4d9SSergei Trofimovich lba512_t lba512; /* number of blocks if 512bytes block size */ 110affae2bfSwdenk 111af75a45dSWolfgang Denk if (dev_desc->type == DEV_TYPE_UNKNOWN) { 112af75a45dSWolfgang Denk puts ("not available\n"); 113af75a45dSWolfgang Denk return; 114af75a45dSWolfgang Denk } 115af75a45dSWolfgang Denk 1168ec6e332STor Krill switch (dev_desc->if_type) { 117574b3195SDetlev Zundel case IF_TYPE_SCSI: 118574b3195SDetlev Zundel printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n", 119574b3195SDetlev Zundel dev_desc->target,dev_desc->lun, 120affae2bfSwdenk dev_desc->vendor, 121affae2bfSwdenk dev_desc->product, 122affae2bfSwdenk dev_desc->revision); 123574b3195SDetlev Zundel break; 1246e24a1ebSRemy Bohmer case IF_TYPE_ATAPI: 125574b3195SDetlev Zundel case IF_TYPE_IDE: 126574b3195SDetlev Zundel case IF_TYPE_SATA: 127574b3195SDetlev Zundel printf ("Model: %s Firm: %s Ser#: %s\n", 128574b3195SDetlev Zundel dev_desc->vendor, 129574b3195SDetlev Zundel dev_desc->revision, 130574b3195SDetlev Zundel dev_desc->product); 131574b3195SDetlev Zundel break; 1326e24a1ebSRemy Bohmer case IF_TYPE_SD: 1336e24a1ebSRemy Bohmer case IF_TYPE_MMC: 13447bebe34SNícolas Carneiro Lebedenco case IF_TYPE_USB: 13547bebe34SNícolas Carneiro Lebedenco printf ("Vendor: %s Rev: %s Prod: %s\n", 13647bebe34SNícolas Carneiro Lebedenco dev_desc->vendor, 13747bebe34SNícolas Carneiro Lebedenco dev_desc->revision, 13847bebe34SNícolas Carneiro Lebedenco dev_desc->product); 13947bebe34SNícolas Carneiro Lebedenco break; 1406e24a1ebSRemy Bohmer case IF_TYPE_DOC: 1416e24a1ebSRemy Bohmer puts("device type DOC\n"); 1426e24a1ebSRemy Bohmer return; 1438ec6e332STor Krill case IF_TYPE_UNKNOWN: 1446e24a1ebSRemy Bohmer puts("device type unknown\n"); 1456e24a1ebSRemy Bohmer return; 146574b3195SDetlev Zundel default: 1476e24a1ebSRemy Bohmer printf("Unhandled device type: %i\n", dev_desc->if_type); 148574b3195SDetlev Zundel return; 149affae2bfSwdenk } 150affae2bfSwdenk puts (" Type: "); 151affae2bfSwdenk if (dev_desc->removable) 152affae2bfSwdenk puts ("Removable "); 153affae2bfSwdenk switch (dev_desc->type & 0x1F) { 154726c0f1eSDetlev Zundel case DEV_TYPE_HARDDISK: 155726c0f1eSDetlev Zundel puts ("Hard Disk"); 156affae2bfSwdenk break; 157726c0f1eSDetlev Zundel case DEV_TYPE_CDROM: 158726c0f1eSDetlev Zundel puts ("CD ROM"); 159affae2bfSwdenk break; 160726c0f1eSDetlev Zundel case DEV_TYPE_OPDISK: 161726c0f1eSDetlev Zundel puts ("Optical Device"); 162affae2bfSwdenk break; 163726c0f1eSDetlev Zundel case DEV_TYPE_TAPE: 164726c0f1eSDetlev Zundel puts ("Tape"); 165affae2bfSwdenk break; 166726c0f1eSDetlev Zundel default: 167726c0f1eSDetlev Zundel printf ("# %02X #", dev_desc->type & 0x1F); 168affae2bfSwdenk break; 169affae2bfSwdenk } 170affae2bfSwdenk puts ("\n"); 17133699df1SJerry Huang if (dev_desc->lba > 0L && dev_desc->blksz > 0L) { 172affae2bfSwdenk ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem; 173c40b2956Swdenk lbaint_t lba; 1746e592385Swdenk 175c40b2956Swdenk lba = dev_desc->lba; 176affae2bfSwdenk 177c40b2956Swdenk lba512 = (lba * (dev_desc->blksz/512)); 178affae2bfSwdenk /* round to 1 digit */ 179214b3f31SPavel Machek /* 2048 = (1024 * 1024) / 512 MB */ 180214b3f31SPavel Machek mb = lba512_muldiv(lba512, 10, 2048); 18169a2a4d9SSergei Trofimovich 182affae2bfSwdenk mb_quot = mb / 10; 183affae2bfSwdenk mb_rem = mb - (10 * mb_quot); 184affae2bfSwdenk 185affae2bfSwdenk gb = mb / 1024; 186affae2bfSwdenk gb_quot = gb / 10; 187affae2bfSwdenk gb_rem = gb - (10 * gb_quot); 18842dfe7a1Swdenk #ifdef CONFIG_LBA48 1896e592385Swdenk if (dev_desc->lba48) 190c40b2956Swdenk printf (" Supports 48-bit addressing\n"); 191c40b2956Swdenk #endif 1924b142febSHeiko Schocher #if defined(CONFIG_SYS_64BIT_LBA) 193139f7b1dSJean-Jacques Hiblot printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n", 194c40b2956Swdenk mb_quot, mb_rem, 195c40b2956Swdenk gb_quot, gb_rem, 196c40b2956Swdenk lba, 197c40b2956Swdenk dev_desc->blksz); 198c40b2956Swdenk #else 199139f7b1dSJean-Jacques Hiblot printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n", 200affae2bfSwdenk mb_quot, mb_rem, 201affae2bfSwdenk gb_quot, gb_rem, 202c40b2956Swdenk (ulong)lba, 203affae2bfSwdenk dev_desc->blksz); 204c40b2956Swdenk #endif 205affae2bfSwdenk } else { 206affae2bfSwdenk puts (" Capacity: not available\n"); 207affae2bfSwdenk } 208affae2bfSwdenk } 209b3aff0cbSJon Loeliger #endif 210affae2bfSwdenk 2110c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 212affae2bfSwdenk 2133e8bd469SSimon Glass void part_init(struct blk_desc *dev_desc) 214affae2bfSwdenk { 21596e5b03cSSimon Glass struct part_driver *drv = 21696e5b03cSSimon Glass ll_entry_start(struct part_driver, part_driver); 21796e5b03cSSimon Glass const int n_ents = ll_entry_count(struct part_driver, part_driver); 21896e5b03cSSimon Glass struct part_driver *entry; 219affae2bfSwdenk 220e40cf34aSEric Nelson blkcache_invalidate(dev_desc->if_type, dev_desc->devnum); 221e40cf34aSEric Nelson 22299d2c205SRob Herring dev_desc->part_type = PART_TYPE_UNKNOWN; 22396e5b03cSSimon Glass for (entry = drv; entry != drv + n_ents; entry++) { 22496e5b03cSSimon Glass int ret; 22596e5b03cSSimon Glass 22696e5b03cSSimon Glass ret = entry->test(dev_desc); 22796e5b03cSSimon Glass debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret); 22896e5b03cSSimon Glass if (!ret) { 22996e5b03cSSimon Glass dev_desc->part_type = entry->part_type; 23096e5b03cSSimon Glass break; 23196e5b03cSSimon Glass } 23296e5b03cSSimon Glass } 233affae2bfSwdenk } 234affae2bfSwdenk 23596e5b03cSSimon Glass static void print_part_header(const char *type, struct blk_desc *dev_desc) 23696e5b03cSSimon Glass { 237f18fa31cSPatrick Delaunay #if CONFIG_IS_ENABLED(MAC_PARTITION) || \ 238b0cf7339SPatrick Delaunay CONFIG_IS_ENABLED(DOS_PARTITION) || \ 2391acc0087SPatrick Delaunay CONFIG_IS_ENABLED(ISO_PARTITION) || \ 240863c5b6cSPatrick Delaunay CONFIG_IS_ENABLED(AMIGA_PARTITION) || \ 241bd42a942SPatrick Delaunay CONFIG_IS_ENABLED(EFI_PARTITION) 242affae2bfSwdenk puts ("\nPartition Map for "); 243affae2bfSwdenk switch (dev_desc->if_type) { 244726c0f1eSDetlev Zundel case IF_TYPE_IDE: 245726c0f1eSDetlev Zundel puts ("IDE"); 246affae2bfSwdenk break; 247726c0f1eSDetlev Zundel case IF_TYPE_SATA: 248726c0f1eSDetlev Zundel puts ("SATA"); 249c7057b52SDave Liu break; 250726c0f1eSDetlev Zundel case IF_TYPE_SCSI: 251726c0f1eSDetlev Zundel puts ("SCSI"); 252affae2bfSwdenk break; 253726c0f1eSDetlev Zundel case IF_TYPE_ATAPI: 254726c0f1eSDetlev Zundel puts ("ATAPI"); 255affae2bfSwdenk break; 256726c0f1eSDetlev Zundel case IF_TYPE_USB: 257726c0f1eSDetlev Zundel puts ("USB"); 258affae2bfSwdenk break; 259726c0f1eSDetlev Zundel case IF_TYPE_DOC: 260726c0f1eSDetlev Zundel puts ("DOC"); 261affae2bfSwdenk break; 2628f3b9642SLei Wen case IF_TYPE_MMC: 2638f3b9642SLei Wen puts ("MMC"); 2648f3b9642SLei Wen break; 265f4d8de48SHenrik Nordström case IF_TYPE_HOST: 266f4d8de48SHenrik Nordström puts("HOST"); 267f4d8de48SHenrik Nordström break; 268726c0f1eSDetlev Zundel default: 269726c0f1eSDetlev Zundel puts ("UNKNOWN"); 270affae2bfSwdenk break; 271affae2bfSwdenk } 272affae2bfSwdenk printf (" device %d -- Partition Type: %s\n\n", 273bcce53d0SSimon Glass dev_desc->devnum, type); 2740c9c8fb5SGabe Black #endif /* any CONFIG_..._PARTITION */ 27596e5b03cSSimon Glass } 2760c9c8fb5SGabe Black 2773e8bd469SSimon Glass void part_print(struct blk_desc *dev_desc) 278affae2bfSwdenk { 27996e5b03cSSimon Glass struct part_driver *drv; 280affae2bfSwdenk 28196e5b03cSSimon Glass drv = part_driver_lookup_type(dev_desc->part_type); 28296e5b03cSSimon Glass if (!drv) { 28396e5b03cSSimon Glass printf("## Unknown partition table type %x\n", 28496e5b03cSSimon Glass dev_desc->part_type); 285affae2bfSwdenk return; 286affae2bfSwdenk } 28796e5b03cSSimon Glass 28896e5b03cSSimon Glass PRINTF("## Testing for valid %s partition ##\n", drv->name); 28996e5b03cSSimon Glass print_part_header(drv->name, dev_desc); 29096e5b03cSSimon Glass if (drv->print) 29196e5b03cSSimon Glass drv->print(dev_desc); 292affae2bfSwdenk } 293affae2bfSwdenk 2940c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 2952f501646SStephen Warren 2963e8bd469SSimon Glass int part_get_info(struct blk_desc *dev_desc, int part, 2973f9eb6e1SPavel Machek disk_partition_t *info) 2982f501646SStephen Warren { 2990c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 30096e5b03cSSimon Glass struct part_driver *drv; 3012f501646SStephen Warren 302*b331cd62SPatrick Delaunay #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 303894bfbbfSStephen Warren /* The common case is no UUID support */ 304894bfbbfSStephen Warren info->uuid[0] = 0; 305894bfbbfSStephen Warren #endif 3067561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 3077561b258SPatrick Delaunay info->type_guid[0] = 0; 3087561b258SPatrick Delaunay #endif 309894bfbbfSStephen Warren 31096e5b03cSSimon Glass drv = part_driver_lookup_type(dev_desc->part_type); 31196e5b03cSSimon Glass if (!drv) { 31296e5b03cSSimon Glass debug("## Unknown partition table type %x\n", 31396e5b03cSSimon Glass dev_desc->part_type); 31496e5b03cSSimon Glass return -EPROTONOSUPPORT; 3152f501646SStephen Warren } 31696e5b03cSSimon Glass if (!drv->get_info) { 3172ae67aecSNishanth Menon PRINTF("## Driver %s does not have the get_info() method\n", 3182ae67aecSNishanth Menon drv->name); 31996e5b03cSSimon Glass return -ENOSYS; 3202f501646SStephen Warren } 32196e5b03cSSimon Glass if (drv->get_info(dev_desc, part, info) == 0) { 32296e5b03cSSimon Glass PRINTF("## Valid %s partition found ##\n", drv->name); 3232f501646SStephen Warren return 0; 3242f501646SStephen Warren } 3250c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 3262f501646SStephen Warren 3272f501646SStephen Warren return -1; 3282f501646SStephen Warren } 32999d2c205SRob Herring 330ebac37cfSSimon Glass int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, 3314101f687SSimon Glass struct blk_desc **dev_desc) 3322023e608SStephen Warren { 3332023e608SStephen Warren char *ep; 334336b6f90SStephen Warren char *dup_str = NULL; 335336b6f90SStephen Warren const char *dev_str, *hwpart_str; 336336b6f90SStephen Warren int dev, hwpart; 337336b6f90SStephen Warren 338336b6f90SStephen Warren hwpart_str = strchr(dev_hwpart_str, '.'); 339336b6f90SStephen Warren if (hwpart_str) { 340336b6f90SStephen Warren dup_str = strdup(dev_hwpart_str); 341336b6f90SStephen Warren dup_str[hwpart_str - dev_hwpart_str] = 0; 342336b6f90SStephen Warren dev_str = dup_str; 343336b6f90SStephen Warren hwpart_str++; 344336b6f90SStephen Warren } else { 345336b6f90SStephen Warren dev_str = dev_hwpart_str; 346ecdd57e2SStephen Warren hwpart = 0; 347336b6f90SStephen Warren } 3482023e608SStephen Warren 3492023e608SStephen Warren dev = simple_strtoul(dev_str, &ep, 16); 3502023e608SStephen Warren if (*ep) { 3512023e608SStephen Warren printf("** Bad device specification %s %s **\n", 3522023e608SStephen Warren ifname, dev_str); 3531598dfcbSSimon Glass dev = -EINVAL; 354336b6f90SStephen Warren goto cleanup; 3552023e608SStephen Warren } 3562023e608SStephen Warren 357336b6f90SStephen Warren if (hwpart_str) { 358336b6f90SStephen Warren hwpart = simple_strtoul(hwpart_str, &ep, 16); 359336b6f90SStephen Warren if (*ep) { 360336b6f90SStephen Warren printf("** Bad HW partition specification %s %s **\n", 361336b6f90SStephen Warren ifname, hwpart_str); 3621598dfcbSSimon Glass dev = -EINVAL; 363336b6f90SStephen Warren goto cleanup; 364336b6f90SStephen Warren } 365336b6f90SStephen Warren } 366336b6f90SStephen Warren 367336b6f90SStephen Warren *dev_desc = get_dev_hwpart(ifname, dev, hwpart); 3682023e608SStephen Warren if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { 369336b6f90SStephen Warren printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); 3701598dfcbSSimon Glass dev = -ENOENT; 371336b6f90SStephen Warren goto cleanup; 3722023e608SStephen Warren } 3732023e608SStephen Warren 37499e7fc8aSErik Tideman #ifdef HAVE_BLOCK_DEVICE 37599e7fc8aSErik Tideman /* 37699e7fc8aSErik Tideman * Updates the partition table for the specified hw partition. 37799e7fc8aSErik Tideman * Does not need to be done for hwpart 0 since it is default and 37899e7fc8aSErik Tideman * already loaded. 37999e7fc8aSErik Tideman */ 38099e7fc8aSErik Tideman if(hwpart != 0) 3813e8bd469SSimon Glass part_init(*dev_desc); 38299e7fc8aSErik Tideman #endif 38399e7fc8aSErik Tideman 384336b6f90SStephen Warren cleanup: 385336b6f90SStephen Warren free(dup_str); 3862023e608SStephen Warren return dev; 3872023e608SStephen Warren } 3882023e608SStephen Warren 38910a37fd7SStephen Warren #define PART_UNSPECIFIED -2 39010a37fd7SStephen Warren #define PART_AUTO -1 39110a37fd7SStephen Warren #define MAX_SEARCH_PARTITIONS 16 392e35929e4SSimon Glass int blk_get_device_part_str(const char *ifname, const char *dev_part_str, 3934101f687SSimon Glass struct blk_desc **dev_desc, 39410a37fd7SStephen Warren disk_partition_t *info, int allow_whole_dev) 39599d2c205SRob Herring { 39610a37fd7SStephen Warren int ret = -1; 39710a37fd7SStephen Warren const char *part_str; 39810a37fd7SStephen Warren char *dup_str = NULL; 39910a37fd7SStephen Warren const char *dev_str; 40099d2c205SRob Herring int dev; 40110a37fd7SStephen Warren char *ep; 40210a37fd7SStephen Warren int p; 40310a37fd7SStephen Warren int part; 40410a37fd7SStephen Warren disk_partition_t tmpinfo; 40599d2c205SRob Herring 406afc1744eSHans de Goede #ifdef CONFIG_SANDBOX 4074d907025SStephen Warren /* 4083f9eb6e1SPavel Machek * Special-case a pseudo block device "hostfs", to allow access to the 4094d907025SStephen Warren * host's own filesystem. 4104d907025SStephen Warren */ 4114d907025SStephen Warren if (0 == strcmp(ifname, "hostfs")) { 4124d907025SStephen Warren *dev_desc = NULL; 4134d907025SStephen Warren info->start = 0; 4144d907025SStephen Warren info->size = 0; 4154d907025SStephen Warren info->blksz = 0; 4164d907025SStephen Warren info->bootable = 0; 4174d907025SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 4184d907025SStephen Warren strcpy((char *)info->name, "Sandbox host"); 419*b331cd62SPatrick Delaunay #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 4204d907025SStephen Warren info->uuid[0] = 0; 4214d907025SStephen Warren #endif 4227561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 4237561b258SPatrick Delaunay info->type_guid[0] = 0; 4247561b258SPatrick Delaunay #endif 4254d907025SStephen Warren 4264d907025SStephen Warren return 0; 4274d907025SStephen Warren } 428afc1744eSHans de Goede #endif 4294d907025SStephen Warren 430251cee0dSHans de Goede #ifdef CONFIG_CMD_UBIFS 431251cee0dSHans de Goede /* 432251cee0dSHans de Goede * Special-case ubi, ubi goes through a mtd, rathen then through 433251cee0dSHans de Goede * a regular block device. 434251cee0dSHans de Goede */ 435251cee0dSHans de Goede if (0 == strcmp(ifname, "ubi")) { 436251cee0dSHans de Goede if (!ubifs_is_mounted()) { 437251cee0dSHans de Goede printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); 438251cee0dSHans de Goede return -1; 439251cee0dSHans de Goede } 440251cee0dSHans de Goede 441251cee0dSHans de Goede *dev_desc = NULL; 442251cee0dSHans de Goede memset(info, 0, sizeof(*info)); 443251cee0dSHans de Goede strcpy((char *)info->type, BOOT_PART_TYPE); 444251cee0dSHans de Goede strcpy((char *)info->name, "UBI"); 445*b331cd62SPatrick Delaunay #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 446251cee0dSHans de Goede info->uuid[0] = 0; 447251cee0dSHans de Goede #endif 448251cee0dSHans de Goede return 0; 449251cee0dSHans de Goede } 450251cee0dSHans de Goede #endif 451251cee0dSHans de Goede 45210a37fd7SStephen Warren /* If no dev_part_str, use bootdevice environment variable */ 453a10973e7SStephen Warren if (!dev_part_str || !strlen(dev_part_str) || 454a10973e7SStephen Warren !strcmp(dev_part_str, "-")) 45510a37fd7SStephen Warren dev_part_str = getenv("bootdevice"); 45699d2c205SRob Herring 45710a37fd7SStephen Warren /* If still no dev_part_str, it's an error */ 45810a37fd7SStephen Warren if (!dev_part_str) { 45910a37fd7SStephen Warren printf("** No device specified **\n"); 46010a37fd7SStephen Warren goto cleanup; 46199d2c205SRob Herring } 46299d2c205SRob Herring 46310a37fd7SStephen Warren /* Separate device and partition ID specification */ 46410a37fd7SStephen Warren part_str = strchr(dev_part_str, ':'); 46510a37fd7SStephen Warren if (part_str) { 46610a37fd7SStephen Warren dup_str = strdup(dev_part_str); 46710a37fd7SStephen Warren dup_str[part_str - dev_part_str] = 0; 46810a37fd7SStephen Warren dev_str = dup_str; 46910a37fd7SStephen Warren part_str++; 47010a37fd7SStephen Warren } else { 47110a37fd7SStephen Warren dev_str = dev_part_str; 47299d2c205SRob Herring } 47310a37fd7SStephen Warren 47410a37fd7SStephen Warren /* Look up the device */ 475ebac37cfSSimon Glass dev = blk_get_device_by_str(ifname, dev_str, dev_desc); 47610a37fd7SStephen Warren if (dev < 0) 47710a37fd7SStephen Warren goto cleanup; 47810a37fd7SStephen Warren 47910a37fd7SStephen Warren /* Convert partition ID string to number */ 48010a37fd7SStephen Warren if (!part_str || !*part_str) { 48110a37fd7SStephen Warren part = PART_UNSPECIFIED; 48210a37fd7SStephen Warren } else if (!strcmp(part_str, "auto")) { 48310a37fd7SStephen Warren part = PART_AUTO; 48410a37fd7SStephen Warren } else { 48510a37fd7SStephen Warren /* Something specified -> use exactly that */ 48610a37fd7SStephen Warren part = (int)simple_strtoul(part_str, &ep, 16); 48710a37fd7SStephen Warren /* 48810a37fd7SStephen Warren * Less than whole string converted, 48910a37fd7SStephen Warren * or request for whole device, but caller requires partition. 49010a37fd7SStephen Warren */ 49110a37fd7SStephen Warren if (*ep || (part == 0 && !allow_whole_dev)) { 49210a37fd7SStephen Warren printf("** Bad partition specification %s %s **\n", 49310a37fd7SStephen Warren ifname, dev_part_str); 49410a37fd7SStephen Warren goto cleanup; 49510a37fd7SStephen Warren } 49610a37fd7SStephen Warren } 49710a37fd7SStephen Warren 49810a37fd7SStephen Warren /* 49910a37fd7SStephen Warren * No partition table on device, 50010a37fd7SStephen Warren * or user requested partition 0 (entire device). 50110a37fd7SStephen Warren */ 50210a37fd7SStephen Warren if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 50310a37fd7SStephen Warren (part == 0)) { 50410a37fd7SStephen Warren if (!(*dev_desc)->lba) { 50510a37fd7SStephen Warren printf("** Bad device size - %s %s **\n", ifname, 50610a37fd7SStephen Warren dev_str); 50710a37fd7SStephen Warren goto cleanup; 50810a37fd7SStephen Warren } 50910a37fd7SStephen Warren 51010a37fd7SStephen Warren /* 51110a37fd7SStephen Warren * If user specified a partition ID other than 0, 51210a37fd7SStephen Warren * or the calling command only accepts partitions, 51310a37fd7SStephen Warren * it's an error. 51410a37fd7SStephen Warren */ 51510a37fd7SStephen Warren if ((part > 0) || (!allow_whole_dev)) { 51610a37fd7SStephen Warren printf("** No partition table - %s %s **\n", ifname, 51710a37fd7SStephen Warren dev_str); 51810a37fd7SStephen Warren goto cleanup; 51910a37fd7SStephen Warren } 52010a37fd7SStephen Warren 52150ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 52250ffc3b6SLan Yixun (dlan) 52399d2c205SRob Herring info->start = 0; 52410a37fd7SStephen Warren info->size = (*dev_desc)->lba; 52510a37fd7SStephen Warren info->blksz = (*dev_desc)->blksz; 52610a37fd7SStephen Warren info->bootable = 0; 5276ab6a650SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 5286ab6a650SStephen Warren strcpy((char *)info->name, "Whole Disk"); 529*b331cd62SPatrick Delaunay #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 53010a37fd7SStephen Warren info->uuid[0] = 0; 53110a37fd7SStephen Warren #endif 5327561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 5337561b258SPatrick Delaunay info->type_guid[0] = 0; 5347561b258SPatrick Delaunay #endif 53599d2c205SRob Herring 53610a37fd7SStephen Warren ret = 0; 53710a37fd7SStephen Warren goto cleanup; 53899d2c205SRob Herring } 53999d2c205SRob Herring 54010a37fd7SStephen Warren /* 54110a37fd7SStephen Warren * Now there's known to be a partition table, 54210a37fd7SStephen Warren * not specifying a partition means to pick partition 1. 54310a37fd7SStephen Warren */ 54410a37fd7SStephen Warren if (part == PART_UNSPECIFIED) 54510a37fd7SStephen Warren part = 1; 54699d2c205SRob Herring 54710a37fd7SStephen Warren /* 54810a37fd7SStephen Warren * If user didn't specify a partition number, or did specify something 54910a37fd7SStephen Warren * other than "auto", use that partition number directly. 55010a37fd7SStephen Warren */ 55110a37fd7SStephen Warren if (part != PART_AUTO) { 5523e8bd469SSimon Glass ret = part_get_info(*dev_desc, part, info); 55399d2c205SRob Herring if (ret) { 55410a37fd7SStephen Warren printf("** Invalid partition %d **\n", part); 55510a37fd7SStephen Warren goto cleanup; 55610a37fd7SStephen Warren } 55710a37fd7SStephen Warren } else { 55810a37fd7SStephen Warren /* 55910a37fd7SStephen Warren * Find the first bootable partition. 56010a37fd7SStephen Warren * If none are bootable, fall back to the first valid partition. 56110a37fd7SStephen Warren */ 56210a37fd7SStephen Warren part = 0; 56310a37fd7SStephen Warren for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 5643e8bd469SSimon Glass ret = part_get_info(*dev_desc, p, info); 56510a37fd7SStephen Warren if (ret) 56610a37fd7SStephen Warren continue; 56710a37fd7SStephen Warren 56810a37fd7SStephen Warren /* 56910a37fd7SStephen Warren * First valid partition, or new better partition? 57010a37fd7SStephen Warren * If so, save partition ID. 57110a37fd7SStephen Warren */ 57210a37fd7SStephen Warren if (!part || info->bootable) 57310a37fd7SStephen Warren part = p; 57410a37fd7SStephen Warren 57510a37fd7SStephen Warren /* Best possible partition? Stop searching. */ 57610a37fd7SStephen Warren if (info->bootable) 57710a37fd7SStephen Warren break; 57810a37fd7SStephen Warren 57910a37fd7SStephen Warren /* 58010a37fd7SStephen Warren * We now need to search further for best possible. 58110a37fd7SStephen Warren * If we what we just queried was the best so far, 58210a37fd7SStephen Warren * save the info since we over-write it next loop. 58310a37fd7SStephen Warren */ 58410a37fd7SStephen Warren if (part == p) 58510a37fd7SStephen Warren tmpinfo = *info; 58610a37fd7SStephen Warren } 58710a37fd7SStephen Warren /* If we found any acceptable partition */ 58810a37fd7SStephen Warren if (part) { 58910a37fd7SStephen Warren /* 59010a37fd7SStephen Warren * If we searched all possible partition IDs, 59110a37fd7SStephen Warren * return the first valid partition we found. 59210a37fd7SStephen Warren */ 59310a37fd7SStephen Warren if (p == MAX_SEARCH_PARTITIONS + 1) 59410a37fd7SStephen Warren *info = tmpinfo; 59510a37fd7SStephen Warren } else { 59610a37fd7SStephen Warren printf("** No valid partitions found **\n"); 59771bba424SStephen Warren ret = -1; 59810a37fd7SStephen Warren goto cleanup; 59910a37fd7SStephen Warren } 60099d2c205SRob Herring } 60199d2c205SRob Herring if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 60299d2c205SRob Herring printf("** Invalid partition type \"%.32s\"" 60399d2c205SRob Herring " (expect \"" BOOT_PART_TYPE "\")\n", 60499d2c205SRob Herring info->type); 60510a37fd7SStephen Warren ret = -1; 60610a37fd7SStephen Warren goto cleanup; 60799d2c205SRob Herring } 60899d2c205SRob Herring 60950ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 61050ffc3b6SLan Yixun (dlan) 61110a37fd7SStephen Warren ret = part; 61210a37fd7SStephen Warren goto cleanup; 61399d2c205SRob Herring 61410a37fd7SStephen Warren cleanup: 61510a37fd7SStephen Warren free(dup_str); 61610a37fd7SStephen Warren return ret; 61799d2c205SRob Herring } 61887b8530fSPetr Kulhavy 61987b8530fSPetr Kulhavy int part_get_info_by_name(struct blk_desc *dev_desc, const char *name, 62087b8530fSPetr Kulhavy disk_partition_t *info) 62187b8530fSPetr Kulhavy { 62287b8530fSPetr Kulhavy struct part_driver *first_drv = 62387b8530fSPetr Kulhavy ll_entry_start(struct part_driver, part_driver); 62487b8530fSPetr Kulhavy const int n_drvs = ll_entry_count(struct part_driver, part_driver); 62587b8530fSPetr Kulhavy struct part_driver *part_drv; 62687b8530fSPetr Kulhavy 62787b8530fSPetr Kulhavy for (part_drv = first_drv; part_drv != first_drv + n_drvs; part_drv++) { 62887b8530fSPetr Kulhavy int ret; 62987b8530fSPetr Kulhavy int i; 63087b8530fSPetr Kulhavy for (i = 1; i < part_drv->max_entries; i++) { 63187b8530fSPetr Kulhavy ret = part_drv->get_info(dev_desc, i, info); 63287b8530fSPetr Kulhavy if (ret != 0) { 63387b8530fSPetr Kulhavy /* no more entries in table */ 63487b8530fSPetr Kulhavy break; 63587b8530fSPetr Kulhavy } 63687b8530fSPetr Kulhavy if (strcmp(name, (const char *)info->name) == 0) { 63787b8530fSPetr Kulhavy /* matched */ 63887b8530fSPetr Kulhavy return 0; 63987b8530fSPetr Kulhavy } 64087b8530fSPetr Kulhavy } 64187b8530fSPetr Kulhavy } 64287b8530fSPetr Kulhavy return -1; 64387b8530fSPetr Kulhavy } 644da2ee24dSPetr Kulhavy 645da2ee24dSPetr Kulhavy void part_set_generic_name(const struct blk_desc *dev_desc, 646da2ee24dSPetr Kulhavy int part_num, char *name) 647da2ee24dSPetr Kulhavy { 648da2ee24dSPetr Kulhavy char *devtype; 649da2ee24dSPetr Kulhavy 650da2ee24dSPetr Kulhavy switch (dev_desc->if_type) { 651da2ee24dSPetr Kulhavy case IF_TYPE_IDE: 652da2ee24dSPetr Kulhavy case IF_TYPE_SATA: 653da2ee24dSPetr Kulhavy case IF_TYPE_ATAPI: 654da2ee24dSPetr Kulhavy devtype = "hd"; 655da2ee24dSPetr Kulhavy break; 656da2ee24dSPetr Kulhavy case IF_TYPE_SCSI: 657da2ee24dSPetr Kulhavy devtype = "sd"; 658da2ee24dSPetr Kulhavy break; 659da2ee24dSPetr Kulhavy case IF_TYPE_USB: 660da2ee24dSPetr Kulhavy devtype = "usbd"; 661da2ee24dSPetr Kulhavy break; 662da2ee24dSPetr Kulhavy case IF_TYPE_DOC: 663da2ee24dSPetr Kulhavy devtype = "docd"; 664da2ee24dSPetr Kulhavy break; 665da2ee24dSPetr Kulhavy case IF_TYPE_MMC: 666da2ee24dSPetr Kulhavy case IF_TYPE_SD: 667da2ee24dSPetr Kulhavy devtype = "mmcsd"; 668da2ee24dSPetr Kulhavy break; 669da2ee24dSPetr Kulhavy default: 670da2ee24dSPetr Kulhavy devtype = "xx"; 671da2ee24dSPetr Kulhavy break; 672da2ee24dSPetr Kulhavy } 673da2ee24dSPetr Kulhavy 674da2ee24dSPetr Kulhavy sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num); 675da2ee24dSPetr Kulhavy } 676