109d71aacSSimon Glass /* 209d71aacSSimon Glass * Copyright (C) 2016 Google, Inc 309d71aacSSimon Glass * Written by Simon Glass <sjg@chromium.org> 409d71aacSSimon Glass * 509d71aacSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 609d71aacSSimon Glass */ 709d71aacSSimon Glass 809d71aacSSimon Glass #include <common.h> 909d71aacSSimon Glass #include <blk.h> 1009d71aacSSimon Glass #include <dm.h> 1109d71aacSSimon Glass #include <dm/device-internal.h> 1209d71aacSSimon Glass #include <dm/lists.h> 136a2ff3f4SStefan Roese #include <dm/uclass-internal.h> 1409d71aacSSimon Glass 15d508c82bSSimon Glass static const char *if_typename_str[IF_TYPE_COUNT] = { 16d508c82bSSimon Glass [IF_TYPE_IDE] = "ide", 17d508c82bSSimon Glass [IF_TYPE_SCSI] = "scsi", 18d508c82bSSimon Glass [IF_TYPE_ATAPI] = "atapi", 19d508c82bSSimon Glass [IF_TYPE_USB] = "usb", 20d508c82bSSimon Glass [IF_TYPE_DOC] = "doc", 21d508c82bSSimon Glass [IF_TYPE_MMC] = "mmc", 22d508c82bSSimon Glass [IF_TYPE_SD] = "sd", 23d508c82bSSimon Glass [IF_TYPE_SATA] = "sata", 24d508c82bSSimon Glass [IF_TYPE_HOST] = "host", 25d508c82bSSimon Glass [IF_TYPE_SYSTEMACE] = "ace", 26ffab6945SZhikang Zhang [IF_TYPE_NVME] = "nvme", 27441217e3SZhaoyifeng [IF_TYPE_RKNAND] = "rknand", 283872c3f4SDingqiang Lin [IF_TYPE_SPINAND] = "spinand", 293872c3f4SDingqiang Lin [IF_TYPE_SPINOR] = "spinor", 30*a3fec70dSJoseph Chen [IF_TYPE_RAMDISK] = "ramdisk", 31*a3fec70dSJoseph Chen 32d508c82bSSimon Glass }; 33d508c82bSSimon Glass 34d508c82bSSimon Glass static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { 3568e6f221SBin Meng [IF_TYPE_IDE] = UCLASS_IDE, 36e8a016b5SMichal Simek [IF_TYPE_SCSI] = UCLASS_SCSI, 37d508c82bSSimon Glass [IF_TYPE_ATAPI] = UCLASS_INVALID, 38d508c82bSSimon Glass [IF_TYPE_USB] = UCLASS_MASS_STORAGE, 39d508c82bSSimon Glass [IF_TYPE_DOC] = UCLASS_INVALID, 40d508c82bSSimon Glass [IF_TYPE_MMC] = UCLASS_MMC, 41d508c82bSSimon Glass [IF_TYPE_SD] = UCLASS_INVALID, 42d508c82bSSimon Glass [IF_TYPE_SATA] = UCLASS_AHCI, 43d508c82bSSimon Glass [IF_TYPE_HOST] = UCLASS_ROOT, 44ffab6945SZhikang Zhang [IF_TYPE_NVME] = UCLASS_NVME, 45441217e3SZhaoyifeng [IF_TYPE_RKNAND] = UCLASS_RKNAND, 463872c3f4SDingqiang Lin [IF_TYPE_SPINAND] = UCLASS_SPI_FLASH, 473872c3f4SDingqiang Lin [IF_TYPE_SPINOR] = UCLASS_SPI_FLASH, 48*a3fec70dSJoseph Chen [IF_TYPE_RAMDISK] = UCLASS_RAMDISK, 49d508c82bSSimon Glass [IF_TYPE_SYSTEMACE] = UCLASS_INVALID, 50d508c82bSSimon Glass }; 51d508c82bSSimon Glass 52d508c82bSSimon Glass static enum if_type if_typename_to_iftype(const char *if_typename) 53d508c82bSSimon Glass { 54d508c82bSSimon Glass int i; 55d508c82bSSimon Glass 56d508c82bSSimon Glass for (i = 0; i < IF_TYPE_COUNT; i++) { 57d508c82bSSimon Glass if (if_typename_str[i] && 58d508c82bSSimon Glass !strcmp(if_typename, if_typename_str[i])) 59d508c82bSSimon Glass return i; 60d508c82bSSimon Glass } 61d508c82bSSimon Glass 62d508c82bSSimon Glass return IF_TYPE_UNKNOWN; 63d508c82bSSimon Glass } 64d508c82bSSimon Glass 65d508c82bSSimon Glass static enum uclass_id if_type_to_uclass_id(enum if_type if_type) 66d508c82bSSimon Glass { 67d508c82bSSimon Glass return if_type_uclass_id[if_type]; 68d508c82bSSimon Glass } 69d508c82bSSimon Glass 706faa4ed7SSimon Glass const char *blk_get_if_type_name(enum if_type if_type) 716faa4ed7SSimon Glass { 726faa4ed7SSimon Glass return if_typename_str[if_type]; 736faa4ed7SSimon Glass } 746faa4ed7SSimon Glass 75d508c82bSSimon Glass struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum) 76d508c82bSSimon Glass { 77d508c82bSSimon Glass struct blk_desc *desc; 78d508c82bSSimon Glass struct udevice *dev; 79d508c82bSSimon Glass int ret; 80d508c82bSSimon Glass 81d508c82bSSimon Glass ret = blk_get_device(if_type, devnum, &dev); 82d508c82bSSimon Glass if (ret) 83d508c82bSSimon Glass return NULL; 84d508c82bSSimon Glass desc = dev_get_uclass_platdata(dev); 85d508c82bSSimon Glass 86d508c82bSSimon Glass return desc; 87d508c82bSSimon Glass } 88d508c82bSSimon Glass 89d508c82bSSimon Glass /* 90d508c82bSSimon Glass * This function is complicated with driver model. We look up the interface 91d508c82bSSimon Glass * name in a local table. This gives us an interface type which we can match 92d508c82bSSimon Glass * against the uclass of the block device's parent. 93d508c82bSSimon Glass */ 94d508c82bSSimon Glass struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum) 95d508c82bSSimon Glass { 96d508c82bSSimon Glass enum uclass_id uclass_id; 97d508c82bSSimon Glass enum if_type if_type; 98d508c82bSSimon Glass struct udevice *dev; 99d508c82bSSimon Glass struct uclass *uc; 100d508c82bSSimon Glass int ret; 101d508c82bSSimon Glass 102d508c82bSSimon Glass if_type = if_typename_to_iftype(if_typename); 103d508c82bSSimon Glass if (if_type == IF_TYPE_UNKNOWN) { 104d508c82bSSimon Glass debug("%s: Unknown interface type '%s'\n", __func__, 105d508c82bSSimon Glass if_typename); 106d508c82bSSimon Glass return NULL; 107d508c82bSSimon Glass } 108d508c82bSSimon Glass uclass_id = if_type_to_uclass_id(if_type); 109d508c82bSSimon Glass if (uclass_id == UCLASS_INVALID) { 110d508c82bSSimon Glass debug("%s: Unknown uclass for interface type'\n", 111d508c82bSSimon Glass if_typename_str[if_type]); 112d508c82bSSimon Glass return NULL; 113d508c82bSSimon Glass } 114d508c82bSSimon Glass 115d508c82bSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 116d508c82bSSimon Glass if (ret) 117d508c82bSSimon Glass return NULL; 118d508c82bSSimon Glass uclass_foreach_dev(dev, uc) { 119d508c82bSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 120d508c82bSSimon Glass 121d508c82bSSimon Glass debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 122d508c82bSSimon Glass if_type, devnum, dev->name, desc->if_type, desc->devnum); 123d508c82bSSimon Glass if (desc->devnum != devnum) 124d508c82bSSimon Glass continue; 125d508c82bSSimon Glass 126d508c82bSSimon Glass /* Find out the parent device uclass */ 127d508c82bSSimon Glass if (device_get_uclass_id(dev->parent) != uclass_id) { 128d508c82bSSimon Glass debug("%s: parent uclass %d, this dev %d\n", __func__, 129d508c82bSSimon Glass device_get_uclass_id(dev->parent), uclass_id); 130d508c82bSSimon Glass continue; 131d508c82bSSimon Glass } 132d508c82bSSimon Glass 133d508c82bSSimon Glass if (device_probe(dev)) 134d508c82bSSimon Glass return NULL; 135d508c82bSSimon Glass 136d508c82bSSimon Glass debug("%s: Device desc %p\n", __func__, desc); 137d508c82bSSimon Glass return desc; 138d508c82bSSimon Glass } 139d508c82bSSimon Glass debug("%s: No device found\n", __func__); 140d508c82bSSimon Glass 141d508c82bSSimon Glass return NULL; 142d508c82bSSimon Glass } 143d508c82bSSimon Glass 144d508c82bSSimon Glass /** 145d508c82bSSimon Glass * get_desc() - Get the block device descriptor for the given device number 146d508c82bSSimon Glass * 147d508c82bSSimon Glass * @if_type: Interface type 148d508c82bSSimon Glass * @devnum: Device number (0 = first) 149d508c82bSSimon Glass * @descp: Returns block device descriptor on success 150d508c82bSSimon Glass * @return 0 on success, -ENODEV if there is no such device and no device 151d508c82bSSimon Glass * with a higher device number, -ENOENT if there is no such device but there 152d508c82bSSimon Glass * is one with a higher number, or other -ve on other error. 153d508c82bSSimon Glass */ 154d508c82bSSimon Glass static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp) 155d508c82bSSimon Glass { 156d508c82bSSimon Glass bool found_more = false; 157d508c82bSSimon Glass struct udevice *dev; 158d508c82bSSimon Glass struct uclass *uc; 159d508c82bSSimon Glass int ret; 160d508c82bSSimon Glass 161d508c82bSSimon Glass *descp = NULL; 162d508c82bSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 163d508c82bSSimon Glass if (ret) 164d508c82bSSimon Glass return ret; 165d508c82bSSimon Glass uclass_foreach_dev(dev, uc) { 166d508c82bSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 167d508c82bSSimon Glass 168d508c82bSSimon Glass debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 169d508c82bSSimon Glass if_type, devnum, dev->name, desc->if_type, desc->devnum); 170d508c82bSSimon Glass if (desc->if_type == if_type) { 171d508c82bSSimon Glass if (desc->devnum == devnum) { 172d508c82bSSimon Glass ret = device_probe(dev); 173d508c82bSSimon Glass if (ret) 174d508c82bSSimon Glass return ret; 175d508c82bSSimon Glass 1764408f6f4SMichal Simek *descp = desc; 1774408f6f4SMichal Simek return 0; 178d508c82bSSimon Glass } else if (desc->devnum > devnum) { 179d508c82bSSimon Glass found_more = true; 180d508c82bSSimon Glass } 181d508c82bSSimon Glass } 182d508c82bSSimon Glass } 183d508c82bSSimon Glass 184d508c82bSSimon Glass return found_more ? -ENOENT : -ENODEV; 185d508c82bSSimon Glass } 186d508c82bSSimon Glass 187cd0fb55bSSimon Glass int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart) 188cd0fb55bSSimon Glass { 189cd0fb55bSSimon Glass struct udevice *dev; 190cd0fb55bSSimon Glass int ret; 191cd0fb55bSSimon Glass 192cd0fb55bSSimon Glass ret = blk_get_device(if_type, devnum, &dev); 193cd0fb55bSSimon Glass if (ret) 194cd0fb55bSSimon Glass return ret; 195cd0fb55bSSimon Glass 196cd0fb55bSSimon Glass return blk_select_hwpart(dev, hwpart); 197cd0fb55bSSimon Glass } 198cd0fb55bSSimon Glass 199d508c82bSSimon Glass int blk_list_part(enum if_type if_type) 200d508c82bSSimon Glass { 201d508c82bSSimon Glass struct blk_desc *desc; 202d508c82bSSimon Glass int devnum, ok; 203d508c82bSSimon Glass int ret; 204d508c82bSSimon Glass 205d508c82bSSimon Glass for (ok = 0, devnum = 0;; ++devnum) { 206d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 207d508c82bSSimon Glass if (ret == -ENODEV) 208d508c82bSSimon Glass break; 209d508c82bSSimon Glass else if (ret) 210d508c82bSSimon Glass continue; 211d508c82bSSimon Glass if (desc->part_type != PART_TYPE_UNKNOWN) { 212d508c82bSSimon Glass ++ok; 213d508c82bSSimon Glass if (devnum) 214d508c82bSSimon Glass putc('\n'); 215d508c82bSSimon Glass part_print(desc); 216d508c82bSSimon Glass } 217d508c82bSSimon Glass } 218d508c82bSSimon Glass if (!ok) 219d508c82bSSimon Glass return -ENODEV; 220d508c82bSSimon Glass 221d508c82bSSimon Glass return 0; 222d508c82bSSimon Glass } 223d508c82bSSimon Glass 224d508c82bSSimon Glass int blk_print_part_devnum(enum if_type if_type, int devnum) 225d508c82bSSimon Glass { 226d508c82bSSimon Glass struct blk_desc *desc; 227d508c82bSSimon Glass int ret; 228d508c82bSSimon Glass 229d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 230d508c82bSSimon Glass if (ret) 231d508c82bSSimon Glass return ret; 232d508c82bSSimon Glass if (desc->type == DEV_TYPE_UNKNOWN) 233d508c82bSSimon Glass return -ENOENT; 234d508c82bSSimon Glass part_print(desc); 235d508c82bSSimon Glass 236d508c82bSSimon Glass return 0; 237d508c82bSSimon Glass } 238d508c82bSSimon Glass 239d508c82bSSimon Glass void blk_list_devices(enum if_type if_type) 240d508c82bSSimon Glass { 241d508c82bSSimon Glass struct blk_desc *desc; 242d508c82bSSimon Glass int ret; 243d508c82bSSimon Glass int i; 244d508c82bSSimon Glass 245d508c82bSSimon Glass for (i = 0;; ++i) { 246d508c82bSSimon Glass ret = get_desc(if_type, i, &desc); 247d508c82bSSimon Glass if (ret == -ENODEV) 248d508c82bSSimon Glass break; 249d508c82bSSimon Glass else if (ret) 250d508c82bSSimon Glass continue; 251d508c82bSSimon Glass if (desc->type == DEV_TYPE_UNKNOWN) 252d508c82bSSimon Glass continue; /* list only known devices */ 253d508c82bSSimon Glass printf("Device %d: ", i); 254d508c82bSSimon Glass dev_print(desc); 255d508c82bSSimon Glass } 256d508c82bSSimon Glass } 257d508c82bSSimon Glass 258d508c82bSSimon Glass int blk_print_device_num(enum if_type if_type, int devnum) 259d508c82bSSimon Glass { 260d508c82bSSimon Glass struct blk_desc *desc; 261d508c82bSSimon Glass int ret; 262d508c82bSSimon Glass 263d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 264d508c82bSSimon Glass if (ret) 265d508c82bSSimon Glass return ret; 266d508c82bSSimon Glass printf("\nIDE device %d: ", devnum); 267d508c82bSSimon Glass dev_print(desc); 268d508c82bSSimon Glass 269d508c82bSSimon Glass return 0; 270d508c82bSSimon Glass } 271d508c82bSSimon Glass 272d508c82bSSimon Glass int blk_show_device(enum if_type if_type, int devnum) 273d508c82bSSimon Glass { 274d508c82bSSimon Glass struct blk_desc *desc; 275d508c82bSSimon Glass int ret; 276d508c82bSSimon Glass 277d508c82bSSimon Glass printf("\nDevice %d: ", devnum); 278d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 279d508c82bSSimon Glass if (ret == -ENODEV || ret == -ENOENT) { 280d508c82bSSimon Glass printf("unknown device\n"); 281d508c82bSSimon Glass return -ENODEV; 282d508c82bSSimon Glass } 283d508c82bSSimon Glass if (ret) 284d508c82bSSimon Glass return ret; 285d508c82bSSimon Glass dev_print(desc); 286d508c82bSSimon Glass 287d508c82bSSimon Glass if (desc->type == DEV_TYPE_UNKNOWN) 288d508c82bSSimon Glass return -ENOENT; 289d508c82bSSimon Glass 290d508c82bSSimon Glass return 0; 291d508c82bSSimon Glass } 292d508c82bSSimon Glass 293d508c82bSSimon Glass ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start, 294d508c82bSSimon Glass lbaint_t blkcnt, void *buffer) 295d508c82bSSimon Glass { 296d508c82bSSimon Glass struct blk_desc *desc; 297d508c82bSSimon Glass ulong n; 298d508c82bSSimon Glass int ret; 299d508c82bSSimon Glass 300d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 301d508c82bSSimon Glass if (ret) 302d508c82bSSimon Glass return ret; 303d508c82bSSimon Glass n = blk_dread(desc, start, blkcnt, buffer); 304d508c82bSSimon Glass if (IS_ERR_VALUE(n)) 305d508c82bSSimon Glass return n; 306d508c82bSSimon Glass 307d508c82bSSimon Glass return n; 308d508c82bSSimon Glass } 309d508c82bSSimon Glass 310d508c82bSSimon Glass ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start, 311d508c82bSSimon Glass lbaint_t blkcnt, const void *buffer) 312d508c82bSSimon Glass { 313d508c82bSSimon Glass struct blk_desc *desc; 314d508c82bSSimon Glass int ret; 315d508c82bSSimon Glass 316d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 317d508c82bSSimon Glass if (ret) 318d508c82bSSimon Glass return ret; 319d508c82bSSimon Glass return blk_dwrite(desc, start, blkcnt, buffer); 320d508c82bSSimon Glass } 321d508c82bSSimon Glass 322cd0fb55bSSimon Glass int blk_select_hwpart(struct udevice *dev, int hwpart) 323cd0fb55bSSimon Glass { 324cd0fb55bSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 325cd0fb55bSSimon Glass 326cd0fb55bSSimon Glass if (!ops) 327cd0fb55bSSimon Glass return -ENOSYS; 328cd0fb55bSSimon Glass if (!ops->select_hwpart) 329cd0fb55bSSimon Glass return 0; 330cd0fb55bSSimon Glass 331cd0fb55bSSimon Glass return ops->select_hwpart(dev, hwpart); 332cd0fb55bSSimon Glass } 333cd0fb55bSSimon Glass 334cd0fb55bSSimon Glass int blk_dselect_hwpart(struct blk_desc *desc, int hwpart) 335cd0fb55bSSimon Glass { 336cd0fb55bSSimon Glass return blk_select_hwpart(desc->bdev, hwpart); 337cd0fb55bSSimon Glass } 338cd0fb55bSSimon Glass 33909d71aacSSimon Glass int blk_first_device(int if_type, struct udevice **devp) 34009d71aacSSimon Glass { 34109d71aacSSimon Glass struct blk_desc *desc; 34209d71aacSSimon Glass int ret; 34309d71aacSSimon Glass 3446a2ff3f4SStefan Roese ret = uclass_find_first_device(UCLASS_BLK, devp); 34509d71aacSSimon Glass if (ret) 34609d71aacSSimon Glass return ret; 34709d71aacSSimon Glass if (!*devp) 34809d71aacSSimon Glass return -ENODEV; 34909d71aacSSimon Glass do { 35009d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 35109d71aacSSimon Glass if (desc->if_type == if_type) 35209d71aacSSimon Glass return 0; 3536a2ff3f4SStefan Roese ret = uclass_find_next_device(devp); 35409d71aacSSimon Glass if (ret) 35509d71aacSSimon Glass return ret; 35609d71aacSSimon Glass } while (*devp); 35709d71aacSSimon Glass 35809d71aacSSimon Glass return -ENODEV; 35909d71aacSSimon Glass } 36009d71aacSSimon Glass 36109d71aacSSimon Glass int blk_next_device(struct udevice **devp) 36209d71aacSSimon Glass { 36309d71aacSSimon Glass struct blk_desc *desc; 36409d71aacSSimon Glass int ret, if_type; 36509d71aacSSimon Glass 36609d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 36709d71aacSSimon Glass if_type = desc->if_type; 36809d71aacSSimon Glass do { 3696a2ff3f4SStefan Roese ret = uclass_find_next_device(devp); 37009d71aacSSimon Glass if (ret) 37109d71aacSSimon Glass return ret; 37209d71aacSSimon Glass if (!*devp) 37309d71aacSSimon Glass return -ENODEV; 37409d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 37509d71aacSSimon Glass if (desc->if_type == if_type) 37609d71aacSSimon Glass return 0; 37709d71aacSSimon Glass } while (1); 37809d71aacSSimon Glass } 37909d71aacSSimon Glass 3806139281aSSimon Glass int blk_find_device(int if_type, int devnum, struct udevice **devp) 38109d71aacSSimon Glass { 38209d71aacSSimon Glass struct uclass *uc; 38309d71aacSSimon Glass struct udevice *dev; 38409d71aacSSimon Glass int ret; 38509d71aacSSimon Glass 38609d71aacSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 38709d71aacSSimon Glass if (ret) 38809d71aacSSimon Glass return ret; 38909d71aacSSimon Glass uclass_foreach_dev(dev, uc) { 39009d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 39109d71aacSSimon Glass 39209d71aacSSimon Glass debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 39309d71aacSSimon Glass if_type, devnum, dev->name, desc->if_type, desc->devnum); 39409d71aacSSimon Glass if (desc->if_type == if_type && desc->devnum == devnum) { 39509d71aacSSimon Glass *devp = dev; 3966139281aSSimon Glass return 0; 39709d71aacSSimon Glass } 39809d71aacSSimon Glass } 39909d71aacSSimon Glass 40009d71aacSSimon Glass return -ENODEV; 40109d71aacSSimon Glass } 40209d71aacSSimon Glass 4036139281aSSimon Glass int blk_get_device(int if_type, int devnum, struct udevice **devp) 4046139281aSSimon Glass { 4056139281aSSimon Glass int ret; 4066139281aSSimon Glass 4076139281aSSimon Glass ret = blk_find_device(if_type, devnum, devp); 4086139281aSSimon Glass if (ret) 4096139281aSSimon Glass return ret; 4106139281aSSimon Glass 4116139281aSSimon Glass return device_probe(*devp); 4126139281aSSimon Glass } 4136139281aSSimon Glass 41409d71aacSSimon Glass unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, 41509d71aacSSimon Glass lbaint_t blkcnt, void *buffer) 41609d71aacSSimon Glass { 41709d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 41809d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 419e40cf34aSEric Nelson ulong blks_read; 42009d71aacSSimon Glass 42109d71aacSSimon Glass if (!ops->read) 42209d71aacSSimon Glass return -ENOSYS; 42309d71aacSSimon Glass 424e40cf34aSEric Nelson if (blkcache_read(block_dev->if_type, block_dev->devnum, 425e40cf34aSEric Nelson start, blkcnt, block_dev->blksz, buffer)) 426e40cf34aSEric Nelson return blkcnt; 427e40cf34aSEric Nelson blks_read = ops->read(dev, start, blkcnt, buffer); 428e40cf34aSEric Nelson if (blks_read == blkcnt) 429e40cf34aSEric Nelson blkcache_fill(block_dev->if_type, block_dev->devnum, 430e40cf34aSEric Nelson start, blkcnt, block_dev->blksz, buffer); 431e40cf34aSEric Nelson 432e40cf34aSEric Nelson return blks_read; 43309d71aacSSimon Glass } 43409d71aacSSimon Glass 43509d71aacSSimon Glass unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start, 43609d71aacSSimon Glass lbaint_t blkcnt, const void *buffer) 43709d71aacSSimon Glass { 43809d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 43909d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 44009d71aacSSimon Glass 44109d71aacSSimon Glass if (!ops->write) 44209d71aacSSimon Glass return -ENOSYS; 44309d71aacSSimon Glass 444e40cf34aSEric Nelson blkcache_invalidate(block_dev->if_type, block_dev->devnum); 44509d71aacSSimon Glass return ops->write(dev, start, blkcnt, buffer); 44609d71aacSSimon Glass } 44709d71aacSSimon Glass 44809d71aacSSimon Glass unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, 44909d71aacSSimon Glass lbaint_t blkcnt) 45009d71aacSSimon Glass { 45109d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 45209d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 45309d71aacSSimon Glass 45409d71aacSSimon Glass if (!ops->erase) 45509d71aacSSimon Glass return -ENOSYS; 45609d71aacSSimon Glass 457e40cf34aSEric Nelson blkcache_invalidate(block_dev->if_type, block_dev->devnum); 45809d71aacSSimon Glass return ops->erase(dev, start, blkcnt); 45909d71aacSSimon Glass } 46009d71aacSSimon Glass 46109d71aacSSimon Glass int blk_prepare_device(struct udevice *dev) 46209d71aacSSimon Glass { 46309d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 46409d71aacSSimon Glass 46509d71aacSSimon Glass part_init(desc); 46609d71aacSSimon Glass 46709d71aacSSimon Glass return 0; 46809d71aacSSimon Glass } 46909d71aacSSimon Glass 4709f103b9cSSimon Glass int blk_get_from_parent(struct udevice *parent, struct udevice **devp) 4719f103b9cSSimon Glass { 4729f103b9cSSimon Glass struct udevice *dev; 4739f103b9cSSimon Glass enum uclass_id id; 4749f103b9cSSimon Glass int ret; 4759f103b9cSSimon Glass 4769f103b9cSSimon Glass device_find_first_child(parent, &dev); 4779f103b9cSSimon Glass if (!dev) { 4789f103b9cSSimon Glass debug("%s: No block device found for parent '%s'\n", __func__, 4799f103b9cSSimon Glass parent->name); 4809f103b9cSSimon Glass return -ENODEV; 4819f103b9cSSimon Glass } 4829f103b9cSSimon Glass id = device_get_uclass_id(dev); 4839f103b9cSSimon Glass if (id != UCLASS_BLK) { 4849f103b9cSSimon Glass debug("%s: Incorrect uclass %s for block device '%s'\n", 4859f103b9cSSimon Glass __func__, uclass_get_name(id), dev->name); 4869f103b9cSSimon Glass return -ENOTBLK; 4879f103b9cSSimon Glass } 4889f103b9cSSimon Glass ret = device_probe(dev); 4899f103b9cSSimon Glass if (ret) 4909f103b9cSSimon Glass return ret; 4919f103b9cSSimon Glass *devp = dev; 4929f103b9cSSimon Glass 4939f103b9cSSimon Glass return 0; 4949f103b9cSSimon Glass } 4959f103b9cSSimon Glass 49652138fd4SSimon Glass int blk_find_max_devnum(enum if_type if_type) 49752138fd4SSimon Glass { 49852138fd4SSimon Glass struct udevice *dev; 49952138fd4SSimon Glass int max_devnum = -ENODEV; 50052138fd4SSimon Glass struct uclass *uc; 50152138fd4SSimon Glass int ret; 50252138fd4SSimon Glass 50352138fd4SSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 50452138fd4SSimon Glass if (ret) 50552138fd4SSimon Glass return ret; 50652138fd4SSimon Glass uclass_foreach_dev(dev, uc) { 50752138fd4SSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 50852138fd4SSimon Glass 50952138fd4SSimon Glass if (desc->if_type == if_type && desc->devnum > max_devnum) 51052138fd4SSimon Glass max_devnum = desc->devnum; 51152138fd4SSimon Glass } 51252138fd4SSimon Glass 51352138fd4SSimon Glass return max_devnum; 51452138fd4SSimon Glass } 51552138fd4SSimon Glass 516e8abbb53SSimon Glass static int blk_next_free_devnum(enum if_type if_type) 517e8abbb53SSimon Glass { 518e8abbb53SSimon Glass int ret; 519e8abbb53SSimon Glass 520e8abbb53SSimon Glass ret = blk_find_max_devnum(if_type); 521e8abbb53SSimon Glass if (ret == -ENODEV) 522e8abbb53SSimon Glass return 0; 523e8abbb53SSimon Glass if (ret < 0) 524e8abbb53SSimon Glass return ret; 525e8abbb53SSimon Glass 526e8abbb53SSimon Glass return ret + 1; 527e8abbb53SSimon Glass } 528e8abbb53SSimon Glass 529e48eeb9eSSimon Glass static int blk_claim_devnum(enum if_type if_type, int devnum) 530e48eeb9eSSimon Glass { 531e48eeb9eSSimon Glass struct udevice *dev; 532e48eeb9eSSimon Glass struct uclass *uc; 533e48eeb9eSSimon Glass int ret; 534e48eeb9eSSimon Glass 535e48eeb9eSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 536e48eeb9eSSimon Glass if (ret) 537e48eeb9eSSimon Glass return ret; 538e48eeb9eSSimon Glass uclass_foreach_dev(dev, uc) { 539e48eeb9eSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 540e48eeb9eSSimon Glass 541e48eeb9eSSimon Glass if (desc->if_type == if_type && desc->devnum == devnum) { 542e48eeb9eSSimon Glass int next = blk_next_free_devnum(if_type); 543e48eeb9eSSimon Glass 544e48eeb9eSSimon Glass if (next < 0) 545e48eeb9eSSimon Glass return next; 546e48eeb9eSSimon Glass desc->devnum = next; 547e48eeb9eSSimon Glass return 0; 548e48eeb9eSSimon Glass } 549e48eeb9eSSimon Glass } 550e48eeb9eSSimon Glass 551e48eeb9eSSimon Glass return -ENOENT; 552e48eeb9eSSimon Glass } 553e48eeb9eSSimon Glass 55409d71aacSSimon Glass int blk_create_device(struct udevice *parent, const char *drv_name, 55509d71aacSSimon Glass const char *name, int if_type, int devnum, int blksz, 55609d71aacSSimon Glass lbaint_t size, struct udevice **devp) 55709d71aacSSimon Glass { 55809d71aacSSimon Glass struct blk_desc *desc; 55909d71aacSSimon Glass struct udevice *dev; 56009d71aacSSimon Glass int ret; 56109d71aacSSimon Glass 56252138fd4SSimon Glass if (devnum == -1) { 563e48eeb9eSSimon Glass devnum = blk_next_free_devnum(if_type); 564e48eeb9eSSimon Glass } else { 565e48eeb9eSSimon Glass ret = blk_claim_devnum(if_type, devnum); 566e48eeb9eSSimon Glass if (ret < 0 && ret != -ENOENT) 56752138fd4SSimon Glass return ret; 56852138fd4SSimon Glass } 569e48eeb9eSSimon Glass if (devnum < 0) 570e48eeb9eSSimon Glass return devnum; 57172a85c0dSSimon Glass ret = device_bind_driver(parent, drv_name, name, &dev); 57272a85c0dSSimon Glass if (ret) 57372a85c0dSSimon Glass return ret; 57472a85c0dSSimon Glass desc = dev_get_uclass_platdata(dev); 57572a85c0dSSimon Glass desc->if_type = if_type; 57672a85c0dSSimon Glass desc->blksz = blksz; 57772a85c0dSSimon Glass desc->lba = size / blksz; 57872a85c0dSSimon Glass desc->part_type = PART_TYPE_UNKNOWN; 57972a85c0dSSimon Glass desc->bdev = dev; 58009d71aacSSimon Glass desc->devnum = devnum; 58109d71aacSSimon Glass *devp = dev; 58209d71aacSSimon Glass 58309d71aacSSimon Glass return 0; 58409d71aacSSimon Glass } 58509d71aacSSimon Glass 5869107c973SSimon Glass int blk_create_devicef(struct udevice *parent, const char *drv_name, 5879107c973SSimon Glass const char *name, int if_type, int devnum, int blksz, 5889107c973SSimon Glass lbaint_t size, struct udevice **devp) 5899107c973SSimon Glass { 5909107c973SSimon Glass char dev_name[30], *str; 591d0773524SSimon Glass int ret; 5929107c973SSimon Glass 5939107c973SSimon Glass snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name); 5949107c973SSimon Glass str = strdup(dev_name); 5959107c973SSimon Glass if (!str) 5969107c973SSimon Glass return -ENOMEM; 5979107c973SSimon Glass 598d0773524SSimon Glass ret = blk_create_device(parent, drv_name, str, if_type, devnum, 5999107c973SSimon Glass blksz, size, devp); 600d0773524SSimon Glass if (ret) { 601d0773524SSimon Glass free(str); 602d0773524SSimon Glass return ret; 603d0773524SSimon Glass } 604d0773524SSimon Glass device_set_name_alloced(*devp); 605d0773524SSimon Glass 6067074b2a3SSimon Glass return 0; 6079107c973SSimon Glass } 6089107c973SSimon Glass 60909d71aacSSimon Glass int blk_unbind_all(int if_type) 61009d71aacSSimon Glass { 61109d71aacSSimon Glass struct uclass *uc; 61209d71aacSSimon Glass struct udevice *dev, *next; 61309d71aacSSimon Glass int ret; 61409d71aacSSimon Glass 61509d71aacSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 61609d71aacSSimon Glass if (ret) 61709d71aacSSimon Glass return ret; 61809d71aacSSimon Glass uclass_foreach_dev_safe(dev, next, uc) { 61909d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 62009d71aacSSimon Glass 62109d71aacSSimon Glass if (desc->if_type == if_type) { 622706865afSStefan Roese ret = device_remove(dev, DM_REMOVE_NORMAL); 62309d71aacSSimon Glass if (ret) 62409d71aacSSimon Glass return ret; 62509d71aacSSimon Glass ret = device_unbind(dev); 62609d71aacSSimon Glass if (ret) 62709d71aacSSimon Glass return ret; 62809d71aacSSimon Glass } 62909d71aacSSimon Glass } 63009d71aacSSimon Glass 63109d71aacSSimon Glass return 0; 63209d71aacSSimon Glass } 63309d71aacSSimon Glass 63409d71aacSSimon Glass UCLASS_DRIVER(blk) = { 63509d71aacSSimon Glass .id = UCLASS_BLK, 63609d71aacSSimon Glass .name = "blk", 63709d71aacSSimon Glass .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc), 63809d71aacSSimon Glass }; 639