uboot/drivers/block/blk-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2016 Google, Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 */
   6
   7#define LOG_CATEGORY UCLASS_BLK
   8
   9#include <common.h>
  10#include <blk.h>
  11#include <dm.h>
  12#include <log.h>
  13#include <malloc.h>
  14#include <part.h>
  15#include <dm/device-internal.h>
  16#include <dm/lists.h>
  17#include <dm/uclass-internal.h>
  18#include <linux/err.h>
  19
  20static const char *if_typename_str[IF_TYPE_COUNT] = {
  21        [IF_TYPE_IDE]           = "ide",
  22        [IF_TYPE_SCSI]          = "scsi",
  23        [IF_TYPE_ATAPI]         = "atapi",
  24        [IF_TYPE_USB]           = "usb",
  25        [IF_TYPE_DOC]           = "doc",
  26        [IF_TYPE_MMC]           = "mmc",
  27        [IF_TYPE_SD]            = "sd",
  28        [IF_TYPE_SATA]          = "sata",
  29        [IF_TYPE_HOST]          = "host",
  30        [IF_TYPE_NVME]          = "nvme",
  31        [IF_TYPE_EFI_MEDIA]     = "efi",
  32        [IF_TYPE_EFI_LOADER]    = "efiloader",
  33        [IF_TYPE_VIRTIO]        = "virtio",
  34        [IF_TYPE_PVBLOCK]       = "pvblock",
  35};
  36
  37static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
  38        [IF_TYPE_IDE]           = UCLASS_IDE,
  39        [IF_TYPE_SCSI]          = UCLASS_SCSI,
  40        [IF_TYPE_ATAPI]         = UCLASS_INVALID,
  41        [IF_TYPE_USB]           = UCLASS_MASS_STORAGE,
  42        [IF_TYPE_DOC]           = UCLASS_INVALID,
  43        [IF_TYPE_MMC]           = UCLASS_MMC,
  44        [IF_TYPE_SD]            = UCLASS_INVALID,
  45        [IF_TYPE_SATA]          = UCLASS_AHCI,
  46        [IF_TYPE_HOST]          = UCLASS_ROOT,
  47        [IF_TYPE_NVME]          = UCLASS_NVME,
  48        [IF_TYPE_EFI_MEDIA]     = UCLASS_EFI_MEDIA,
  49        [IF_TYPE_EFI_LOADER]    = UCLASS_EFI_LOADER,
  50        [IF_TYPE_VIRTIO]        = UCLASS_VIRTIO,
  51        [IF_TYPE_PVBLOCK]       = UCLASS_PVBLOCK,
  52};
  53
  54static enum if_type if_typename_to_iftype(const char *if_typename)
  55{
  56        int i;
  57
  58        for (i = 0; i < IF_TYPE_COUNT; i++) {
  59                if (if_typename_str[i] &&
  60                    !strcmp(if_typename, if_typename_str[i]))
  61                        return i;
  62        }
  63
  64        return IF_TYPE_UNKNOWN;
  65}
  66
  67static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
  68{
  69        return if_type_uclass_id[if_type];
  70}
  71
  72const char *blk_get_if_type_name(enum if_type if_type)
  73{
  74        return if_typename_str[if_type];
  75}
  76
  77struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
  78{
  79        struct blk_desc *desc;
  80        struct udevice *dev;
  81        int ret;
  82
  83        ret = blk_get_device(if_type, devnum, &dev);
  84        if (ret)
  85                return NULL;
  86        desc = dev_get_uclass_plat(dev);
  87
  88        return desc;
  89}
  90
  91/*
  92 * This function is complicated with driver model. We look up the interface
  93 * name in a local table. This gives us an interface type which we can match
  94 * against the uclass of the block device's parent.
  95 */
  96struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
  97{
  98        enum uclass_id uclass_id;
  99        enum if_type if_type;
 100        struct udevice *dev;
 101        struct uclass *uc;
 102        int ret;
 103
 104        if_type = if_typename_to_iftype(if_typename);
 105        if (if_type == IF_TYPE_UNKNOWN) {
 106                debug("%s: Unknown interface type '%s'\n", __func__,
 107                      if_typename);
 108                return NULL;
 109        }
 110        uclass_id = if_type_to_uclass_id(if_type);
 111        if (uclass_id == UCLASS_INVALID) {
 112                debug("%s: Unknown uclass for interface type'\n",
 113                      if_typename_str[if_type]);
 114                return NULL;
 115        }
 116
 117        ret = uclass_get(UCLASS_BLK, &uc);
 118        if (ret)
 119                return NULL;
 120        uclass_foreach_dev(dev, uc) {
 121                struct blk_desc *desc = dev_get_uclass_plat(dev);
 122
 123                debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
 124                      if_type, devnum, dev->name, desc->if_type, desc->devnum);
 125                if (desc->devnum != devnum)
 126                        continue;
 127
 128                /* Find out the parent device uclass */
 129                if (device_get_uclass_id(dev->parent) != uclass_id) {
 130                        debug("%s: parent uclass %d, this dev %d\n", __func__,
 131                              device_get_uclass_id(dev->parent), uclass_id);
 132                        continue;
 133                }
 134
 135                if (device_probe(dev))
 136                        return NULL;
 137
 138                debug("%s: Device desc %p\n", __func__, desc);
 139                return desc;
 140        }
 141        debug("%s: No device found\n", __func__);
 142
 143        return NULL;
 144}
 145
 146/**
 147 * blk_get_by_device() - Get the block device descriptor for the given device
 148 * @dev:        Instance of a storage device
 149 *
 150 * Return: With block device descriptor on success , NULL if there is no such
 151 *         block device.
 152 */
 153struct blk_desc *blk_get_by_device(struct udevice *dev)
 154{
 155        struct udevice *child_dev;
 156
 157        device_foreach_child(child_dev, dev) {
 158                if (device_get_uclass_id(child_dev) != UCLASS_BLK)
 159                        continue;
 160
 161                return dev_get_uclass_plat(child_dev);
 162        }
 163
 164        debug("%s: No block device found\n", __func__);
 165
 166        return NULL;
 167}
 168
 169/**
 170 * get_desc() - Get the block device descriptor for the given device number
 171 *
 172 * @if_type:    Interface type
 173 * @devnum:     Device number (0 = first)
 174 * @descp:      Returns block device descriptor on success
 175 * @return 0 on success, -ENODEV if there is no such device and no device
 176 * with a higher device number, -ENOENT if there is no such device but there
 177 * is one with a higher number, or other -ve on other error.
 178 */
 179static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
 180{
 181        bool found_more = false;
 182        struct udevice *dev;
 183        struct uclass *uc;
 184        int ret;
 185
 186        *descp = NULL;
 187        ret = uclass_get(UCLASS_BLK, &uc);
 188        if (ret)
 189                return ret;
 190        uclass_foreach_dev(dev, uc) {
 191                struct blk_desc *desc = dev_get_uclass_plat(dev);
 192
 193                debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
 194                      if_type, devnum, dev->name, desc->if_type, desc->devnum);
 195                if (desc->if_type == if_type) {
 196                        if (desc->devnum == devnum) {
 197                                ret = device_probe(dev);
 198                                if (ret)
 199                                        return ret;
 200
 201                                *descp = desc;
 202                                return 0;
 203                        } else if (desc->devnum > devnum) {
 204                                found_more = true;
 205                        }
 206                }
 207        }
 208
 209        return found_more ? -ENOENT : -ENODEV;
 210}
 211
 212int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
 213{
 214        struct udevice *dev;
 215        int ret;
 216
 217        ret = blk_get_device(if_type, devnum, &dev);
 218        if (ret)
 219                return ret;
 220
 221        return blk_select_hwpart(dev, hwpart);
 222}
 223
 224int blk_list_part(enum if_type if_type)
 225{
 226        struct blk_desc *desc;
 227        int devnum, ok;
 228        int ret;
 229
 230        for (ok = 0, devnum = 0;; ++devnum) {
 231                ret = get_desc(if_type, devnum, &desc);
 232                if (ret == -ENODEV)
 233                        break;
 234                else if (ret)
 235                        continue;
 236                if (desc->part_type != PART_TYPE_UNKNOWN) {
 237                        ++ok;
 238                        if (devnum)
 239                                putc('\n');
 240                        part_print(desc);
 241                }
 242        }
 243        if (!ok)
 244                return -ENODEV;
 245
 246        return 0;
 247}
 248
 249int blk_print_part_devnum(enum if_type if_type, int devnum)
 250{
 251        struct blk_desc *desc;
 252        int ret;
 253
 254        ret = get_desc(if_type, devnum, &desc);
 255        if (ret)
 256                return ret;
 257        if (desc->type == DEV_TYPE_UNKNOWN)
 258                return -ENOENT;
 259        part_print(desc);
 260
 261        return 0;
 262}
 263
 264void blk_list_devices(enum if_type if_type)
 265{
 266        struct blk_desc *desc;
 267        int ret;
 268        int i;
 269
 270        for (i = 0;; ++i) {
 271                ret = get_desc(if_type, i, &desc);
 272                if (ret == -ENODEV)
 273                        break;
 274                else if (ret)
 275                        continue;
 276                if (desc->type == DEV_TYPE_UNKNOWN)
 277                        continue;  /* list only known devices */
 278                printf("Device %d: ", i);
 279                dev_print(desc);
 280        }
 281}
 282
 283int blk_print_device_num(enum if_type if_type, int devnum)
 284{
 285        struct blk_desc *desc;
 286        int ret;
 287
 288        ret = get_desc(if_type, devnum, &desc);
 289        if (ret)
 290                return ret;
 291        printf("\nIDE device %d: ", devnum);
 292        dev_print(desc);
 293
 294        return 0;
 295}
 296
 297int blk_show_device(enum if_type if_type, int devnum)
 298{
 299        struct blk_desc *desc;
 300        int ret;
 301
 302        printf("\nDevice %d: ", devnum);
 303        ret = get_desc(if_type, devnum, &desc);
 304        if (ret == -ENODEV || ret == -ENOENT) {
 305                printf("unknown device\n");
 306                return -ENODEV;
 307        }
 308        if (ret)
 309                return ret;
 310        dev_print(desc);
 311
 312        if (desc->type == DEV_TYPE_UNKNOWN)
 313                return -ENOENT;
 314
 315        return 0;
 316}
 317
 318ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
 319                      lbaint_t blkcnt, void *buffer)
 320{
 321        struct blk_desc *desc;
 322        ulong n;
 323        int ret;
 324
 325        ret = get_desc(if_type, devnum, &desc);
 326        if (ret)
 327                return ret;
 328        n = blk_dread(desc, start, blkcnt, buffer);
 329        if (IS_ERR_VALUE(n))
 330                return n;
 331
 332        return n;
 333}
 334
 335ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
 336                       lbaint_t blkcnt, const void *buffer)
 337{
 338        struct blk_desc *desc;
 339        int ret;
 340
 341        ret = get_desc(if_type, devnum, &desc);
 342        if (ret)
 343                return ret;
 344        return blk_dwrite(desc, start, blkcnt, buffer);
 345}
 346
 347int blk_select_hwpart(struct udevice *dev, int hwpart)
 348{
 349        const struct blk_ops *ops = blk_get_ops(dev);
 350
 351        if (!ops)
 352                return -ENOSYS;
 353        if (!ops->select_hwpart)
 354                return 0;
 355
 356        return ops->select_hwpart(dev, hwpart);
 357}
 358
 359int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
 360{
 361        return blk_select_hwpart(desc->bdev, hwpart);
 362}
 363
 364int blk_first_device(int if_type, struct udevice **devp)
 365{
 366        struct blk_desc *desc;
 367        int ret;
 368
 369        ret = uclass_find_first_device(UCLASS_BLK, devp);
 370        if (ret)
 371                return ret;
 372        if (!*devp)
 373                return -ENODEV;
 374        do {
 375                desc = dev_get_uclass_plat(*devp);
 376                if (desc->if_type == if_type)
 377                        return 0;
 378                ret = uclass_find_next_device(devp);
 379                if (ret)
 380                        return ret;
 381        } while (*devp);
 382
 383        return -ENODEV;
 384}
 385
 386int blk_next_device(struct udevice **devp)
 387{
 388        struct blk_desc *desc;
 389        int ret, if_type;
 390
 391        desc = dev_get_uclass_plat(*devp);
 392        if_type = desc->if_type;
 393        do {
 394                ret = uclass_find_next_device(devp);
 395                if (ret)
 396                        return ret;
 397                if (!*devp)
 398                        return -ENODEV;
 399                desc = dev_get_uclass_plat(*devp);
 400                if (desc->if_type == if_type)
 401                        return 0;
 402        } while (1);
 403}
 404
 405int blk_find_device(int if_type, int devnum, struct udevice **devp)
 406{
 407        struct uclass *uc;
 408        struct udevice *dev;
 409        int ret;
 410
 411        ret = uclass_get(UCLASS_BLK, &uc);
 412        if (ret)
 413                return ret;
 414        uclass_foreach_dev(dev, uc) {
 415                struct blk_desc *desc = dev_get_uclass_plat(dev);
 416
 417                debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
 418                      if_type, devnum, dev->name, desc->if_type, desc->devnum);
 419                if (desc->if_type == if_type && desc->devnum == devnum) {
 420                        *devp = dev;
 421                        return 0;
 422                }
 423        }
 424
 425        return -ENODEV;
 426}
 427
 428int blk_get_device(int if_type, int devnum, struct udevice **devp)
 429{
 430        int ret;
 431
 432        ret = blk_find_device(if_type, devnum, devp);
 433        if (ret)
 434                return ret;
 435
 436        return device_probe(*devp);
 437}
 438
 439unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
 440                        lbaint_t blkcnt, void *buffer)
 441{
 442        struct udevice *dev = block_dev->bdev;
 443        const struct blk_ops *ops = blk_get_ops(dev);
 444        ulong blks_read;
 445
 446        if (!ops->read)
 447                return -ENOSYS;
 448
 449        if (blkcache_read(block_dev->if_type, block_dev->devnum,
 450                          start, blkcnt, block_dev->blksz, buffer))
 451                return blkcnt;
 452        blks_read = ops->read(dev, start, blkcnt, buffer);
 453        if (blks_read == blkcnt)
 454                blkcache_fill(block_dev->if_type, block_dev->devnum,
 455                              start, blkcnt, block_dev->blksz, buffer);
 456
 457        return blks_read;
 458}
 459
 460unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
 461                         lbaint_t blkcnt, const void *buffer)
 462{
 463        struct udevice *dev = block_dev->bdev;
 464        const struct blk_ops *ops = blk_get_ops(dev);
 465
 466        if (!ops->write)
 467                return -ENOSYS;
 468
 469        blkcache_invalidate(block_dev->if_type, block_dev->devnum);
 470        return ops->write(dev, start, blkcnt, buffer);
 471}
 472
 473unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
 474                         lbaint_t blkcnt)
 475{
 476        struct udevice *dev = block_dev->bdev;
 477        const struct blk_ops *ops = blk_get_ops(dev);
 478
 479        if (!ops->erase)
 480                return -ENOSYS;
 481
 482        blkcache_invalidate(block_dev->if_type, block_dev->devnum);
 483        return ops->erase(dev, start, blkcnt);
 484}
 485
 486int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
 487{
 488        struct udevice *dev;
 489        enum uclass_id id;
 490        int ret;
 491
 492        device_find_first_child(parent, &dev);
 493        if (!dev) {
 494                debug("%s: No block device found for parent '%s'\n", __func__,
 495                      parent->name);
 496                return -ENODEV;
 497        }
 498        id = device_get_uclass_id(dev);
 499        if (id != UCLASS_BLK) {
 500                debug("%s: Incorrect uclass %s for block device '%s'\n",
 501                      __func__, uclass_get_name(id), dev->name);
 502                return -ENOTBLK;
 503        }
 504        ret = device_probe(dev);
 505        if (ret)
 506                return ret;
 507        *devp = dev;
 508
 509        return 0;
 510}
 511
 512int blk_find_max_devnum(enum if_type if_type)
 513{
 514        struct udevice *dev;
 515        int max_devnum = -ENODEV;
 516        struct uclass *uc;
 517        int ret;
 518
 519        ret = uclass_get(UCLASS_BLK, &uc);
 520        if (ret)
 521                return ret;
 522        uclass_foreach_dev(dev, uc) {
 523                struct blk_desc *desc = dev_get_uclass_plat(dev);
 524
 525                if (desc->if_type == if_type && desc->devnum > max_devnum)
 526                        max_devnum = desc->devnum;
 527        }
 528
 529        return max_devnum;
 530}
 531
 532int blk_next_free_devnum(enum if_type if_type)
 533{
 534        int ret;
 535
 536        ret = blk_find_max_devnum(if_type);
 537        if (ret == -ENODEV)
 538                return 0;
 539        if (ret < 0)
 540                return ret;
 541
 542        return ret + 1;
 543}
 544
 545static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
 546{
 547        const struct blk_desc *desc = dev_get_uclass_plat(dev);
 548        enum blk_flag_t flags;
 549
 550        flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
 551
 552        return flags & req_flags ? 0 : 1;
 553}
 554
 555int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
 556{
 557        int ret;
 558
 559        for (ret = uclass_first_device_err(UCLASS_BLK, devp);
 560             !ret;
 561             ret = uclass_next_device_err(devp)) {
 562                if (!blk_flags_check(*devp, flags))
 563                        return 0;
 564        }
 565
 566        return -ENODEV;
 567}
 568
 569int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
 570{
 571        int ret;
 572
 573        for (ret = uclass_next_device_err(devp);
 574             !ret;
 575             ret = uclass_next_device_err(devp)) {
 576                if (!blk_flags_check(*devp, flags))
 577                        return 0;
 578        }
 579
 580        return -ENODEV;
 581}
 582
 583int blk_count_devices(enum blk_flag_t flag)
 584{
 585        struct udevice *dev;
 586        int count = 0;
 587
 588        blk_foreach_probe(flag, dev)
 589                count++;
 590
 591        return count;
 592}
 593
 594static int blk_claim_devnum(enum if_type if_type, int devnum)
 595{
 596        struct udevice *dev;
 597        struct uclass *uc;
 598        int ret;
 599
 600        ret = uclass_get(UCLASS_BLK, &uc);
 601        if (ret)
 602                return ret;
 603        uclass_foreach_dev(dev, uc) {
 604                struct blk_desc *desc = dev_get_uclass_plat(dev);
 605
 606                if (desc->if_type == if_type && desc->devnum == devnum) {
 607                        int next = blk_next_free_devnum(if_type);
 608
 609                        if (next < 0)
 610                                return next;
 611                        desc->devnum = next;
 612                        return 0;
 613                }
 614        }
 615
 616        return -ENOENT;
 617}
 618
 619int blk_create_device(struct udevice *parent, const char *drv_name,
 620                      const char *name, int if_type, int devnum, int blksz,
 621                      lbaint_t lba, struct udevice **devp)
 622{
 623        struct blk_desc *desc;
 624        struct udevice *dev;
 625        int ret;
 626
 627        if (devnum == -1) {
 628                devnum = blk_next_free_devnum(if_type);
 629        } else {
 630                ret = blk_claim_devnum(if_type, devnum);
 631                if (ret < 0 && ret != -ENOENT)
 632                        return ret;
 633        }
 634        if (devnum < 0)
 635                return devnum;
 636        ret = device_bind_driver(parent, drv_name, name, &dev);
 637        if (ret)
 638                return ret;
 639        desc = dev_get_uclass_plat(dev);
 640        desc->if_type = if_type;
 641        desc->blksz = blksz;
 642        desc->log2blksz = LOG2(desc->blksz);
 643        desc->lba = lba;
 644        desc->part_type = PART_TYPE_UNKNOWN;
 645        desc->bdev = dev;
 646        desc->devnum = devnum;
 647        *devp = dev;
 648
 649        return 0;
 650}
 651
 652int blk_create_devicef(struct udevice *parent, const char *drv_name,
 653                       const char *name, int if_type, int devnum, int blksz,
 654                       lbaint_t lba, struct udevice **devp)
 655{
 656        char dev_name[30], *str;
 657        int ret;
 658
 659        snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
 660        str = strdup(dev_name);
 661        if (!str)
 662                return -ENOMEM;
 663
 664        ret = blk_create_device(parent, drv_name, str, if_type, devnum,
 665                                blksz, lba, devp);
 666        if (ret) {
 667                free(str);
 668                return ret;
 669        }
 670        device_set_name_alloced(*devp);
 671
 672        return 0;
 673}
 674
 675int blk_probe_or_unbind(struct udevice *dev)
 676{
 677        int ret;
 678
 679        ret = device_probe(dev);
 680        if (ret) {
 681                log_debug("probing %s failed\n", dev->name);
 682                device_unbind(dev);
 683        }
 684
 685        return ret;
 686}
 687
 688int blk_unbind_all(int if_type)
 689{
 690        struct uclass *uc;
 691        struct udevice *dev, *next;
 692        int ret;
 693
 694        ret = uclass_get(UCLASS_BLK, &uc);
 695        if (ret)
 696                return ret;
 697        uclass_foreach_dev_safe(dev, next, uc) {
 698                struct blk_desc *desc = dev_get_uclass_plat(dev);
 699
 700                if (desc->if_type == if_type) {
 701                        ret = device_remove(dev, DM_REMOVE_NORMAL);
 702                        if (ret)
 703                                return ret;
 704                        ret = device_unbind(dev);
 705                        if (ret)
 706                                return ret;
 707                }
 708        }
 709
 710        return 0;
 711}
 712
 713static int blk_post_probe(struct udevice *dev)
 714{
 715        if (IS_ENABLED(CONFIG_PARTITIONS) &&
 716            IS_ENABLED(CONFIG_HAVE_BLOCK_DEVICE)) {
 717                struct blk_desc *desc = dev_get_uclass_plat(dev);
 718
 719                part_init(desc);
 720        }
 721
 722        return 0;
 723}
 724
 725UCLASS_DRIVER(blk) = {
 726        .id             = UCLASS_BLK,
 727        .name           = "blk",
 728        .post_probe     = blk_post_probe,
 729        .per_device_plat_auto   = sizeof(struct blk_desc),
 730};
 731