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 24*d96a9804SAlexander 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 27199d2c205SRob Herring dev_desc->part_type = PART_TYPE_UNKNOWN; 27296e5b03cSSimon Glass for (entry = drv; entry != drv + n_ents; entry++) { 27396e5b03cSSimon Glass int ret; 27496e5b03cSSimon Glass 27596e5b03cSSimon Glass ret = entry->test(dev_desc); 27696e5b03cSSimon Glass debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret); 27796e5b03cSSimon Glass if (!ret) { 27896e5b03cSSimon Glass dev_desc->part_type = entry->part_type; 27996e5b03cSSimon Glass break; 28096e5b03cSSimon Glass } 28196e5b03cSSimon Glass } 282affae2bfSwdenk } 283affae2bfSwdenk 28496e5b03cSSimon Glass static void print_part_header(const char *type, struct blk_desc *dev_desc) 28596e5b03cSSimon Glass { 2860c9c8fb5SGabe Black #if defined(CONFIG_MAC_PARTITION) || \ 2870c9c8fb5SGabe Black defined(CONFIG_DOS_PARTITION) || \ 2880c9c8fb5SGabe Black defined(CONFIG_ISO_PARTITION) || \ 2890c9c8fb5SGabe Black defined(CONFIG_AMIGA_PARTITION) || \ 2900c9c8fb5SGabe Black defined(CONFIG_EFI_PARTITION) 291affae2bfSwdenk puts ("\nPartition Map for "); 292affae2bfSwdenk switch (dev_desc->if_type) { 293726c0f1eSDetlev Zundel case IF_TYPE_IDE: 294726c0f1eSDetlev Zundel puts ("IDE"); 295affae2bfSwdenk break; 296726c0f1eSDetlev Zundel case IF_TYPE_SATA: 297726c0f1eSDetlev Zundel puts ("SATA"); 298c7057b52SDave Liu break; 299726c0f1eSDetlev Zundel case IF_TYPE_SCSI: 300726c0f1eSDetlev Zundel puts ("SCSI"); 301affae2bfSwdenk break; 302726c0f1eSDetlev Zundel case IF_TYPE_ATAPI: 303726c0f1eSDetlev Zundel puts ("ATAPI"); 304affae2bfSwdenk break; 305726c0f1eSDetlev Zundel case IF_TYPE_USB: 306726c0f1eSDetlev Zundel puts ("USB"); 307affae2bfSwdenk break; 308726c0f1eSDetlev Zundel case IF_TYPE_DOC: 309726c0f1eSDetlev Zundel puts ("DOC"); 310affae2bfSwdenk break; 3118f3b9642SLei Wen case IF_TYPE_MMC: 3128f3b9642SLei Wen puts ("MMC"); 3138f3b9642SLei Wen break; 314f4d8de48SHenrik Nordström case IF_TYPE_HOST: 315f4d8de48SHenrik Nordström puts("HOST"); 316f4d8de48SHenrik Nordström break; 317726c0f1eSDetlev Zundel default: 318726c0f1eSDetlev Zundel puts ("UNKNOWN"); 319affae2bfSwdenk break; 320affae2bfSwdenk } 321affae2bfSwdenk printf (" device %d -- Partition Type: %s\n\n", 322bcce53d0SSimon Glass dev_desc->devnum, type); 3230c9c8fb5SGabe Black #endif /* any CONFIG_..._PARTITION */ 32496e5b03cSSimon Glass } 3250c9c8fb5SGabe Black 3263e8bd469SSimon Glass void part_print(struct blk_desc *dev_desc) 327affae2bfSwdenk { 32896e5b03cSSimon Glass struct part_driver *drv; 329affae2bfSwdenk 33096e5b03cSSimon Glass drv = part_driver_lookup_type(dev_desc->part_type); 33196e5b03cSSimon Glass if (!drv) { 33296e5b03cSSimon Glass printf("## Unknown partition table type %x\n", 33396e5b03cSSimon Glass dev_desc->part_type); 334affae2bfSwdenk return; 335affae2bfSwdenk } 33696e5b03cSSimon Glass 33796e5b03cSSimon Glass PRINTF("## Testing for valid %s partition ##\n", drv->name); 33896e5b03cSSimon Glass print_part_header(drv->name, dev_desc); 33996e5b03cSSimon Glass if (drv->print) 34096e5b03cSSimon Glass drv->print(dev_desc); 341affae2bfSwdenk } 342affae2bfSwdenk 3430c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 3442f501646SStephen Warren 3453e8bd469SSimon Glass int part_get_info(struct blk_desc *dev_desc, int part, 3463f9eb6e1SPavel Machek disk_partition_t *info) 3472f501646SStephen Warren { 3480c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 34996e5b03cSSimon Glass struct part_driver *drv; 3502f501646SStephen Warren 351894bfbbfSStephen Warren #ifdef CONFIG_PARTITION_UUIDS 352894bfbbfSStephen Warren /* The common case is no UUID support */ 353894bfbbfSStephen Warren info->uuid[0] = 0; 354894bfbbfSStephen Warren #endif 3557561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 3567561b258SPatrick Delaunay info->type_guid[0] = 0; 3577561b258SPatrick Delaunay #endif 358894bfbbfSStephen Warren 35996e5b03cSSimon Glass drv = part_driver_lookup_type(dev_desc->part_type); 36096e5b03cSSimon Glass if (!drv) { 36196e5b03cSSimon Glass debug("## Unknown partition table type %x\n", 36296e5b03cSSimon Glass dev_desc->part_type); 36396e5b03cSSimon Glass return -EPROTONOSUPPORT; 3642f501646SStephen Warren } 36596e5b03cSSimon Glass if (!drv->get_info) { 36696e5b03cSSimon Glass PRINTF("## Driver %s does not have the get_info() method\n"); 36796e5b03cSSimon Glass return -ENOSYS; 3682f501646SStephen Warren } 36996e5b03cSSimon Glass if (drv->get_info(dev_desc, part, info) == 0) { 37096e5b03cSSimon Glass PRINTF("## Valid %s partition found ##\n", drv->name); 3712f501646SStephen Warren return 0; 3722f501646SStephen Warren } 3730c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 3742f501646SStephen Warren 3752f501646SStephen Warren return -1; 3762f501646SStephen Warren } 37799d2c205SRob Herring 378ebac37cfSSimon Glass int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, 3794101f687SSimon Glass struct blk_desc **dev_desc) 3802023e608SStephen Warren { 3812023e608SStephen Warren char *ep; 382336b6f90SStephen Warren char *dup_str = NULL; 383336b6f90SStephen Warren const char *dev_str, *hwpart_str; 384336b6f90SStephen Warren int dev, hwpart; 385336b6f90SStephen Warren 386336b6f90SStephen Warren hwpart_str = strchr(dev_hwpart_str, '.'); 387336b6f90SStephen Warren if (hwpart_str) { 388336b6f90SStephen Warren dup_str = strdup(dev_hwpart_str); 389336b6f90SStephen Warren dup_str[hwpart_str - dev_hwpart_str] = 0; 390336b6f90SStephen Warren dev_str = dup_str; 391336b6f90SStephen Warren hwpart_str++; 392336b6f90SStephen Warren } else { 393336b6f90SStephen Warren dev_str = dev_hwpart_str; 394ecdd57e2SStephen Warren hwpart = 0; 395336b6f90SStephen Warren } 3962023e608SStephen Warren 3972023e608SStephen Warren dev = simple_strtoul(dev_str, &ep, 16); 3982023e608SStephen Warren if (*ep) { 3992023e608SStephen Warren printf("** Bad device specification %s %s **\n", 4002023e608SStephen Warren ifname, dev_str); 401336b6f90SStephen Warren dev = -1; 402336b6f90SStephen Warren goto cleanup; 4032023e608SStephen Warren } 4042023e608SStephen Warren 405336b6f90SStephen Warren if (hwpart_str) { 406336b6f90SStephen Warren hwpart = simple_strtoul(hwpart_str, &ep, 16); 407336b6f90SStephen Warren if (*ep) { 408336b6f90SStephen Warren printf("** Bad HW partition specification %s %s **\n", 409336b6f90SStephen Warren ifname, hwpart_str); 410336b6f90SStephen Warren dev = -1; 411336b6f90SStephen Warren goto cleanup; 412336b6f90SStephen Warren } 413336b6f90SStephen Warren } 414336b6f90SStephen Warren 415336b6f90SStephen Warren *dev_desc = get_dev_hwpart(ifname, dev, hwpart); 4162023e608SStephen Warren if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { 417336b6f90SStephen Warren printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); 418336b6f90SStephen Warren dev = -1; 419336b6f90SStephen Warren goto cleanup; 4202023e608SStephen Warren } 4212023e608SStephen Warren 42299e7fc8aSErik Tideman #ifdef HAVE_BLOCK_DEVICE 42399e7fc8aSErik Tideman /* 42499e7fc8aSErik Tideman * Updates the partition table for the specified hw partition. 42599e7fc8aSErik Tideman * Does not need to be done for hwpart 0 since it is default and 42699e7fc8aSErik Tideman * already loaded. 42799e7fc8aSErik Tideman */ 42899e7fc8aSErik Tideman if(hwpart != 0) 4293e8bd469SSimon Glass part_init(*dev_desc); 43099e7fc8aSErik Tideman #endif 43199e7fc8aSErik Tideman 432336b6f90SStephen Warren cleanup: 433336b6f90SStephen Warren free(dup_str); 4342023e608SStephen Warren return dev; 4352023e608SStephen Warren } 4362023e608SStephen Warren 43710a37fd7SStephen Warren #define PART_UNSPECIFIED -2 43810a37fd7SStephen Warren #define PART_AUTO -1 43910a37fd7SStephen Warren #define MAX_SEARCH_PARTITIONS 16 440e35929e4SSimon Glass int blk_get_device_part_str(const char *ifname, const char *dev_part_str, 4414101f687SSimon Glass struct blk_desc **dev_desc, 44210a37fd7SStephen Warren disk_partition_t *info, int allow_whole_dev) 44399d2c205SRob Herring { 44410a37fd7SStephen Warren int ret = -1; 44510a37fd7SStephen Warren const char *part_str; 44610a37fd7SStephen Warren char *dup_str = NULL; 44710a37fd7SStephen Warren const char *dev_str; 44899d2c205SRob Herring int dev; 44910a37fd7SStephen Warren char *ep; 45010a37fd7SStephen Warren int p; 45110a37fd7SStephen Warren int part; 45210a37fd7SStephen Warren disk_partition_t tmpinfo; 45399d2c205SRob Herring 454afc1744eSHans de Goede #ifdef CONFIG_SANDBOX 4554d907025SStephen Warren /* 4563f9eb6e1SPavel Machek * Special-case a pseudo block device "hostfs", to allow access to the 4574d907025SStephen Warren * host's own filesystem. 4584d907025SStephen Warren */ 4594d907025SStephen Warren if (0 == strcmp(ifname, "hostfs")) { 4604d907025SStephen Warren *dev_desc = NULL; 4614d907025SStephen Warren info->start = 0; 4624d907025SStephen Warren info->size = 0; 4634d907025SStephen Warren info->blksz = 0; 4644d907025SStephen Warren info->bootable = 0; 4654d907025SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 4664d907025SStephen Warren strcpy((char *)info->name, "Sandbox host"); 4674d907025SStephen Warren #ifdef CONFIG_PARTITION_UUIDS 4684d907025SStephen Warren info->uuid[0] = 0; 4694d907025SStephen Warren #endif 4707561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 4717561b258SPatrick Delaunay info->type_guid[0] = 0; 4727561b258SPatrick Delaunay #endif 4734d907025SStephen Warren 4744d907025SStephen Warren return 0; 4754d907025SStephen Warren } 476afc1744eSHans de Goede #endif 4774d907025SStephen Warren 478251cee0dSHans de Goede #ifdef CONFIG_CMD_UBIFS 479251cee0dSHans de Goede /* 480251cee0dSHans de Goede * Special-case ubi, ubi goes through a mtd, rathen then through 481251cee0dSHans de Goede * a regular block device. 482251cee0dSHans de Goede */ 483251cee0dSHans de Goede if (0 == strcmp(ifname, "ubi")) { 484251cee0dSHans de Goede if (!ubifs_is_mounted()) { 485251cee0dSHans de Goede printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); 486251cee0dSHans de Goede return -1; 487251cee0dSHans de Goede } 488251cee0dSHans de Goede 489251cee0dSHans de Goede *dev_desc = NULL; 490251cee0dSHans de Goede memset(info, 0, sizeof(*info)); 491251cee0dSHans de Goede strcpy((char *)info->type, BOOT_PART_TYPE); 492251cee0dSHans de Goede strcpy((char *)info->name, "UBI"); 493251cee0dSHans de Goede #ifdef CONFIG_PARTITION_UUIDS 494251cee0dSHans de Goede info->uuid[0] = 0; 495251cee0dSHans de Goede #endif 496251cee0dSHans de Goede return 0; 497251cee0dSHans de Goede } 498251cee0dSHans de Goede #endif 499251cee0dSHans de Goede 50010a37fd7SStephen Warren /* If no dev_part_str, use bootdevice environment variable */ 501a10973e7SStephen Warren if (!dev_part_str || !strlen(dev_part_str) || 502a10973e7SStephen Warren !strcmp(dev_part_str, "-")) 50310a37fd7SStephen Warren dev_part_str = getenv("bootdevice"); 50499d2c205SRob Herring 50510a37fd7SStephen Warren /* If still no dev_part_str, it's an error */ 50610a37fd7SStephen Warren if (!dev_part_str) { 50710a37fd7SStephen Warren printf("** No device specified **\n"); 50810a37fd7SStephen Warren goto cleanup; 50999d2c205SRob Herring } 51099d2c205SRob Herring 51110a37fd7SStephen Warren /* Separate device and partition ID specification */ 51210a37fd7SStephen Warren part_str = strchr(dev_part_str, ':'); 51310a37fd7SStephen Warren if (part_str) { 51410a37fd7SStephen Warren dup_str = strdup(dev_part_str); 51510a37fd7SStephen Warren dup_str[part_str - dev_part_str] = 0; 51610a37fd7SStephen Warren dev_str = dup_str; 51710a37fd7SStephen Warren part_str++; 51810a37fd7SStephen Warren } else { 51910a37fd7SStephen Warren dev_str = dev_part_str; 52099d2c205SRob Herring } 52110a37fd7SStephen Warren 52210a37fd7SStephen Warren /* Look up the device */ 523ebac37cfSSimon Glass dev = blk_get_device_by_str(ifname, dev_str, dev_desc); 52410a37fd7SStephen Warren if (dev < 0) 52510a37fd7SStephen Warren goto cleanup; 52610a37fd7SStephen Warren 52710a37fd7SStephen Warren /* Convert partition ID string to number */ 52810a37fd7SStephen Warren if (!part_str || !*part_str) { 52910a37fd7SStephen Warren part = PART_UNSPECIFIED; 53010a37fd7SStephen Warren } else if (!strcmp(part_str, "auto")) { 53110a37fd7SStephen Warren part = PART_AUTO; 53210a37fd7SStephen Warren } else { 53310a37fd7SStephen Warren /* Something specified -> use exactly that */ 53410a37fd7SStephen Warren part = (int)simple_strtoul(part_str, &ep, 16); 53510a37fd7SStephen Warren /* 53610a37fd7SStephen Warren * Less than whole string converted, 53710a37fd7SStephen Warren * or request for whole device, but caller requires partition. 53810a37fd7SStephen Warren */ 53910a37fd7SStephen Warren if (*ep || (part == 0 && !allow_whole_dev)) { 54010a37fd7SStephen Warren printf("** Bad partition specification %s %s **\n", 54110a37fd7SStephen Warren ifname, dev_part_str); 54210a37fd7SStephen Warren goto cleanup; 54310a37fd7SStephen Warren } 54410a37fd7SStephen Warren } 54510a37fd7SStephen Warren 54610a37fd7SStephen Warren /* 54710a37fd7SStephen Warren * No partition table on device, 54810a37fd7SStephen Warren * or user requested partition 0 (entire device). 54910a37fd7SStephen Warren */ 55010a37fd7SStephen Warren if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 55110a37fd7SStephen Warren (part == 0)) { 55210a37fd7SStephen Warren if (!(*dev_desc)->lba) { 55310a37fd7SStephen Warren printf("** Bad device size - %s %s **\n", ifname, 55410a37fd7SStephen Warren dev_str); 55510a37fd7SStephen Warren goto cleanup; 55610a37fd7SStephen Warren } 55710a37fd7SStephen Warren 55810a37fd7SStephen Warren /* 55910a37fd7SStephen Warren * If user specified a partition ID other than 0, 56010a37fd7SStephen Warren * or the calling command only accepts partitions, 56110a37fd7SStephen Warren * it's an error. 56210a37fd7SStephen Warren */ 56310a37fd7SStephen Warren if ((part > 0) || (!allow_whole_dev)) { 56410a37fd7SStephen Warren printf("** No partition table - %s %s **\n", ifname, 56510a37fd7SStephen Warren dev_str); 56610a37fd7SStephen Warren goto cleanup; 56710a37fd7SStephen Warren } 56810a37fd7SStephen Warren 56950ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 57050ffc3b6SLan Yixun (dlan) 57199d2c205SRob Herring info->start = 0; 57210a37fd7SStephen Warren info->size = (*dev_desc)->lba; 57310a37fd7SStephen Warren info->blksz = (*dev_desc)->blksz; 57410a37fd7SStephen Warren info->bootable = 0; 5756ab6a650SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 5766ab6a650SStephen Warren strcpy((char *)info->name, "Whole Disk"); 57710a37fd7SStephen Warren #ifdef CONFIG_PARTITION_UUIDS 57810a37fd7SStephen Warren info->uuid[0] = 0; 57910a37fd7SStephen Warren #endif 5807561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 5817561b258SPatrick Delaunay info->type_guid[0] = 0; 5827561b258SPatrick Delaunay #endif 58399d2c205SRob Herring 58410a37fd7SStephen Warren ret = 0; 58510a37fd7SStephen Warren goto cleanup; 58699d2c205SRob Herring } 58799d2c205SRob Herring 58810a37fd7SStephen Warren /* 58910a37fd7SStephen Warren * Now there's known to be a partition table, 59010a37fd7SStephen Warren * not specifying a partition means to pick partition 1. 59110a37fd7SStephen Warren */ 59210a37fd7SStephen Warren if (part == PART_UNSPECIFIED) 59310a37fd7SStephen Warren part = 1; 59499d2c205SRob Herring 59510a37fd7SStephen Warren /* 59610a37fd7SStephen Warren * If user didn't specify a partition number, or did specify something 59710a37fd7SStephen Warren * other than "auto", use that partition number directly. 59810a37fd7SStephen Warren */ 59910a37fd7SStephen Warren if (part != PART_AUTO) { 6003e8bd469SSimon Glass ret = part_get_info(*dev_desc, part, info); 60199d2c205SRob Herring if (ret) { 60210a37fd7SStephen Warren printf("** Invalid partition %d **\n", part); 60310a37fd7SStephen Warren goto cleanup; 60410a37fd7SStephen Warren } 60510a37fd7SStephen Warren } else { 60610a37fd7SStephen Warren /* 60710a37fd7SStephen Warren * Find the first bootable partition. 60810a37fd7SStephen Warren * If none are bootable, fall back to the first valid partition. 60910a37fd7SStephen Warren */ 61010a37fd7SStephen Warren part = 0; 61110a37fd7SStephen Warren for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 6123e8bd469SSimon Glass ret = part_get_info(*dev_desc, p, info); 61310a37fd7SStephen Warren if (ret) 61410a37fd7SStephen Warren continue; 61510a37fd7SStephen Warren 61610a37fd7SStephen Warren /* 61710a37fd7SStephen Warren * First valid partition, or new better partition? 61810a37fd7SStephen Warren * If so, save partition ID. 61910a37fd7SStephen Warren */ 62010a37fd7SStephen Warren if (!part || info->bootable) 62110a37fd7SStephen Warren part = p; 62210a37fd7SStephen Warren 62310a37fd7SStephen Warren /* Best possible partition? Stop searching. */ 62410a37fd7SStephen Warren if (info->bootable) 62510a37fd7SStephen Warren break; 62610a37fd7SStephen Warren 62710a37fd7SStephen Warren /* 62810a37fd7SStephen Warren * We now need to search further for best possible. 62910a37fd7SStephen Warren * If we what we just queried was the best so far, 63010a37fd7SStephen Warren * save the info since we over-write it next loop. 63110a37fd7SStephen Warren */ 63210a37fd7SStephen Warren if (part == p) 63310a37fd7SStephen Warren tmpinfo = *info; 63410a37fd7SStephen Warren } 63510a37fd7SStephen Warren /* If we found any acceptable partition */ 63610a37fd7SStephen Warren if (part) { 63710a37fd7SStephen Warren /* 63810a37fd7SStephen Warren * If we searched all possible partition IDs, 63910a37fd7SStephen Warren * return the first valid partition we found. 64010a37fd7SStephen Warren */ 64110a37fd7SStephen Warren if (p == MAX_SEARCH_PARTITIONS + 1) 64210a37fd7SStephen Warren *info = tmpinfo; 64310a37fd7SStephen Warren } else { 64410a37fd7SStephen Warren printf("** No valid partitions found **\n"); 64571bba424SStephen Warren ret = -1; 64610a37fd7SStephen Warren goto cleanup; 64710a37fd7SStephen Warren } 64899d2c205SRob Herring } 64999d2c205SRob Herring if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 65099d2c205SRob Herring printf("** Invalid partition type \"%.32s\"" 65199d2c205SRob Herring " (expect \"" BOOT_PART_TYPE "\")\n", 65299d2c205SRob Herring info->type); 65310a37fd7SStephen Warren ret = -1; 65410a37fd7SStephen Warren goto cleanup; 65599d2c205SRob Herring } 65699d2c205SRob Herring 65750ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 65850ffc3b6SLan Yixun (dlan) 65910a37fd7SStephen Warren ret = part; 66010a37fd7SStephen Warren goto cleanup; 66199d2c205SRob Herring 66210a37fd7SStephen Warren cleanup: 66310a37fd7SStephen Warren free(dup_str); 66410a37fd7SStephen Warren return ret; 66599d2c205SRob Herring } 666