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: 135ffab6945SZhikang Zhang case IF_TYPE_NVME: 13647bebe34SNícolas Carneiro Lebedenco printf ("Vendor: %s Rev: %s Prod: %s\n", 13747bebe34SNícolas Carneiro Lebedenco dev_desc->vendor, 13847bebe34SNícolas Carneiro Lebedenco dev_desc->revision, 13947bebe34SNícolas Carneiro Lebedenco dev_desc->product); 14047bebe34SNícolas Carneiro Lebedenco break; 1416e24a1ebSRemy Bohmer case IF_TYPE_DOC: 1426e24a1ebSRemy Bohmer puts("device type DOC\n"); 1436e24a1ebSRemy Bohmer return; 1448ec6e332STor Krill case IF_TYPE_UNKNOWN: 1456e24a1ebSRemy Bohmer puts("device type unknown\n"); 1466e24a1ebSRemy Bohmer return; 147574b3195SDetlev Zundel default: 1486e24a1ebSRemy Bohmer printf("Unhandled device type: %i\n", dev_desc->if_type); 149574b3195SDetlev Zundel return; 150affae2bfSwdenk } 151affae2bfSwdenk puts (" Type: "); 152affae2bfSwdenk if (dev_desc->removable) 153affae2bfSwdenk puts ("Removable "); 154affae2bfSwdenk switch (dev_desc->type & 0x1F) { 155726c0f1eSDetlev Zundel case DEV_TYPE_HARDDISK: 156726c0f1eSDetlev Zundel puts ("Hard Disk"); 157affae2bfSwdenk break; 158726c0f1eSDetlev Zundel case DEV_TYPE_CDROM: 159726c0f1eSDetlev Zundel puts ("CD ROM"); 160affae2bfSwdenk break; 161726c0f1eSDetlev Zundel case DEV_TYPE_OPDISK: 162726c0f1eSDetlev Zundel puts ("Optical Device"); 163affae2bfSwdenk break; 164726c0f1eSDetlev Zundel case DEV_TYPE_TAPE: 165726c0f1eSDetlev Zundel puts ("Tape"); 166affae2bfSwdenk break; 167726c0f1eSDetlev Zundel default: 168726c0f1eSDetlev Zundel printf ("# %02X #", dev_desc->type & 0x1F); 169affae2bfSwdenk break; 170affae2bfSwdenk } 171affae2bfSwdenk puts ("\n"); 17233699df1SJerry Huang if (dev_desc->lba > 0L && dev_desc->blksz > 0L) { 173affae2bfSwdenk ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem; 174c40b2956Swdenk lbaint_t lba; 1756e592385Swdenk 176c40b2956Swdenk lba = dev_desc->lba; 177affae2bfSwdenk 178c40b2956Swdenk lba512 = (lba * (dev_desc->blksz/512)); 179affae2bfSwdenk /* round to 1 digit */ 180214b3f31SPavel Machek /* 2048 = (1024 * 1024) / 512 MB */ 181214b3f31SPavel Machek mb = lba512_muldiv(lba512, 10, 2048); 18269a2a4d9SSergei Trofimovich 183affae2bfSwdenk mb_quot = mb / 10; 184affae2bfSwdenk mb_rem = mb - (10 * mb_quot); 185affae2bfSwdenk 186affae2bfSwdenk gb = mb / 1024; 187affae2bfSwdenk gb_quot = gb / 10; 188affae2bfSwdenk gb_rem = gb - (10 * gb_quot); 18942dfe7a1Swdenk #ifdef CONFIG_LBA48 1906e592385Swdenk if (dev_desc->lba48) 191c40b2956Swdenk printf (" Supports 48-bit addressing\n"); 192c40b2956Swdenk #endif 1934b142febSHeiko Schocher #if defined(CONFIG_SYS_64BIT_LBA) 194139f7b1dSJean-Jacques Hiblot printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n", 195c40b2956Swdenk mb_quot, mb_rem, 196c40b2956Swdenk gb_quot, gb_rem, 197c40b2956Swdenk lba, 198c40b2956Swdenk dev_desc->blksz); 199c40b2956Swdenk #else 200139f7b1dSJean-Jacques Hiblot printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n", 201affae2bfSwdenk mb_quot, mb_rem, 202affae2bfSwdenk gb_quot, gb_rem, 203c40b2956Swdenk (ulong)lba, 204affae2bfSwdenk dev_desc->blksz); 205c40b2956Swdenk #endif 206affae2bfSwdenk } else { 207affae2bfSwdenk puts (" Capacity: not available\n"); 208affae2bfSwdenk } 209affae2bfSwdenk } 210b3aff0cbSJon Loeliger #endif 211affae2bfSwdenk 2120c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 213affae2bfSwdenk 2143e8bd469SSimon Glass void part_init(struct blk_desc *dev_desc) 215affae2bfSwdenk { 21696e5b03cSSimon Glass struct part_driver *drv = 21796e5b03cSSimon Glass ll_entry_start(struct part_driver, part_driver); 21896e5b03cSSimon Glass const int n_ents = ll_entry_count(struct part_driver, part_driver); 21996e5b03cSSimon Glass struct part_driver *entry; 220affae2bfSwdenk 221e40cf34aSEric Nelson blkcache_invalidate(dev_desc->if_type, dev_desc->devnum); 222e40cf34aSEric Nelson 22399d2c205SRob Herring dev_desc->part_type = PART_TYPE_UNKNOWN; 22496e5b03cSSimon Glass for (entry = drv; entry != drv + n_ents; entry++) { 22596e5b03cSSimon Glass int ret; 22696e5b03cSSimon Glass 22796e5b03cSSimon Glass ret = entry->test(dev_desc); 22896e5b03cSSimon Glass debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret); 22996e5b03cSSimon Glass if (!ret) { 23096e5b03cSSimon Glass dev_desc->part_type = entry->part_type; 23196e5b03cSSimon Glass break; 23296e5b03cSSimon Glass } 23396e5b03cSSimon Glass } 234affae2bfSwdenk } 235affae2bfSwdenk 23696e5b03cSSimon Glass static void print_part_header(const char *type, struct blk_desc *dev_desc) 23796e5b03cSSimon Glass { 238f18fa31cSPatrick Delaunay #if CONFIG_IS_ENABLED(MAC_PARTITION) || \ 239b0cf7339SPatrick Delaunay CONFIG_IS_ENABLED(DOS_PARTITION) || \ 2401acc0087SPatrick Delaunay CONFIG_IS_ENABLED(ISO_PARTITION) || \ 241863c5b6cSPatrick Delaunay CONFIG_IS_ENABLED(AMIGA_PARTITION) || \ 242bd42a942SPatrick Delaunay CONFIG_IS_ENABLED(EFI_PARTITION) 243affae2bfSwdenk puts ("\nPartition Map for "); 244affae2bfSwdenk switch (dev_desc->if_type) { 245726c0f1eSDetlev Zundel case IF_TYPE_IDE: 246726c0f1eSDetlev Zundel puts ("IDE"); 247affae2bfSwdenk break; 248726c0f1eSDetlev Zundel case IF_TYPE_SATA: 249726c0f1eSDetlev Zundel puts ("SATA"); 250c7057b52SDave Liu break; 251726c0f1eSDetlev Zundel case IF_TYPE_SCSI: 252726c0f1eSDetlev Zundel puts ("SCSI"); 253affae2bfSwdenk break; 254726c0f1eSDetlev Zundel case IF_TYPE_ATAPI: 255726c0f1eSDetlev Zundel puts ("ATAPI"); 256affae2bfSwdenk break; 257726c0f1eSDetlev Zundel case IF_TYPE_USB: 258726c0f1eSDetlev Zundel puts ("USB"); 259affae2bfSwdenk break; 260726c0f1eSDetlev Zundel case IF_TYPE_DOC: 261726c0f1eSDetlev Zundel puts ("DOC"); 262affae2bfSwdenk break; 2638f3b9642SLei Wen case IF_TYPE_MMC: 2648f3b9642SLei Wen puts ("MMC"); 2658f3b9642SLei Wen break; 266f4d8de48SHenrik Nordström case IF_TYPE_HOST: 267f4d8de48SHenrik Nordström puts ("HOST"); 268f4d8de48SHenrik Nordström break; 269ffab6945SZhikang Zhang case IF_TYPE_NVME: 270ffab6945SZhikang Zhang puts ("NVMe"); 271ffab6945SZhikang Zhang break; 272726c0f1eSDetlev Zundel default: 273726c0f1eSDetlev Zundel puts ("UNKNOWN"); 274affae2bfSwdenk break; 275affae2bfSwdenk } 276affae2bfSwdenk printf (" device %d -- Partition Type: %s\n\n", 277bcce53d0SSimon Glass dev_desc->devnum, type); 2780c9c8fb5SGabe Black #endif /* any CONFIG_..._PARTITION */ 27996e5b03cSSimon Glass } 2800c9c8fb5SGabe Black 2813e8bd469SSimon Glass void part_print(struct blk_desc *dev_desc) 282affae2bfSwdenk { 28396e5b03cSSimon Glass struct part_driver *drv; 284affae2bfSwdenk 28596e5b03cSSimon Glass drv = part_driver_lookup_type(dev_desc->part_type); 28696e5b03cSSimon Glass if (!drv) { 28796e5b03cSSimon Glass printf("## Unknown partition table type %x\n", 28896e5b03cSSimon Glass dev_desc->part_type); 289affae2bfSwdenk return; 290affae2bfSwdenk } 29196e5b03cSSimon Glass 29296e5b03cSSimon Glass PRINTF("## Testing for valid %s partition ##\n", drv->name); 29396e5b03cSSimon Glass print_part_header(drv->name, dev_desc); 29496e5b03cSSimon Glass if (drv->print) 29596e5b03cSSimon Glass drv->print(dev_desc); 296affae2bfSwdenk } 297affae2bfSwdenk 2980c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 2992f501646SStephen Warren 3003e8bd469SSimon Glass int part_get_info(struct blk_desc *dev_desc, int part, 3013f9eb6e1SPavel Machek disk_partition_t *info) 3022f501646SStephen Warren { 3030c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 30496e5b03cSSimon Glass struct part_driver *drv; 3052f501646SStephen Warren 306b331cd62SPatrick Delaunay #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 307894bfbbfSStephen Warren /* The common case is no UUID support */ 308894bfbbfSStephen Warren info->uuid[0] = 0; 309894bfbbfSStephen Warren #endif 3107561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 3117561b258SPatrick Delaunay info->type_guid[0] = 0; 3127561b258SPatrick Delaunay #endif 313894bfbbfSStephen Warren 31496e5b03cSSimon Glass drv = part_driver_lookup_type(dev_desc->part_type); 31596e5b03cSSimon Glass if (!drv) { 31696e5b03cSSimon Glass debug("## Unknown partition table type %x\n", 31796e5b03cSSimon Glass dev_desc->part_type); 31896e5b03cSSimon Glass return -EPROTONOSUPPORT; 3192f501646SStephen Warren } 32096e5b03cSSimon Glass if (!drv->get_info) { 3212ae67aecSNishanth Menon PRINTF("## Driver %s does not have the get_info() method\n", 3222ae67aecSNishanth Menon drv->name); 32396e5b03cSSimon Glass return -ENOSYS; 3242f501646SStephen Warren } 32596e5b03cSSimon Glass if (drv->get_info(dev_desc, part, info) == 0) { 32696e5b03cSSimon Glass PRINTF("## Valid %s partition found ##\n", drv->name); 3272f501646SStephen Warren return 0; 3282f501646SStephen Warren } 3290c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 3302f501646SStephen Warren 3312f501646SStephen Warren return -1; 3322f501646SStephen Warren } 33399d2c205SRob Herring 334*4bbcc965SRob Clark int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info) 335*4bbcc965SRob Clark { 336*4bbcc965SRob Clark info->start = 0; 337*4bbcc965SRob Clark info->size = dev_desc->lba; 338*4bbcc965SRob Clark info->blksz = dev_desc->blksz; 339*4bbcc965SRob Clark info->bootable = 0; 340*4bbcc965SRob Clark strcpy((char *)info->type, BOOT_PART_TYPE); 341*4bbcc965SRob Clark strcpy((char *)info->name, "Whole Disk"); 342*4bbcc965SRob Clark #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 343*4bbcc965SRob Clark info->uuid[0] = 0; 344*4bbcc965SRob Clark #endif 345*4bbcc965SRob Clark #ifdef CONFIG_PARTITION_TYPE_GUID 346*4bbcc965SRob Clark info->type_guid[0] = 0; 347*4bbcc965SRob Clark #endif 348*4bbcc965SRob Clark 349*4bbcc965SRob Clark return 0; 350*4bbcc965SRob Clark } 351*4bbcc965SRob Clark 352ebac37cfSSimon Glass int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, 3534101f687SSimon Glass struct blk_desc **dev_desc) 3542023e608SStephen Warren { 3552023e608SStephen Warren char *ep; 356336b6f90SStephen Warren char *dup_str = NULL; 357336b6f90SStephen Warren const char *dev_str, *hwpart_str; 358336b6f90SStephen Warren int dev, hwpart; 359336b6f90SStephen Warren 360336b6f90SStephen Warren hwpart_str = strchr(dev_hwpart_str, '.'); 361336b6f90SStephen Warren if (hwpart_str) { 362336b6f90SStephen Warren dup_str = strdup(dev_hwpart_str); 363336b6f90SStephen Warren dup_str[hwpart_str - dev_hwpart_str] = 0; 364336b6f90SStephen Warren dev_str = dup_str; 365336b6f90SStephen Warren hwpart_str++; 366336b6f90SStephen Warren } else { 367336b6f90SStephen Warren dev_str = dev_hwpart_str; 368ecdd57e2SStephen Warren hwpart = 0; 369336b6f90SStephen Warren } 3702023e608SStephen Warren 3712023e608SStephen Warren dev = simple_strtoul(dev_str, &ep, 16); 3722023e608SStephen Warren if (*ep) { 3732023e608SStephen Warren printf("** Bad device specification %s %s **\n", 3742023e608SStephen Warren ifname, dev_str); 3751598dfcbSSimon Glass dev = -EINVAL; 376336b6f90SStephen Warren goto cleanup; 3772023e608SStephen Warren } 3782023e608SStephen Warren 379336b6f90SStephen Warren if (hwpart_str) { 380336b6f90SStephen Warren hwpart = simple_strtoul(hwpart_str, &ep, 16); 381336b6f90SStephen Warren if (*ep) { 382336b6f90SStephen Warren printf("** Bad HW partition specification %s %s **\n", 383336b6f90SStephen Warren ifname, hwpart_str); 3841598dfcbSSimon Glass dev = -EINVAL; 385336b6f90SStephen Warren goto cleanup; 386336b6f90SStephen Warren } 387336b6f90SStephen Warren } 388336b6f90SStephen Warren 389336b6f90SStephen Warren *dev_desc = get_dev_hwpart(ifname, dev, hwpart); 3902023e608SStephen Warren if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { 391336b6f90SStephen Warren printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); 3921598dfcbSSimon Glass dev = -ENOENT; 393336b6f90SStephen Warren goto cleanup; 3942023e608SStephen Warren } 3952023e608SStephen Warren 39699e7fc8aSErik Tideman #ifdef HAVE_BLOCK_DEVICE 39799e7fc8aSErik Tideman /* 39899e7fc8aSErik Tideman * Updates the partition table for the specified hw partition. 39999e7fc8aSErik Tideman * Does not need to be done for hwpart 0 since it is default and 40099e7fc8aSErik Tideman * already loaded. 40199e7fc8aSErik Tideman */ 40299e7fc8aSErik Tideman if(hwpart != 0) 4033e8bd469SSimon Glass part_init(*dev_desc); 40499e7fc8aSErik Tideman #endif 40599e7fc8aSErik Tideman 406336b6f90SStephen Warren cleanup: 407336b6f90SStephen Warren free(dup_str); 4082023e608SStephen Warren return dev; 4092023e608SStephen Warren } 4102023e608SStephen Warren 41110a37fd7SStephen Warren #define PART_UNSPECIFIED -2 41210a37fd7SStephen Warren #define PART_AUTO -1 413e35929e4SSimon Glass int blk_get_device_part_str(const char *ifname, const char *dev_part_str, 4144101f687SSimon Glass struct blk_desc **dev_desc, 41510a37fd7SStephen Warren disk_partition_t *info, int allow_whole_dev) 41699d2c205SRob Herring { 41710a37fd7SStephen Warren int ret = -1; 41810a37fd7SStephen Warren const char *part_str; 41910a37fd7SStephen Warren char *dup_str = NULL; 42010a37fd7SStephen Warren const char *dev_str; 42199d2c205SRob Herring int dev; 42210a37fd7SStephen Warren char *ep; 42310a37fd7SStephen Warren int p; 42410a37fd7SStephen Warren int part; 42510a37fd7SStephen Warren disk_partition_t tmpinfo; 42699d2c205SRob Herring 427afc1744eSHans de Goede #ifdef CONFIG_SANDBOX 4284d907025SStephen Warren /* 4293f9eb6e1SPavel Machek * Special-case a pseudo block device "hostfs", to allow access to the 4304d907025SStephen Warren * host's own filesystem. 4314d907025SStephen Warren */ 4324d907025SStephen Warren if (0 == strcmp(ifname, "hostfs")) { 4334d907025SStephen Warren *dev_desc = NULL; 4344d907025SStephen Warren info->start = 0; 4354d907025SStephen Warren info->size = 0; 4364d907025SStephen Warren info->blksz = 0; 4374d907025SStephen Warren info->bootable = 0; 4384d907025SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 4394d907025SStephen Warren strcpy((char *)info->name, "Sandbox host"); 440b331cd62SPatrick Delaunay #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 4414d907025SStephen Warren info->uuid[0] = 0; 4424d907025SStephen Warren #endif 4437561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 4447561b258SPatrick Delaunay info->type_guid[0] = 0; 4457561b258SPatrick Delaunay #endif 4464d907025SStephen Warren 4474d907025SStephen Warren return 0; 4484d907025SStephen Warren } 449afc1744eSHans de Goede #endif 4504d907025SStephen Warren 451251cee0dSHans de Goede #ifdef CONFIG_CMD_UBIFS 452251cee0dSHans de Goede /* 453251cee0dSHans de Goede * Special-case ubi, ubi goes through a mtd, rathen then through 454251cee0dSHans de Goede * a regular block device. 455251cee0dSHans de Goede */ 456251cee0dSHans de Goede if (0 == strcmp(ifname, "ubi")) { 457251cee0dSHans de Goede if (!ubifs_is_mounted()) { 458251cee0dSHans de Goede printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); 459251cee0dSHans de Goede return -1; 460251cee0dSHans de Goede } 461251cee0dSHans de Goede 462251cee0dSHans de Goede *dev_desc = NULL; 463251cee0dSHans de Goede memset(info, 0, sizeof(*info)); 464251cee0dSHans de Goede strcpy((char *)info->type, BOOT_PART_TYPE); 465251cee0dSHans de Goede strcpy((char *)info->name, "UBI"); 466b331cd62SPatrick Delaunay #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 467251cee0dSHans de Goede info->uuid[0] = 0; 468251cee0dSHans de Goede #endif 469251cee0dSHans de Goede return 0; 470251cee0dSHans de Goede } 471251cee0dSHans de Goede #endif 472251cee0dSHans de Goede 47310a37fd7SStephen Warren /* If no dev_part_str, use bootdevice environment variable */ 474a10973e7SStephen Warren if (!dev_part_str || !strlen(dev_part_str) || 475a10973e7SStephen Warren !strcmp(dev_part_str, "-")) 47600caae6dSSimon Glass dev_part_str = env_get("bootdevice"); 47799d2c205SRob Herring 47810a37fd7SStephen Warren /* If still no dev_part_str, it's an error */ 47910a37fd7SStephen Warren if (!dev_part_str) { 48010a37fd7SStephen Warren printf("** No device specified **\n"); 48110a37fd7SStephen Warren goto cleanup; 48299d2c205SRob Herring } 48399d2c205SRob Herring 48410a37fd7SStephen Warren /* Separate device and partition ID specification */ 48510a37fd7SStephen Warren part_str = strchr(dev_part_str, ':'); 48610a37fd7SStephen Warren if (part_str) { 48710a37fd7SStephen Warren dup_str = strdup(dev_part_str); 48810a37fd7SStephen Warren dup_str[part_str - dev_part_str] = 0; 48910a37fd7SStephen Warren dev_str = dup_str; 49010a37fd7SStephen Warren part_str++; 49110a37fd7SStephen Warren } else { 49210a37fd7SStephen Warren dev_str = dev_part_str; 49399d2c205SRob Herring } 49410a37fd7SStephen Warren 49510a37fd7SStephen Warren /* Look up the device */ 496ebac37cfSSimon Glass dev = blk_get_device_by_str(ifname, dev_str, dev_desc); 49710a37fd7SStephen Warren if (dev < 0) 49810a37fd7SStephen Warren goto cleanup; 49910a37fd7SStephen Warren 50010a37fd7SStephen Warren /* Convert partition ID string to number */ 50110a37fd7SStephen Warren if (!part_str || !*part_str) { 50210a37fd7SStephen Warren part = PART_UNSPECIFIED; 50310a37fd7SStephen Warren } else if (!strcmp(part_str, "auto")) { 50410a37fd7SStephen Warren part = PART_AUTO; 50510a37fd7SStephen Warren } else { 50610a37fd7SStephen Warren /* Something specified -> use exactly that */ 50710a37fd7SStephen Warren part = (int)simple_strtoul(part_str, &ep, 16); 50810a37fd7SStephen Warren /* 50910a37fd7SStephen Warren * Less than whole string converted, 51010a37fd7SStephen Warren * or request for whole device, but caller requires partition. 51110a37fd7SStephen Warren */ 51210a37fd7SStephen Warren if (*ep || (part == 0 && !allow_whole_dev)) { 51310a37fd7SStephen Warren printf("** Bad partition specification %s %s **\n", 51410a37fd7SStephen Warren ifname, dev_part_str); 51510a37fd7SStephen Warren goto cleanup; 51610a37fd7SStephen Warren } 51710a37fd7SStephen Warren } 51810a37fd7SStephen Warren 51910a37fd7SStephen Warren /* 52010a37fd7SStephen Warren * No partition table on device, 52110a37fd7SStephen Warren * or user requested partition 0 (entire device). 52210a37fd7SStephen Warren */ 52310a37fd7SStephen Warren if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 52410a37fd7SStephen Warren (part == 0)) { 52510a37fd7SStephen Warren if (!(*dev_desc)->lba) { 52610a37fd7SStephen Warren printf("** Bad device size - %s %s **\n", ifname, 52710a37fd7SStephen Warren dev_str); 52810a37fd7SStephen Warren goto cleanup; 52910a37fd7SStephen Warren } 53010a37fd7SStephen Warren 53110a37fd7SStephen Warren /* 53210a37fd7SStephen Warren * If user specified a partition ID other than 0, 53310a37fd7SStephen Warren * or the calling command only accepts partitions, 53410a37fd7SStephen Warren * it's an error. 53510a37fd7SStephen Warren */ 53610a37fd7SStephen Warren if ((part > 0) || (!allow_whole_dev)) { 53710a37fd7SStephen Warren printf("** No partition table - %s %s **\n", ifname, 53810a37fd7SStephen Warren dev_str); 53910a37fd7SStephen Warren goto cleanup; 54010a37fd7SStephen Warren } 54110a37fd7SStephen Warren 54250ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 54350ffc3b6SLan Yixun (dlan) 544*4bbcc965SRob Clark part_get_info_whole_disk(*dev_desc, info); 54599d2c205SRob Herring 54610a37fd7SStephen Warren ret = 0; 54710a37fd7SStephen Warren goto cleanup; 54899d2c205SRob Herring } 54999d2c205SRob Herring 55010a37fd7SStephen Warren /* 55110a37fd7SStephen Warren * Now there's known to be a partition table, 55210a37fd7SStephen Warren * not specifying a partition means to pick partition 1. 55310a37fd7SStephen Warren */ 55410a37fd7SStephen Warren if (part == PART_UNSPECIFIED) 55510a37fd7SStephen Warren part = 1; 55699d2c205SRob Herring 55710a37fd7SStephen Warren /* 55810a37fd7SStephen Warren * If user didn't specify a partition number, or did specify something 55910a37fd7SStephen Warren * other than "auto", use that partition number directly. 56010a37fd7SStephen Warren */ 56110a37fd7SStephen Warren if (part != PART_AUTO) { 5623e8bd469SSimon Glass ret = part_get_info(*dev_desc, part, info); 56399d2c205SRob Herring if (ret) { 56410a37fd7SStephen Warren printf("** Invalid partition %d **\n", part); 56510a37fd7SStephen Warren goto cleanup; 56610a37fd7SStephen Warren } 56710a37fd7SStephen Warren } else { 56810a37fd7SStephen Warren /* 56910a37fd7SStephen Warren * Find the first bootable partition. 57010a37fd7SStephen Warren * If none are bootable, fall back to the first valid partition. 57110a37fd7SStephen Warren */ 57210a37fd7SStephen Warren part = 0; 57310a37fd7SStephen Warren for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 5743e8bd469SSimon Glass ret = part_get_info(*dev_desc, p, info); 57510a37fd7SStephen Warren if (ret) 57610a37fd7SStephen Warren continue; 57710a37fd7SStephen Warren 57810a37fd7SStephen Warren /* 57910a37fd7SStephen Warren * First valid partition, or new better partition? 58010a37fd7SStephen Warren * If so, save partition ID. 58110a37fd7SStephen Warren */ 58210a37fd7SStephen Warren if (!part || info->bootable) 58310a37fd7SStephen Warren part = p; 58410a37fd7SStephen Warren 58510a37fd7SStephen Warren /* Best possible partition? Stop searching. */ 58610a37fd7SStephen Warren if (info->bootable) 58710a37fd7SStephen Warren break; 58810a37fd7SStephen Warren 58910a37fd7SStephen Warren /* 59010a37fd7SStephen Warren * We now need to search further for best possible. 59110a37fd7SStephen Warren * If we what we just queried was the best so far, 59210a37fd7SStephen Warren * save the info since we over-write it next loop. 59310a37fd7SStephen Warren */ 59410a37fd7SStephen Warren if (part == p) 59510a37fd7SStephen Warren tmpinfo = *info; 59610a37fd7SStephen Warren } 59710a37fd7SStephen Warren /* If we found any acceptable partition */ 59810a37fd7SStephen Warren if (part) { 59910a37fd7SStephen Warren /* 60010a37fd7SStephen Warren * If we searched all possible partition IDs, 60110a37fd7SStephen Warren * return the first valid partition we found. 60210a37fd7SStephen Warren */ 60310a37fd7SStephen Warren if (p == MAX_SEARCH_PARTITIONS + 1) 60410a37fd7SStephen Warren *info = tmpinfo; 60510a37fd7SStephen Warren } else { 60610a37fd7SStephen Warren printf("** No valid partitions found **\n"); 60771bba424SStephen Warren ret = -1; 60810a37fd7SStephen Warren goto cleanup; 60910a37fd7SStephen Warren } 61099d2c205SRob Herring } 61199d2c205SRob Herring if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 61299d2c205SRob Herring printf("** Invalid partition type \"%.32s\"" 61399d2c205SRob Herring " (expect \"" BOOT_PART_TYPE "\")\n", 61499d2c205SRob Herring info->type); 61510a37fd7SStephen Warren ret = -1; 61610a37fd7SStephen Warren goto cleanup; 61799d2c205SRob Herring } 61899d2c205SRob Herring 61950ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 62050ffc3b6SLan Yixun (dlan) 62110a37fd7SStephen Warren ret = part; 62210a37fd7SStephen Warren goto cleanup; 62399d2c205SRob Herring 62410a37fd7SStephen Warren cleanup: 62510a37fd7SStephen Warren free(dup_str); 62610a37fd7SStephen Warren return ret; 62799d2c205SRob Herring } 62887b8530fSPetr Kulhavy 62987b8530fSPetr Kulhavy int part_get_info_by_name(struct blk_desc *dev_desc, const char *name, 63087b8530fSPetr Kulhavy disk_partition_t *info) 63187b8530fSPetr Kulhavy { 63287b8530fSPetr Kulhavy struct part_driver *first_drv = 63387b8530fSPetr Kulhavy ll_entry_start(struct part_driver, part_driver); 63487b8530fSPetr Kulhavy const int n_drvs = ll_entry_count(struct part_driver, part_driver); 63587b8530fSPetr Kulhavy struct part_driver *part_drv; 63687b8530fSPetr Kulhavy 63787b8530fSPetr Kulhavy for (part_drv = first_drv; part_drv != first_drv + n_drvs; part_drv++) { 63887b8530fSPetr Kulhavy int ret; 63987b8530fSPetr Kulhavy int i; 64087b8530fSPetr Kulhavy for (i = 1; i < part_drv->max_entries; i++) { 64187b8530fSPetr Kulhavy ret = part_drv->get_info(dev_desc, i, info); 64287b8530fSPetr Kulhavy if (ret != 0) { 64387b8530fSPetr Kulhavy /* no more entries in table */ 64487b8530fSPetr Kulhavy break; 64587b8530fSPetr Kulhavy } 64687b8530fSPetr Kulhavy if (strcmp(name, (const char *)info->name) == 0) { 64787b8530fSPetr Kulhavy /* matched */ 64888b6329cSAlex Deymo return i; 64987b8530fSPetr Kulhavy } 65087b8530fSPetr Kulhavy } 65187b8530fSPetr Kulhavy } 65287b8530fSPetr Kulhavy return -1; 65387b8530fSPetr Kulhavy } 654da2ee24dSPetr Kulhavy 655da2ee24dSPetr Kulhavy void part_set_generic_name(const struct blk_desc *dev_desc, 656da2ee24dSPetr Kulhavy int part_num, char *name) 657da2ee24dSPetr Kulhavy { 658da2ee24dSPetr Kulhavy char *devtype; 659da2ee24dSPetr Kulhavy 660da2ee24dSPetr Kulhavy switch (dev_desc->if_type) { 661da2ee24dSPetr Kulhavy case IF_TYPE_IDE: 662da2ee24dSPetr Kulhavy case IF_TYPE_SATA: 663da2ee24dSPetr Kulhavy case IF_TYPE_ATAPI: 664da2ee24dSPetr Kulhavy devtype = "hd"; 665da2ee24dSPetr Kulhavy break; 666da2ee24dSPetr Kulhavy case IF_TYPE_SCSI: 667da2ee24dSPetr Kulhavy devtype = "sd"; 668da2ee24dSPetr Kulhavy break; 669da2ee24dSPetr Kulhavy case IF_TYPE_USB: 670da2ee24dSPetr Kulhavy devtype = "usbd"; 671da2ee24dSPetr Kulhavy break; 672da2ee24dSPetr Kulhavy case IF_TYPE_DOC: 673da2ee24dSPetr Kulhavy devtype = "docd"; 674da2ee24dSPetr Kulhavy break; 675da2ee24dSPetr Kulhavy case IF_TYPE_MMC: 676da2ee24dSPetr Kulhavy case IF_TYPE_SD: 677da2ee24dSPetr Kulhavy devtype = "mmcsd"; 678da2ee24dSPetr Kulhavy break; 679da2ee24dSPetr Kulhavy default: 680da2ee24dSPetr Kulhavy devtype = "xx"; 681da2ee24dSPetr Kulhavy break; 682da2ee24dSPetr Kulhavy } 683da2ee24dSPetr Kulhavy 684da2ee24dSPetr Kulhavy sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num); 685da2ee24dSPetr Kulhavy } 686