uboot/disk/part.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2001
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 */
   6
   7#include <common.h>
   8#include <blk.h>
   9#include <command.h>
  10#include <env.h>
  11#include <errno.h>
  12#include <ide.h>
  13#include <log.h>
  14#include <malloc.h>
  15#include <part.h>
  16#include <ubifs_uboot.h>
  17
  18#undef  PART_DEBUG
  19
  20#ifdef  PART_DEBUG
  21#define PRINTF(fmt,args...)     printf (fmt ,##args)
  22#else
  23#define PRINTF(fmt,args...)
  24#endif
  25
  26/* Check all partition types */
  27#define PART_TYPE_ALL           -1
  28
  29static struct part_driver *part_driver_lookup_type(struct blk_desc *dev_desc)
  30{
  31        struct part_driver *drv =
  32                ll_entry_start(struct part_driver, part_driver);
  33        const int n_ents = ll_entry_count(struct part_driver, part_driver);
  34        struct part_driver *entry;
  35
  36        if (dev_desc->part_type == PART_TYPE_UNKNOWN) {
  37                for (entry = drv; entry != drv + n_ents; entry++) {
  38                        int ret;
  39
  40                        ret = entry->test(dev_desc);
  41                        if (!ret) {
  42                                dev_desc->part_type = entry->part_type;
  43                                return entry;
  44                        }
  45                }
  46        } else {
  47                for (entry = drv; entry != drv + n_ents; entry++) {
  48                        if (dev_desc->part_type == entry->part_type)
  49                                return entry;
  50                }
  51        }
  52
  53        /* Not found */
  54        return NULL;
  55}
  56
  57static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
  58{
  59        struct blk_desc *dev_desc;
  60        int ret;
  61
  62        if (!blk_enabled())
  63                return NULL;
  64        dev_desc = blk_get_devnum_by_uclass_idname(ifname, dev);
  65        if (!dev_desc) {
  66                debug("%s: No device for iface '%s', dev %d\n", __func__,
  67                      ifname, dev);
  68                return NULL;
  69        }
  70        ret = blk_dselect_hwpart(dev_desc, hwpart);
  71        if (ret) {
  72                debug("%s: Failed to select h/w partition: err-%d\n", __func__,
  73                      ret);
  74                return NULL;
  75        }
  76
  77        return dev_desc;
  78}
  79
  80struct blk_desc *blk_get_dev(const char *ifname, int dev)
  81{
  82        if (!blk_enabled())
  83                return NULL;
  84
  85        return get_dev_hwpart(ifname, dev, 0);
  86}
  87
  88/* ------------------------------------------------------------------------- */
  89/*
  90 * reports device info to the user
  91 */
  92
  93#ifdef CONFIG_LBA48
  94typedef uint64_t lba512_t;
  95#else
  96typedef lbaint_t lba512_t;
  97#endif
  98
  99/*
 100 * Overflowless variant of (block_count * mul_by / 2**right_shift)
 101 * when 2**right_shift > mul_by
 102 */
 103static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by,
 104                              int right_shift)
 105{
 106        lba512_t bc_quot, bc_rem;
 107
 108        /* x * m / d == x / d * m + (x % d) * m / d */
 109        bc_quot = block_count >> right_shift;
 110        bc_rem  = block_count - (bc_quot << right_shift);
 111        return bc_quot * mul_by + ((bc_rem * mul_by) >> right_shift);
 112}
 113
 114void dev_print(struct blk_desc *dev_desc)
 115{
 116        lba512_t lba512; /* number of blocks if 512bytes block size */
 117
 118        if (dev_desc->type == DEV_TYPE_UNKNOWN) {
 119                puts ("not available\n");
 120                return;
 121        }
 122
 123        switch (dev_desc->uclass_id) {
 124        case UCLASS_SCSI:
 125                printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
 126                        dev_desc->target,dev_desc->lun,
 127                        dev_desc->vendor,
 128                        dev_desc->product,
 129                        dev_desc->revision);
 130                break;
 131        case UCLASS_IDE:
 132        case UCLASS_AHCI:
 133                printf ("Model: %s Firm: %s Ser#: %s\n",
 134                        dev_desc->vendor,
 135                        dev_desc->revision,
 136                        dev_desc->product);
 137                break;
 138        case UCLASS_MMC:
 139        case UCLASS_USB:
 140        case UCLASS_NVME:
 141        case UCLASS_PVBLOCK:
 142        case UCLASS_HOST:
 143                printf ("Vendor: %s Rev: %s Prod: %s\n",
 144                        dev_desc->vendor,
 145                        dev_desc->revision,
 146                        dev_desc->product);
 147                break;
 148        case UCLASS_VIRTIO:
 149                printf("%s VirtIO Block Device\n", dev_desc->vendor);
 150                break;
 151        case UCLASS_EFI_MEDIA:
 152                printf("EFI media Block Device %d\n", dev_desc->devnum);
 153                break;
 154        case UCLASS_INVALID:
 155                puts("device type unknown\n");
 156                return;
 157        default:
 158                printf("Unhandled device type: %i\n", dev_desc->uclass_id);
 159                return;
 160        }
 161        puts ("            Type: ");
 162        if (dev_desc->removable)
 163                puts ("Removable ");
 164        switch (dev_desc->type & 0x1F) {
 165        case DEV_TYPE_HARDDISK:
 166                puts ("Hard Disk");
 167                break;
 168        case DEV_TYPE_CDROM:
 169                puts ("CD ROM");
 170                break;
 171        case DEV_TYPE_OPDISK:
 172                puts ("Optical Device");
 173                break;
 174        case DEV_TYPE_TAPE:
 175                puts ("Tape");
 176                break;
 177        default:
 178                printf ("# %02X #", dev_desc->type & 0x1F);
 179                break;
 180        }
 181        puts ("\n");
 182        if (dev_desc->lba > 0L && dev_desc->blksz > 0L) {
 183                ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
 184                lbaint_t lba;
 185
 186                lba = dev_desc->lba;
 187
 188                lba512 = (lba * (dev_desc->blksz/512));
 189                /* round to 1 digit */
 190                /* 2048 = (1024 * 1024) / 512 MB */
 191                mb = lba512_muldiv(lba512, 10, 11);
 192
 193                mb_quot = mb / 10;
 194                mb_rem  = mb - (10 * mb_quot);
 195
 196                gb = mb / 1024;
 197                gb_quot = gb / 10;
 198                gb_rem  = gb - (10 * gb_quot);
 199#ifdef CONFIG_LBA48
 200                if (dev_desc->lba48)
 201                        printf ("            Supports 48-bit addressing\n");
 202#endif
 203#if defined(CONFIG_SYS_64BIT_LBA)
 204                printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n",
 205                        mb_quot, mb_rem,
 206                        gb_quot, gb_rem,
 207                        lba,
 208                        dev_desc->blksz);
 209#else
 210                printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n",
 211                        mb_quot, mb_rem,
 212                        gb_quot, gb_rem,
 213                        (ulong)lba,
 214                        dev_desc->blksz);
 215#endif
 216        } else {
 217                puts ("            Capacity: not available\n");
 218        }
 219}
 220
 221void part_init(struct blk_desc *dev_desc)
 222{
 223        struct part_driver *drv =
 224                ll_entry_start(struct part_driver, part_driver);
 225        const int n_ents = ll_entry_count(struct part_driver, part_driver);
 226        struct part_driver *entry;
 227
 228        blkcache_invalidate(dev_desc->uclass_id, dev_desc->devnum);
 229
 230        dev_desc->part_type = PART_TYPE_UNKNOWN;
 231        for (entry = drv; entry != drv + n_ents; entry++) {
 232                int ret;
 233
 234                ret = entry->test(dev_desc);
 235                debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret);
 236                if (!ret) {
 237                        dev_desc->part_type = entry->part_type;
 238                        break;
 239                }
 240        }
 241}
 242
 243static void print_part_header(const char *type, struct blk_desc *dev_desc)
 244{
 245#if CONFIG_IS_ENABLED(MAC_PARTITION) || \
 246        CONFIG_IS_ENABLED(DOS_PARTITION) || \
 247        CONFIG_IS_ENABLED(ISO_PARTITION) || \
 248        CONFIG_IS_ENABLED(AMIGA_PARTITION) || \
 249        CONFIG_IS_ENABLED(EFI_PARTITION)
 250        puts ("\nPartition Map for ");
 251        switch (dev_desc->uclass_id) {
 252        case UCLASS_IDE:
 253                puts ("IDE");
 254                break;
 255        case UCLASS_AHCI:
 256                puts ("SATA");
 257                break;
 258        case UCLASS_SCSI:
 259                puts ("SCSI");
 260                break;
 261        case UCLASS_USB:
 262                puts ("USB");
 263                break;
 264        case UCLASS_MMC:
 265                puts ("MMC");
 266                break;
 267        case UCLASS_HOST:
 268                puts ("HOST");
 269                break;
 270        case UCLASS_NVME:
 271                puts ("NVMe");
 272                break;
 273        case UCLASS_PVBLOCK:
 274                puts("PV BLOCK");
 275                break;
 276        case UCLASS_VIRTIO:
 277                puts("VirtIO");
 278                break;
 279        case UCLASS_EFI_MEDIA:
 280                puts("EFI");
 281                break;
 282        default:
 283                puts("UNKNOWN");
 284                break;
 285        }
 286        printf (" device %d  --   Partition Type: %s\n\n",
 287                        dev_desc->devnum, type);
 288#endif /* any CONFIG_..._PARTITION */
 289}
 290
 291void part_print(struct blk_desc *dev_desc)
 292{
 293        struct part_driver *drv;
 294
 295        drv = part_driver_lookup_type(dev_desc);
 296        if (!drv) {
 297                printf("## Unknown partition table type %x\n",
 298                       dev_desc->part_type);
 299                return;
 300        }
 301
 302        PRINTF("## Testing for valid %s partition ##\n", drv->name);
 303        print_part_header(drv->name, dev_desc);
 304        if (drv->print)
 305                drv->print(dev_desc);
 306}
 307
 308int part_get_info(struct blk_desc *dev_desc, int part,
 309                       struct disk_partition *info)
 310{
 311        struct part_driver *drv;
 312
 313        if (blk_enabled()) {
 314#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 315                /* The common case is no UUID support */
 316                info->uuid[0] = 0;
 317#endif
 318#ifdef CONFIG_PARTITION_TYPE_GUID
 319                info->type_guid[0] = 0;
 320#endif
 321
 322                drv = part_driver_lookup_type(dev_desc);
 323                if (!drv) {
 324                        debug("## Unknown partition table type %x\n",
 325                              dev_desc->part_type);
 326                        return -EPROTONOSUPPORT;
 327                }
 328                if (!drv->get_info) {
 329                        PRINTF("## Driver %s does not have the get_info() method\n",
 330                               drv->name);
 331                        return -ENOSYS;
 332                }
 333                if (drv->get_info(dev_desc, part, info) == 0) {
 334                        PRINTF("## Valid %s partition found ##\n", drv->name);
 335                        return 0;
 336                }
 337        }
 338
 339        return -ENOENT;
 340}
 341
 342int part_get_info_whole_disk(struct blk_desc *dev_desc,
 343                             struct disk_partition *info)
 344{
 345        info->start = 0;
 346        info->size = dev_desc->lba;
 347        info->blksz = dev_desc->blksz;
 348        info->bootable = 0;
 349        strcpy((char *)info->type, BOOT_PART_TYPE);
 350        strcpy((char *)info->name, "Whole Disk");
 351#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 352        info->uuid[0] = 0;
 353#endif
 354#ifdef CONFIG_PARTITION_TYPE_GUID
 355        info->type_guid[0] = 0;
 356#endif
 357
 358        return 0;
 359}
 360
 361int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
 362                          struct blk_desc **dev_desc)
 363{
 364        char *ep;
 365        char *dup_str = NULL;
 366        const char *dev_str, *hwpart_str;
 367        int dev, hwpart;
 368
 369        hwpart_str = strchr(dev_hwpart_str, '.');
 370        if (hwpart_str) {
 371                dup_str = strdup(dev_hwpart_str);
 372                dup_str[hwpart_str - dev_hwpart_str] = 0;
 373                dev_str = dup_str;
 374                hwpart_str++;
 375        } else {
 376                dev_str = dev_hwpart_str;
 377                hwpart = 0;
 378        }
 379
 380        dev = hextoul(dev_str, &ep);
 381        if (*ep) {
 382                printf("** Bad device specification %s %s **\n",
 383                       ifname, dev_str);
 384                dev = -EINVAL;
 385                goto cleanup;
 386        }
 387
 388        if (hwpart_str) {
 389                hwpart = hextoul(hwpart_str, &ep);
 390                if (*ep) {
 391                        printf("** Bad HW partition specification %s %s **\n",
 392                            ifname, hwpart_str);
 393                        dev = -EINVAL;
 394                        goto cleanup;
 395                }
 396        }
 397
 398        *dev_desc = get_dev_hwpart(ifname, dev, hwpart);
 399        if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
 400                debug("** Bad device %s %s **\n", ifname, dev_hwpart_str);
 401                dev = -ENODEV;
 402                goto cleanup;
 403        }
 404
 405        if (blk_enabled()) {
 406                /*
 407                 * Updates the partition table for the specified hw partition.
 408                 * Always should be done, otherwise hw partition 0 will return
 409                 * stale data after displaying a non-zero hw partition.
 410                 */
 411                if ((*dev_desc)->uclass_id == UCLASS_MMC)
 412                        part_init(*dev_desc);
 413        }
 414
 415cleanup:
 416        free(dup_str);
 417        return dev;
 418}
 419
 420#define PART_UNSPECIFIED -2
 421#define PART_AUTO -1
 422int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
 423                             struct blk_desc **dev_desc,
 424                             struct disk_partition *info, int allow_whole_dev)
 425{
 426        int ret;
 427        const char *part_str;
 428        char *dup_str = NULL;
 429        const char *dev_str;
 430        int dev;
 431        char *ep;
 432        int p;
 433        int part;
 434        struct disk_partition tmpinfo;
 435
 436        *dev_desc = NULL;
 437        memset(info, 0, sizeof(*info));
 438
 439#if IS_ENABLED(CONFIG_SANDBOX) || IS_ENABLED(CONFIG_SEMIHOSTING)
 440        /*
 441         * Special-case a pseudo block device "hostfs", to allow access to the
 442         * host's own filesystem.
 443         */
 444        if (!strcmp(ifname, "hostfs")) {
 445                strcpy((char *)info->type, BOOT_PART_TYPE);
 446                strcpy((char *)info->name, "Host filesystem");
 447
 448                return 0;
 449        }
 450#endif
 451
 452#if IS_ENABLED(CONFIG_CMD_UBIFS) && !IS_ENABLED(CONFIG_SPL_BUILD)
 453        /*
 454         * Special-case ubi, ubi goes through a mtd, rather than through
 455         * a regular block device.
 456         */
 457        if (!strcmp(ifname, "ubi")) {
 458                if (!ubifs_is_mounted()) {
 459                        printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
 460                        return -EINVAL;
 461                }
 462
 463                strcpy((char *)info->type, BOOT_PART_TYPE);
 464                strcpy((char *)info->name, "UBI");
 465                return 0;
 466        }
 467#endif
 468
 469        /* If no dev_part_str, use bootdevice environment variable */
 470        if (!dev_part_str || !strlen(dev_part_str) ||
 471            !strcmp(dev_part_str, "-"))
 472                dev_part_str = env_get("bootdevice");
 473
 474        /* If still no dev_part_str, it's an error */
 475        if (!dev_part_str) {
 476                printf("** No device specified **\n");
 477                ret = -ENODEV;
 478                goto cleanup;
 479        }
 480
 481        /* Separate device and partition ID specification */
 482        part_str = strchr(dev_part_str, ':');
 483        if (part_str) {
 484                dup_str = strdup(dev_part_str);
 485                dup_str[part_str - dev_part_str] = 0;
 486                dev_str = dup_str;
 487                part_str++;
 488        } else {
 489                dev_str = dev_part_str;
 490        }
 491
 492        /* Look up the device */
 493        dev = blk_get_device_by_str(ifname, dev_str, dev_desc);
 494        if (dev < 0) {
 495                printf("** Bad device specification %s %s **\n",
 496                       ifname, dev_str);
 497                ret = dev;
 498                goto cleanup;
 499        }
 500
 501        /* Convert partition ID string to number */
 502        if (!part_str || !*part_str) {
 503                part = PART_UNSPECIFIED;
 504        } else if (!strcmp(part_str, "auto")) {
 505                part = PART_AUTO;
 506        } else {
 507                /* Something specified -> use exactly that */
 508                part = (int)hextoul(part_str, &ep);
 509                /*
 510                 * Less than whole string converted,
 511                 * or request for whole device, but caller requires partition.
 512                 */
 513                if (*ep || (part == 0 && !allow_whole_dev)) {
 514                        printf("** Bad partition specification %s %s **\n",
 515                            ifname, dev_part_str);
 516                        ret = -ENOENT;
 517                        goto cleanup;
 518                }
 519        }
 520
 521        /*
 522         * No partition table on device,
 523         * or user requested partition 0 (entire device).
 524         */
 525        if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
 526            (part == 0)) {
 527                if (!(*dev_desc)->lba) {
 528                        printf("** Bad device size - %s %s **\n", ifname,
 529                               dev_str);
 530                        ret = -EINVAL;
 531                        goto cleanup;
 532                }
 533
 534                /*
 535                 * If user specified a partition ID other than 0,
 536                 * or the calling command only accepts partitions,
 537                 * it's an error.
 538                 */
 539                if ((part > 0) || (!allow_whole_dev)) {
 540                        printf("** No partition table - %s %s **\n", ifname,
 541                               dev_str);
 542                        ret = -EPROTONOSUPPORT;
 543                        goto cleanup;
 544                }
 545
 546                (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
 547
 548                part_get_info_whole_disk(*dev_desc, info);
 549
 550                ret = 0;
 551                goto cleanup;
 552        }
 553
 554        /*
 555         * Now there's known to be a partition table,
 556         * not specifying a partition means to pick partition 1.
 557         */
 558        if (part == PART_UNSPECIFIED)
 559                part = 1;
 560
 561        /*
 562         * If user didn't specify a partition number, or did specify something
 563         * other than "auto", use that partition number directly.
 564         */
 565        if (part != PART_AUTO) {
 566                ret = part_get_info(*dev_desc, part, info);
 567                if (ret) {
 568                        printf("** Invalid partition %d **\n", part);
 569                        goto cleanup;
 570                }
 571        } else {
 572                /*
 573                 * Find the first bootable partition.
 574                 * If none are bootable, fall back to the first valid partition.
 575                 */
 576                part = 0;
 577                for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 578                        ret = part_get_info(*dev_desc, p, info);
 579                        if (ret)
 580                                continue;
 581
 582                        /*
 583                         * First valid partition, or new better partition?
 584                         * If so, save partition ID.
 585                         */
 586                        if (!part || info->bootable)
 587                                part = p;
 588
 589                        /* Best possible partition? Stop searching. */
 590                        if (info->bootable)
 591                                break;
 592
 593                        /*
 594                         * We now need to search further for best possible.
 595                         * If we what we just queried was the best so far,
 596                         * save the info since we over-write it next loop.
 597                         */
 598                        if (part == p)
 599                                tmpinfo = *info;
 600                }
 601                /* If we found any acceptable partition */
 602                if (part) {
 603                        /*
 604                         * If we searched all possible partition IDs,
 605                         * return the first valid partition we found.
 606                         */
 607                        if (p == MAX_SEARCH_PARTITIONS + 1)
 608                                *info = tmpinfo;
 609                } else {
 610                        printf("** No valid partitions found **\n");
 611                        goto cleanup;
 612                }
 613        }
 614        if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
 615                printf("** Invalid partition type \"%.32s\""
 616                        " (expect \"" BOOT_PART_TYPE "\")\n",
 617                        info->type);
 618                ret  = -EINVAL;
 619                goto cleanup;
 620        }
 621
 622        (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
 623
 624        ret = part;
 625        goto cleanup;
 626
 627cleanup:
 628        free(dup_str);
 629        return ret;
 630}
 631
 632int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
 633                               struct disk_partition *info, int part_type)
 634{
 635        struct part_driver *part_drv;
 636        int ret;
 637        int i;
 638
 639        part_drv = part_driver_lookup_type(dev_desc);
 640        if (!part_drv)
 641                return -1;
 642
 643        if (!part_drv->get_info) {
 644                log_debug("## Driver %s does not have the get_info() method\n",
 645                          part_drv->name);
 646                return -ENOSYS;
 647        }
 648
 649        for (i = 1; i < part_drv->max_entries; i++) {
 650                ret = part_drv->get_info(dev_desc, i, info);
 651                if (ret != 0) {
 652                        /* no more entries in table */
 653                        break;
 654                }
 655                if (strcmp(name, (const char *)info->name) == 0) {
 656                        /* matched */
 657                        return i;
 658                }
 659        }
 660
 661        return -ENOENT;
 662}
 663
 664int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
 665                          struct disk_partition *info)
 666{
 667        return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
 668}
 669
 670/**
 671 * Get partition info from device number and partition name.
 672 *
 673 * Parse a device number and partition name string in the form of
 674 * "devicenum.hwpartnum#partition_name", for example "0.1#misc". devicenum and
 675 * hwpartnum are both optional, defaulting to 0. If the partition is found,
 676 * sets dev_desc and part_info accordingly with the information of the
 677 * partition with the given partition_name.
 678 *
 679 * @param[in] dev_iface Device interface
 680 * @param[in] dev_part_str Input string argument, like "0.1#misc"
 681 * @param[out] dev_desc Place to store the device description pointer
 682 * @param[out] part_info Place to store the partition information
 683 * Return: 0 on success, or a negative on error
 684 */
 685static int part_get_info_by_dev_and_name(const char *dev_iface,
 686                                         const char *dev_part_str,
 687                                         struct blk_desc **dev_desc,
 688                                         struct disk_partition *part_info)
 689{
 690        char *dup_str = NULL;
 691        const char *dev_str, *part_str;
 692        int ret;
 693
 694        /* Separate device and partition name specification */
 695        if (dev_part_str)
 696                part_str = strchr(dev_part_str, '#');
 697        else
 698                part_str = NULL;
 699
 700        if (part_str) {
 701                dup_str = strdup(dev_part_str);
 702                dup_str[part_str - dev_part_str] = 0;
 703                dev_str = dup_str;
 704                part_str++;
 705        } else {
 706                return -EINVAL;
 707        }
 708
 709        ret = blk_get_device_by_str(dev_iface, dev_str, dev_desc);
 710        if (ret < 0)
 711                goto cleanup;
 712
 713        ret = part_get_info_by_name(*dev_desc, part_str, part_info);
 714        if (ret < 0)
 715                printf("Could not find \"%s\" partition\n", part_str);
 716
 717cleanup:
 718        free(dup_str);
 719        return ret;
 720}
 721
 722int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
 723                                         const char *dev_part_str,
 724                                         struct blk_desc **dev_desc,
 725                                         struct disk_partition *part_info,
 726                                         int allow_whole_dev)
 727{
 728        int ret;
 729
 730        /* Split the part_name if passed as "$dev_num#part_name". */
 731        ret = part_get_info_by_dev_and_name(dev_iface, dev_part_str,
 732                                            dev_desc, part_info);
 733        if (ret >= 0)
 734                return ret;
 735        /*
 736         * Couldn't lookup by name, try looking up the partition description
 737         * directly.
 738         */
 739        ret = blk_get_device_part_str(dev_iface, dev_part_str,
 740                                      dev_desc, part_info, allow_whole_dev);
 741        if (ret < 0)
 742                printf("Couldn't find partition %s %s\n",
 743                       dev_iface, dev_part_str);
 744        return ret;
 745}
 746
 747void part_set_generic_name(const struct blk_desc *dev_desc,
 748        int part_num, char *name)
 749{
 750        char *devtype;
 751
 752        switch (dev_desc->uclass_id) {
 753        case UCLASS_IDE:
 754        case UCLASS_AHCI:
 755                devtype = "hd";
 756                break;
 757        case UCLASS_SCSI:
 758                devtype = "sd";
 759                break;
 760        case UCLASS_USB:
 761                devtype = "usbd";
 762                break;
 763        case UCLASS_MMC:
 764                devtype = "mmcsd";
 765                break;
 766        default:
 767                devtype = "xx";
 768                break;
 769        }
 770
 771        sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num);
 772}
 773