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 24d96a9804SAlexander Graf const struct block_drvr block_drvr[] = { 25cde5c64dSJon Loeliger #if defined(CONFIG_CMD_IDE) 26735dd97bSGrant Likely { .name = "ide", .get_dev = ide_get_dev, }, 27735dd97bSGrant Likely #endif 28c7057b52SDave Liu #if defined(CONFIG_CMD_SATA) 29c7057b52SDave Liu {.name = "sata", .get_dev = sata_get_dev, }, 30c7057b52SDave Liu #endif 31cde5c64dSJon Loeliger #if defined(CONFIG_CMD_SCSI) 32735dd97bSGrant Likely { .name = "scsi", .get_dev = scsi_get_dev, }, 33735dd97bSGrant Likely #endif 34cde5c64dSJon Loeliger #if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) 35735dd97bSGrant Likely { .name = "usb", .get_dev = usb_stor_get_dev, }, 36735dd97bSGrant Likely #endif 37735dd97bSGrant Likely #if defined(CONFIG_MMC) 38d2356284SStephen Warren { 39d2356284SStephen Warren .name = "mmc", 40d2356284SStephen Warren .get_dev = mmc_get_dev, 41d2356284SStephen Warren .select_hwpart = mmc_select_hwpart, 42d2356284SStephen Warren }, 43735dd97bSGrant Likely #endif 44735dd97bSGrant Likely #if defined(CONFIG_SYSTEMACE) 45735dd97bSGrant Likely { .name = "ace", .get_dev = systemace_get_dev, }, 46735dd97bSGrant Likely #endif 47f4d8de48SHenrik Nordström #if defined(CONFIG_SANDBOX) 48f4d8de48SHenrik Nordström { .name = "host", .get_dev = host_get_dev, }, 49f4d8de48SHenrik Nordström #endif 50735dd97bSGrant Likely { }, 51735dd97bSGrant Likely }; 52735dd97bSGrant Likely 53751bb571SStefan Roese DECLARE_GLOBAL_DATA_PTR; 54751bb571SStefan Roese 550c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 5696e5b03cSSimon Glass static struct part_driver *part_driver_lookup_type(int part_type) 5796e5b03cSSimon Glass { 5896e5b03cSSimon Glass struct part_driver *drv = 5996e5b03cSSimon Glass ll_entry_start(struct part_driver, part_driver); 6096e5b03cSSimon Glass const int n_ents = ll_entry_count(struct part_driver, part_driver); 6196e5b03cSSimon Glass struct part_driver *entry; 6296e5b03cSSimon Glass 6396e5b03cSSimon Glass for (entry = drv; entry != drv + n_ents; entry++) { 6496e5b03cSSimon Glass if (part_type == entry->part_type) 6596e5b03cSSimon Glass return entry; 6696e5b03cSSimon Glass } 6796e5b03cSSimon Glass 6896e5b03cSSimon Glass /* Not found */ 6996e5b03cSSimon Glass return NULL; 7096e5b03cSSimon Glass } 7196e5b03cSSimon Glass 724101f687SSimon Glass static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 73735dd97bSGrant Likely { 74735dd97bSGrant Likely const struct block_drvr *drvr = block_drvr; 754101f687SSimon Glass struct blk_desc* (*reloc_get_dev)(int dev); 76336b6f90SStephen Warren int (*select_hwpart)(int dev_num, int hwpart); 7723090dacSHeiko Schocher char *name; 78336b6f90SStephen Warren int ret; 79751bb571SStefan Roese 807e71dc68STim Kientzle if (!ifname) 817e71dc68STim Kientzle return NULL; 827e71dc68STim Kientzle 8323090dacSHeiko Schocher name = drvr->name; 842e5167ccSWolfgang Denk #ifdef CONFIG_NEEDS_MANUAL_RELOC 8523090dacSHeiko Schocher name += gd->reloc_off; 8623090dacSHeiko Schocher #endif 87b16aadf4SLei Wen while (drvr->name) { 8823090dacSHeiko Schocher name = drvr->name; 89521af04dSPeter Tyser reloc_get_dev = drvr->get_dev; 90336b6f90SStephen Warren select_hwpart = drvr->select_hwpart; 912e5167ccSWolfgang Denk #ifdef CONFIG_NEEDS_MANUAL_RELOC 9223090dacSHeiko Schocher name += gd->reloc_off; 93521af04dSPeter Tyser reloc_get_dev += gd->reloc_off; 94336b6f90SStephen Warren if (select_hwpart) 95336b6f90SStephen Warren select_hwpart += gd->reloc_off; 96521af04dSPeter Tyser #endif 97336b6f90SStephen Warren if (strncmp(ifname, name, strlen(name)) == 0) { 984101f687SSimon Glass struct blk_desc *dev_desc = reloc_get_dev(dev); 99336b6f90SStephen Warren if (!dev_desc) 100336b6f90SStephen Warren return NULL; 101ecdd57e2SStephen Warren if (hwpart == 0 && !select_hwpart) 102336b6f90SStephen Warren return dev_desc; 103336b6f90SStephen Warren if (!select_hwpart) 104336b6f90SStephen Warren return NULL; 105bcce53d0SSimon Glass ret = select_hwpart(dev_desc->devnum, hwpart); 106336b6f90SStephen Warren if (ret < 0) 107336b6f90SStephen Warren return NULL; 108336b6f90SStephen Warren return dev_desc; 109336b6f90SStephen Warren } 110735dd97bSGrant Likely drvr++; 111735dd97bSGrant Likely } 112735dd97bSGrant Likely return NULL; 113735dd97bSGrant Likely } 114336b6f90SStephen Warren 115db1d9e78SSimon Glass struct blk_desc *blk_get_dev(const char *ifname, int dev) 116336b6f90SStephen Warren { 117ecdd57e2SStephen Warren return get_dev_hwpart(ifname, dev, 0); 118336b6f90SStephen Warren } 119735dd97bSGrant Likely #else 1204101f687SSimon Glass struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 121336b6f90SStephen Warren { 122336b6f90SStephen Warren return NULL; 123336b6f90SStephen Warren } 124336b6f90SStephen Warren 125db1d9e78SSimon Glass struct blk_desc *blk_get_dev(const char *ifname, int dev) 126735dd97bSGrant Likely { 127735dd97bSGrant Likely return NULL; 128735dd97bSGrant Likely } 129735dd97bSGrant Likely #endif 130735dd97bSGrant Likely 1310c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 132735dd97bSGrant Likely 133affae2bfSwdenk /* ------------------------------------------------------------------------- */ 134affae2bfSwdenk /* 135affae2bfSwdenk * reports device info to the user 136affae2bfSwdenk */ 13769a2a4d9SSergei Trofimovich 13869a2a4d9SSergei Trofimovich #ifdef CONFIG_LBA48 13969a2a4d9SSergei Trofimovich typedef uint64_t lba512_t; 14069a2a4d9SSergei Trofimovich #else 14169a2a4d9SSergei Trofimovich typedef lbaint_t lba512_t; 14269a2a4d9SSergei Trofimovich #endif 14369a2a4d9SSergei Trofimovich 14469a2a4d9SSergei Trofimovich /* 14569a2a4d9SSergei Trofimovich * Overflowless variant of (block_count * mul_by / div_by) 14669a2a4d9SSergei Trofimovich * when div_by > mul_by 14769a2a4d9SSergei Trofimovich */ 14869a2a4d9SSergei Trofimovich static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, lba512_t div_by) 14969a2a4d9SSergei Trofimovich { 15069a2a4d9SSergei Trofimovich lba512_t bc_quot, bc_rem; 15169a2a4d9SSergei Trofimovich 15269a2a4d9SSergei Trofimovich /* x * m / d == x / d * m + (x % d) * m / d */ 15369a2a4d9SSergei Trofimovich bc_quot = block_count / div_by; 15469a2a4d9SSergei Trofimovich bc_rem = block_count - div_by * bc_quot; 15569a2a4d9SSergei Trofimovich return bc_quot * mul_by + (bc_rem * mul_by) / div_by; 15669a2a4d9SSergei Trofimovich } 15769a2a4d9SSergei Trofimovich 1584101f687SSimon Glass void dev_print (struct blk_desc *dev_desc) 159affae2bfSwdenk { 16069a2a4d9SSergei Trofimovich lba512_t lba512; /* number of blocks if 512bytes block size */ 161affae2bfSwdenk 162af75a45dSWolfgang Denk if (dev_desc->type == DEV_TYPE_UNKNOWN) { 163af75a45dSWolfgang Denk puts ("not available\n"); 164af75a45dSWolfgang Denk return; 165af75a45dSWolfgang Denk } 166af75a45dSWolfgang Denk 1678ec6e332STor Krill switch (dev_desc->if_type) { 168574b3195SDetlev Zundel case IF_TYPE_SCSI: 169574b3195SDetlev Zundel printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n", 170574b3195SDetlev Zundel dev_desc->target,dev_desc->lun, 171affae2bfSwdenk dev_desc->vendor, 172affae2bfSwdenk dev_desc->product, 173affae2bfSwdenk dev_desc->revision); 174574b3195SDetlev Zundel break; 1756e24a1ebSRemy Bohmer case IF_TYPE_ATAPI: 176574b3195SDetlev Zundel case IF_TYPE_IDE: 177574b3195SDetlev Zundel case IF_TYPE_SATA: 178574b3195SDetlev Zundel printf ("Model: %s Firm: %s Ser#: %s\n", 179574b3195SDetlev Zundel dev_desc->vendor, 180574b3195SDetlev Zundel dev_desc->revision, 181574b3195SDetlev Zundel dev_desc->product); 182574b3195SDetlev Zundel break; 1836e24a1ebSRemy Bohmer case IF_TYPE_SD: 1846e24a1ebSRemy Bohmer case IF_TYPE_MMC: 18547bebe34SNícolas Carneiro Lebedenco case IF_TYPE_USB: 18647bebe34SNícolas Carneiro Lebedenco printf ("Vendor: %s Rev: %s Prod: %s\n", 18747bebe34SNícolas Carneiro Lebedenco dev_desc->vendor, 18847bebe34SNícolas Carneiro Lebedenco dev_desc->revision, 18947bebe34SNícolas Carneiro Lebedenco dev_desc->product); 19047bebe34SNícolas Carneiro Lebedenco break; 1916e24a1ebSRemy Bohmer case IF_TYPE_DOC: 1926e24a1ebSRemy Bohmer puts("device type DOC\n"); 1936e24a1ebSRemy Bohmer return; 1948ec6e332STor Krill case IF_TYPE_UNKNOWN: 1956e24a1ebSRemy Bohmer puts("device type unknown\n"); 1966e24a1ebSRemy Bohmer return; 197574b3195SDetlev Zundel default: 1986e24a1ebSRemy Bohmer printf("Unhandled device type: %i\n", dev_desc->if_type); 199574b3195SDetlev Zundel return; 200affae2bfSwdenk } 201affae2bfSwdenk puts (" Type: "); 202affae2bfSwdenk if (dev_desc->removable) 203affae2bfSwdenk puts ("Removable "); 204affae2bfSwdenk switch (dev_desc->type & 0x1F) { 205726c0f1eSDetlev Zundel case DEV_TYPE_HARDDISK: 206726c0f1eSDetlev Zundel puts ("Hard Disk"); 207affae2bfSwdenk break; 208726c0f1eSDetlev Zundel case DEV_TYPE_CDROM: 209726c0f1eSDetlev Zundel puts ("CD ROM"); 210affae2bfSwdenk break; 211726c0f1eSDetlev Zundel case DEV_TYPE_OPDISK: 212726c0f1eSDetlev Zundel puts ("Optical Device"); 213affae2bfSwdenk break; 214726c0f1eSDetlev Zundel case DEV_TYPE_TAPE: 215726c0f1eSDetlev Zundel puts ("Tape"); 216affae2bfSwdenk break; 217726c0f1eSDetlev Zundel default: 218726c0f1eSDetlev Zundel printf ("# %02X #", dev_desc->type & 0x1F); 219affae2bfSwdenk break; 220affae2bfSwdenk } 221affae2bfSwdenk puts ("\n"); 22233699df1SJerry Huang if (dev_desc->lba > 0L && dev_desc->blksz > 0L) { 223affae2bfSwdenk ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem; 224c40b2956Swdenk lbaint_t lba; 2256e592385Swdenk 226c40b2956Swdenk lba = dev_desc->lba; 227affae2bfSwdenk 228c40b2956Swdenk lba512 = (lba * (dev_desc->blksz/512)); 229affae2bfSwdenk /* round to 1 digit */ 230214b3f31SPavel Machek /* 2048 = (1024 * 1024) / 512 MB */ 231214b3f31SPavel Machek mb = lba512_muldiv(lba512, 10, 2048); 23269a2a4d9SSergei Trofimovich 233affae2bfSwdenk mb_quot = mb / 10; 234affae2bfSwdenk mb_rem = mb - (10 * mb_quot); 235affae2bfSwdenk 236affae2bfSwdenk gb = mb / 1024; 237affae2bfSwdenk gb_quot = gb / 10; 238affae2bfSwdenk gb_rem = gb - (10 * gb_quot); 23942dfe7a1Swdenk #ifdef CONFIG_LBA48 2406e592385Swdenk if (dev_desc->lba48) 241c40b2956Swdenk printf (" Supports 48-bit addressing\n"); 242c40b2956Swdenk #endif 2434b142febSHeiko Schocher #if defined(CONFIG_SYS_64BIT_LBA) 2446c6166f5SMike Frysinger printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n", 245c40b2956Swdenk mb_quot, mb_rem, 246c40b2956Swdenk gb_quot, gb_rem, 247c40b2956Swdenk lba, 248c40b2956Swdenk dev_desc->blksz); 249c40b2956Swdenk #else 250affae2bfSwdenk printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n", 251affae2bfSwdenk mb_quot, mb_rem, 252affae2bfSwdenk gb_quot, gb_rem, 253c40b2956Swdenk (ulong)lba, 254affae2bfSwdenk dev_desc->blksz); 255c40b2956Swdenk #endif 256affae2bfSwdenk } else { 257affae2bfSwdenk puts (" Capacity: not available\n"); 258affae2bfSwdenk } 259affae2bfSwdenk } 260b3aff0cbSJon Loeliger #endif 261affae2bfSwdenk 2620c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 263affae2bfSwdenk 2643e8bd469SSimon Glass void part_init(struct blk_desc *dev_desc) 265affae2bfSwdenk { 26696e5b03cSSimon Glass struct part_driver *drv = 26796e5b03cSSimon Glass ll_entry_start(struct part_driver, part_driver); 26896e5b03cSSimon Glass const int n_ents = ll_entry_count(struct part_driver, part_driver); 26996e5b03cSSimon Glass struct part_driver *entry; 270affae2bfSwdenk 271*e40cf34aSEric Nelson blkcache_invalidate(dev_desc->if_type, dev_desc->devnum); 272*e40cf34aSEric Nelson 27399d2c205SRob Herring dev_desc->part_type = PART_TYPE_UNKNOWN; 27496e5b03cSSimon Glass for (entry = drv; entry != drv + n_ents; entry++) { 27596e5b03cSSimon Glass int ret; 27696e5b03cSSimon Glass 27796e5b03cSSimon Glass ret = entry->test(dev_desc); 27896e5b03cSSimon Glass debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret); 27996e5b03cSSimon Glass if (!ret) { 28096e5b03cSSimon Glass dev_desc->part_type = entry->part_type; 28196e5b03cSSimon Glass break; 28296e5b03cSSimon Glass } 28396e5b03cSSimon Glass } 284affae2bfSwdenk } 285affae2bfSwdenk 28696e5b03cSSimon Glass static void print_part_header(const char *type, struct blk_desc *dev_desc) 28796e5b03cSSimon Glass { 2880c9c8fb5SGabe Black #if defined(CONFIG_MAC_PARTITION) || \ 2890c9c8fb5SGabe Black defined(CONFIG_DOS_PARTITION) || \ 2900c9c8fb5SGabe Black defined(CONFIG_ISO_PARTITION) || \ 2910c9c8fb5SGabe Black defined(CONFIG_AMIGA_PARTITION) || \ 2920c9c8fb5SGabe Black defined(CONFIG_EFI_PARTITION) 293affae2bfSwdenk puts ("\nPartition Map for "); 294affae2bfSwdenk switch (dev_desc->if_type) { 295726c0f1eSDetlev Zundel case IF_TYPE_IDE: 296726c0f1eSDetlev Zundel puts ("IDE"); 297affae2bfSwdenk break; 298726c0f1eSDetlev Zundel case IF_TYPE_SATA: 299726c0f1eSDetlev Zundel puts ("SATA"); 300c7057b52SDave Liu break; 301726c0f1eSDetlev Zundel case IF_TYPE_SCSI: 302726c0f1eSDetlev Zundel puts ("SCSI"); 303affae2bfSwdenk break; 304726c0f1eSDetlev Zundel case IF_TYPE_ATAPI: 305726c0f1eSDetlev Zundel puts ("ATAPI"); 306affae2bfSwdenk break; 307726c0f1eSDetlev Zundel case IF_TYPE_USB: 308726c0f1eSDetlev Zundel puts ("USB"); 309affae2bfSwdenk break; 310726c0f1eSDetlev Zundel case IF_TYPE_DOC: 311726c0f1eSDetlev Zundel puts ("DOC"); 312affae2bfSwdenk break; 3138f3b9642SLei Wen case IF_TYPE_MMC: 3148f3b9642SLei Wen puts ("MMC"); 3158f3b9642SLei Wen break; 316f4d8de48SHenrik Nordström case IF_TYPE_HOST: 317f4d8de48SHenrik Nordström puts("HOST"); 318f4d8de48SHenrik Nordström break; 319726c0f1eSDetlev Zundel default: 320726c0f1eSDetlev Zundel puts ("UNKNOWN"); 321affae2bfSwdenk break; 322affae2bfSwdenk } 323affae2bfSwdenk printf (" device %d -- Partition Type: %s\n\n", 324bcce53d0SSimon Glass dev_desc->devnum, type); 3250c9c8fb5SGabe Black #endif /* any CONFIG_..._PARTITION */ 32696e5b03cSSimon Glass } 3270c9c8fb5SGabe Black 3283e8bd469SSimon Glass void part_print(struct blk_desc *dev_desc) 329affae2bfSwdenk { 33096e5b03cSSimon Glass struct part_driver *drv; 331affae2bfSwdenk 33296e5b03cSSimon Glass drv = part_driver_lookup_type(dev_desc->part_type); 33396e5b03cSSimon Glass if (!drv) { 33496e5b03cSSimon Glass printf("## Unknown partition table type %x\n", 33596e5b03cSSimon Glass dev_desc->part_type); 336affae2bfSwdenk return; 337affae2bfSwdenk } 33896e5b03cSSimon Glass 33996e5b03cSSimon Glass PRINTF("## Testing for valid %s partition ##\n", drv->name); 34096e5b03cSSimon Glass print_part_header(drv->name, dev_desc); 34196e5b03cSSimon Glass if (drv->print) 34296e5b03cSSimon Glass drv->print(dev_desc); 343affae2bfSwdenk } 344affae2bfSwdenk 3450c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 3462f501646SStephen Warren 3473e8bd469SSimon Glass int part_get_info(struct blk_desc *dev_desc, int part, 3483f9eb6e1SPavel Machek disk_partition_t *info) 3492f501646SStephen Warren { 3500c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 35196e5b03cSSimon Glass struct part_driver *drv; 3522f501646SStephen Warren 353894bfbbfSStephen Warren #ifdef CONFIG_PARTITION_UUIDS 354894bfbbfSStephen Warren /* The common case is no UUID support */ 355894bfbbfSStephen Warren info->uuid[0] = 0; 356894bfbbfSStephen Warren #endif 3577561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 3587561b258SPatrick Delaunay info->type_guid[0] = 0; 3597561b258SPatrick Delaunay #endif 360894bfbbfSStephen Warren 36196e5b03cSSimon Glass drv = part_driver_lookup_type(dev_desc->part_type); 36296e5b03cSSimon Glass if (!drv) { 36396e5b03cSSimon Glass debug("## Unknown partition table type %x\n", 36496e5b03cSSimon Glass dev_desc->part_type); 36596e5b03cSSimon Glass return -EPROTONOSUPPORT; 3662f501646SStephen Warren } 36796e5b03cSSimon Glass if (!drv->get_info) { 36896e5b03cSSimon Glass PRINTF("## Driver %s does not have the get_info() method\n"); 36996e5b03cSSimon Glass return -ENOSYS; 3702f501646SStephen Warren } 37196e5b03cSSimon Glass if (drv->get_info(dev_desc, part, info) == 0) { 37296e5b03cSSimon Glass PRINTF("## Valid %s partition found ##\n", drv->name); 3732f501646SStephen Warren return 0; 3742f501646SStephen Warren } 3750c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 3762f501646SStephen Warren 3772f501646SStephen Warren return -1; 3782f501646SStephen Warren } 37999d2c205SRob Herring 380ebac37cfSSimon Glass int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, 3814101f687SSimon Glass struct blk_desc **dev_desc) 3822023e608SStephen Warren { 3832023e608SStephen Warren char *ep; 384336b6f90SStephen Warren char *dup_str = NULL; 385336b6f90SStephen Warren const char *dev_str, *hwpart_str; 386336b6f90SStephen Warren int dev, hwpart; 387336b6f90SStephen Warren 388336b6f90SStephen Warren hwpart_str = strchr(dev_hwpart_str, '.'); 389336b6f90SStephen Warren if (hwpart_str) { 390336b6f90SStephen Warren dup_str = strdup(dev_hwpart_str); 391336b6f90SStephen Warren dup_str[hwpart_str - dev_hwpart_str] = 0; 392336b6f90SStephen Warren dev_str = dup_str; 393336b6f90SStephen Warren hwpart_str++; 394336b6f90SStephen Warren } else { 395336b6f90SStephen Warren dev_str = dev_hwpart_str; 396ecdd57e2SStephen Warren hwpart = 0; 397336b6f90SStephen Warren } 3982023e608SStephen Warren 3992023e608SStephen Warren dev = simple_strtoul(dev_str, &ep, 16); 4002023e608SStephen Warren if (*ep) { 4012023e608SStephen Warren printf("** Bad device specification %s %s **\n", 4022023e608SStephen Warren ifname, dev_str); 403336b6f90SStephen Warren dev = -1; 404336b6f90SStephen Warren goto cleanup; 4052023e608SStephen Warren } 4062023e608SStephen Warren 407336b6f90SStephen Warren if (hwpart_str) { 408336b6f90SStephen Warren hwpart = simple_strtoul(hwpart_str, &ep, 16); 409336b6f90SStephen Warren if (*ep) { 410336b6f90SStephen Warren printf("** Bad HW partition specification %s %s **\n", 411336b6f90SStephen Warren ifname, hwpart_str); 412336b6f90SStephen Warren dev = -1; 413336b6f90SStephen Warren goto cleanup; 414336b6f90SStephen Warren } 415336b6f90SStephen Warren } 416336b6f90SStephen Warren 417336b6f90SStephen Warren *dev_desc = get_dev_hwpart(ifname, dev, hwpart); 4182023e608SStephen Warren if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { 419336b6f90SStephen Warren printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); 420336b6f90SStephen Warren dev = -1; 421336b6f90SStephen Warren goto cleanup; 4222023e608SStephen Warren } 4232023e608SStephen Warren 42499e7fc8aSErik Tideman #ifdef HAVE_BLOCK_DEVICE 42599e7fc8aSErik Tideman /* 42699e7fc8aSErik Tideman * Updates the partition table for the specified hw partition. 42799e7fc8aSErik Tideman * Does not need to be done for hwpart 0 since it is default and 42899e7fc8aSErik Tideman * already loaded. 42999e7fc8aSErik Tideman */ 43099e7fc8aSErik Tideman if(hwpart != 0) 4313e8bd469SSimon Glass part_init(*dev_desc); 43299e7fc8aSErik Tideman #endif 43399e7fc8aSErik Tideman 434336b6f90SStephen Warren cleanup: 435336b6f90SStephen Warren free(dup_str); 4362023e608SStephen Warren return dev; 4372023e608SStephen Warren } 4382023e608SStephen Warren 43910a37fd7SStephen Warren #define PART_UNSPECIFIED -2 44010a37fd7SStephen Warren #define PART_AUTO -1 44110a37fd7SStephen Warren #define MAX_SEARCH_PARTITIONS 16 442e35929e4SSimon Glass int blk_get_device_part_str(const char *ifname, const char *dev_part_str, 4434101f687SSimon Glass struct blk_desc **dev_desc, 44410a37fd7SStephen Warren disk_partition_t *info, int allow_whole_dev) 44599d2c205SRob Herring { 44610a37fd7SStephen Warren int ret = -1; 44710a37fd7SStephen Warren const char *part_str; 44810a37fd7SStephen Warren char *dup_str = NULL; 44910a37fd7SStephen Warren const char *dev_str; 45099d2c205SRob Herring int dev; 45110a37fd7SStephen Warren char *ep; 45210a37fd7SStephen Warren int p; 45310a37fd7SStephen Warren int part; 45410a37fd7SStephen Warren disk_partition_t tmpinfo; 45599d2c205SRob Herring 456afc1744eSHans de Goede #ifdef CONFIG_SANDBOX 4574d907025SStephen Warren /* 4583f9eb6e1SPavel Machek * Special-case a pseudo block device "hostfs", to allow access to the 4594d907025SStephen Warren * host's own filesystem. 4604d907025SStephen Warren */ 4614d907025SStephen Warren if (0 == strcmp(ifname, "hostfs")) { 4624d907025SStephen Warren *dev_desc = NULL; 4634d907025SStephen Warren info->start = 0; 4644d907025SStephen Warren info->size = 0; 4654d907025SStephen Warren info->blksz = 0; 4664d907025SStephen Warren info->bootable = 0; 4674d907025SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 4684d907025SStephen Warren strcpy((char *)info->name, "Sandbox host"); 4694d907025SStephen Warren #ifdef CONFIG_PARTITION_UUIDS 4704d907025SStephen Warren info->uuid[0] = 0; 4714d907025SStephen Warren #endif 4727561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 4737561b258SPatrick Delaunay info->type_guid[0] = 0; 4747561b258SPatrick Delaunay #endif 4754d907025SStephen Warren 4764d907025SStephen Warren return 0; 4774d907025SStephen Warren } 478afc1744eSHans de Goede #endif 4794d907025SStephen Warren 480251cee0dSHans de Goede #ifdef CONFIG_CMD_UBIFS 481251cee0dSHans de Goede /* 482251cee0dSHans de Goede * Special-case ubi, ubi goes through a mtd, rathen then through 483251cee0dSHans de Goede * a regular block device. 484251cee0dSHans de Goede */ 485251cee0dSHans de Goede if (0 == strcmp(ifname, "ubi")) { 486251cee0dSHans de Goede if (!ubifs_is_mounted()) { 487251cee0dSHans de Goede printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); 488251cee0dSHans de Goede return -1; 489251cee0dSHans de Goede } 490251cee0dSHans de Goede 491251cee0dSHans de Goede *dev_desc = NULL; 492251cee0dSHans de Goede memset(info, 0, sizeof(*info)); 493251cee0dSHans de Goede strcpy((char *)info->type, BOOT_PART_TYPE); 494251cee0dSHans de Goede strcpy((char *)info->name, "UBI"); 495251cee0dSHans de Goede #ifdef CONFIG_PARTITION_UUIDS 496251cee0dSHans de Goede info->uuid[0] = 0; 497251cee0dSHans de Goede #endif 498251cee0dSHans de Goede return 0; 499251cee0dSHans de Goede } 500251cee0dSHans de Goede #endif 501251cee0dSHans de Goede 50210a37fd7SStephen Warren /* If no dev_part_str, use bootdevice environment variable */ 503a10973e7SStephen Warren if (!dev_part_str || !strlen(dev_part_str) || 504a10973e7SStephen Warren !strcmp(dev_part_str, "-")) 50510a37fd7SStephen Warren dev_part_str = getenv("bootdevice"); 50699d2c205SRob Herring 50710a37fd7SStephen Warren /* If still no dev_part_str, it's an error */ 50810a37fd7SStephen Warren if (!dev_part_str) { 50910a37fd7SStephen Warren printf("** No device specified **\n"); 51010a37fd7SStephen Warren goto cleanup; 51199d2c205SRob Herring } 51299d2c205SRob Herring 51310a37fd7SStephen Warren /* Separate device and partition ID specification */ 51410a37fd7SStephen Warren part_str = strchr(dev_part_str, ':'); 51510a37fd7SStephen Warren if (part_str) { 51610a37fd7SStephen Warren dup_str = strdup(dev_part_str); 51710a37fd7SStephen Warren dup_str[part_str - dev_part_str] = 0; 51810a37fd7SStephen Warren dev_str = dup_str; 51910a37fd7SStephen Warren part_str++; 52010a37fd7SStephen Warren } else { 52110a37fd7SStephen Warren dev_str = dev_part_str; 52299d2c205SRob Herring } 52310a37fd7SStephen Warren 52410a37fd7SStephen Warren /* Look up the device */ 525ebac37cfSSimon Glass dev = blk_get_device_by_str(ifname, dev_str, dev_desc); 52610a37fd7SStephen Warren if (dev < 0) 52710a37fd7SStephen Warren goto cleanup; 52810a37fd7SStephen Warren 52910a37fd7SStephen Warren /* Convert partition ID string to number */ 53010a37fd7SStephen Warren if (!part_str || !*part_str) { 53110a37fd7SStephen Warren part = PART_UNSPECIFIED; 53210a37fd7SStephen Warren } else if (!strcmp(part_str, "auto")) { 53310a37fd7SStephen Warren part = PART_AUTO; 53410a37fd7SStephen Warren } else { 53510a37fd7SStephen Warren /* Something specified -> use exactly that */ 53610a37fd7SStephen Warren part = (int)simple_strtoul(part_str, &ep, 16); 53710a37fd7SStephen Warren /* 53810a37fd7SStephen Warren * Less than whole string converted, 53910a37fd7SStephen Warren * or request for whole device, but caller requires partition. 54010a37fd7SStephen Warren */ 54110a37fd7SStephen Warren if (*ep || (part == 0 && !allow_whole_dev)) { 54210a37fd7SStephen Warren printf("** Bad partition specification %s %s **\n", 54310a37fd7SStephen Warren ifname, dev_part_str); 54410a37fd7SStephen Warren goto cleanup; 54510a37fd7SStephen Warren } 54610a37fd7SStephen Warren } 54710a37fd7SStephen Warren 54810a37fd7SStephen Warren /* 54910a37fd7SStephen Warren * No partition table on device, 55010a37fd7SStephen Warren * or user requested partition 0 (entire device). 55110a37fd7SStephen Warren */ 55210a37fd7SStephen Warren if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 55310a37fd7SStephen Warren (part == 0)) { 55410a37fd7SStephen Warren if (!(*dev_desc)->lba) { 55510a37fd7SStephen Warren printf("** Bad device size - %s %s **\n", ifname, 55610a37fd7SStephen Warren dev_str); 55710a37fd7SStephen Warren goto cleanup; 55810a37fd7SStephen Warren } 55910a37fd7SStephen Warren 56010a37fd7SStephen Warren /* 56110a37fd7SStephen Warren * If user specified a partition ID other than 0, 56210a37fd7SStephen Warren * or the calling command only accepts partitions, 56310a37fd7SStephen Warren * it's an error. 56410a37fd7SStephen Warren */ 56510a37fd7SStephen Warren if ((part > 0) || (!allow_whole_dev)) { 56610a37fd7SStephen Warren printf("** No partition table - %s %s **\n", ifname, 56710a37fd7SStephen Warren dev_str); 56810a37fd7SStephen Warren goto cleanup; 56910a37fd7SStephen Warren } 57010a37fd7SStephen Warren 57150ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 57250ffc3b6SLan Yixun (dlan) 57399d2c205SRob Herring info->start = 0; 57410a37fd7SStephen Warren info->size = (*dev_desc)->lba; 57510a37fd7SStephen Warren info->blksz = (*dev_desc)->blksz; 57610a37fd7SStephen Warren info->bootable = 0; 5776ab6a650SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 5786ab6a650SStephen Warren strcpy((char *)info->name, "Whole Disk"); 57910a37fd7SStephen Warren #ifdef CONFIG_PARTITION_UUIDS 58010a37fd7SStephen Warren info->uuid[0] = 0; 58110a37fd7SStephen Warren #endif 5827561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 5837561b258SPatrick Delaunay info->type_guid[0] = 0; 5847561b258SPatrick Delaunay #endif 58599d2c205SRob Herring 58610a37fd7SStephen Warren ret = 0; 58710a37fd7SStephen Warren goto cleanup; 58899d2c205SRob Herring } 58999d2c205SRob Herring 59010a37fd7SStephen Warren /* 59110a37fd7SStephen Warren * Now there's known to be a partition table, 59210a37fd7SStephen Warren * not specifying a partition means to pick partition 1. 59310a37fd7SStephen Warren */ 59410a37fd7SStephen Warren if (part == PART_UNSPECIFIED) 59510a37fd7SStephen Warren part = 1; 59699d2c205SRob Herring 59710a37fd7SStephen Warren /* 59810a37fd7SStephen Warren * If user didn't specify a partition number, or did specify something 59910a37fd7SStephen Warren * other than "auto", use that partition number directly. 60010a37fd7SStephen Warren */ 60110a37fd7SStephen Warren if (part != PART_AUTO) { 6023e8bd469SSimon Glass ret = part_get_info(*dev_desc, part, info); 60399d2c205SRob Herring if (ret) { 60410a37fd7SStephen Warren printf("** Invalid partition %d **\n", part); 60510a37fd7SStephen Warren goto cleanup; 60610a37fd7SStephen Warren } 60710a37fd7SStephen Warren } else { 60810a37fd7SStephen Warren /* 60910a37fd7SStephen Warren * Find the first bootable partition. 61010a37fd7SStephen Warren * If none are bootable, fall back to the first valid partition. 61110a37fd7SStephen Warren */ 61210a37fd7SStephen Warren part = 0; 61310a37fd7SStephen Warren for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 6143e8bd469SSimon Glass ret = part_get_info(*dev_desc, p, info); 61510a37fd7SStephen Warren if (ret) 61610a37fd7SStephen Warren continue; 61710a37fd7SStephen Warren 61810a37fd7SStephen Warren /* 61910a37fd7SStephen Warren * First valid partition, or new better partition? 62010a37fd7SStephen Warren * If so, save partition ID. 62110a37fd7SStephen Warren */ 62210a37fd7SStephen Warren if (!part || info->bootable) 62310a37fd7SStephen Warren part = p; 62410a37fd7SStephen Warren 62510a37fd7SStephen Warren /* Best possible partition? Stop searching. */ 62610a37fd7SStephen Warren if (info->bootable) 62710a37fd7SStephen Warren break; 62810a37fd7SStephen Warren 62910a37fd7SStephen Warren /* 63010a37fd7SStephen Warren * We now need to search further for best possible. 63110a37fd7SStephen Warren * If we what we just queried was the best so far, 63210a37fd7SStephen Warren * save the info since we over-write it next loop. 63310a37fd7SStephen Warren */ 63410a37fd7SStephen Warren if (part == p) 63510a37fd7SStephen Warren tmpinfo = *info; 63610a37fd7SStephen Warren } 63710a37fd7SStephen Warren /* If we found any acceptable partition */ 63810a37fd7SStephen Warren if (part) { 63910a37fd7SStephen Warren /* 64010a37fd7SStephen Warren * If we searched all possible partition IDs, 64110a37fd7SStephen Warren * return the first valid partition we found. 64210a37fd7SStephen Warren */ 64310a37fd7SStephen Warren if (p == MAX_SEARCH_PARTITIONS + 1) 64410a37fd7SStephen Warren *info = tmpinfo; 64510a37fd7SStephen Warren } else { 64610a37fd7SStephen Warren printf("** No valid partitions found **\n"); 64771bba424SStephen Warren ret = -1; 64810a37fd7SStephen Warren goto cleanup; 64910a37fd7SStephen Warren } 65099d2c205SRob Herring } 65199d2c205SRob Herring if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 65299d2c205SRob Herring printf("** Invalid partition type \"%.32s\"" 65399d2c205SRob Herring " (expect \"" BOOT_PART_TYPE "\")\n", 65499d2c205SRob Herring info->type); 65510a37fd7SStephen Warren ret = -1; 65610a37fd7SStephen Warren goto cleanup; 65799d2c205SRob Herring } 65899d2c205SRob Herring 65950ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 66050ffc3b6SLan Yixun (dlan) 66110a37fd7SStephen Warren ret = part; 66210a37fd7SStephen Warren goto cleanup; 66399d2c205SRob Herring 66410a37fd7SStephen Warren cleanup: 66510a37fd7SStephen Warren free(dup_str); 66610a37fd7SStephen Warren return ret; 66799d2c205SRob Herring } 668