1 /* 2 * Copyright (C) 2016 Google, Inc 3 * Written by Simon Glass <sjg@chromium.org> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <blk.h> 10 #include <dm.h> 11 #include <dm/device-internal.h> 12 #include <dm/lists.h> 13 14 static const char *if_typename_str[IF_TYPE_COUNT] = { 15 [IF_TYPE_IDE] = "ide", 16 [IF_TYPE_SCSI] = "scsi", 17 [IF_TYPE_ATAPI] = "atapi", 18 [IF_TYPE_USB] = "usb", 19 [IF_TYPE_DOC] = "doc", 20 [IF_TYPE_MMC] = "mmc", 21 [IF_TYPE_SD] = "sd", 22 [IF_TYPE_SATA] = "sata", 23 [IF_TYPE_HOST] = "host", 24 [IF_TYPE_SYSTEMACE] = "ace", 25 }; 26 27 static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { 28 [IF_TYPE_IDE] = UCLASS_INVALID, 29 [IF_TYPE_SCSI] = UCLASS_INVALID, 30 [IF_TYPE_ATAPI] = UCLASS_INVALID, 31 [IF_TYPE_USB] = UCLASS_MASS_STORAGE, 32 [IF_TYPE_DOC] = UCLASS_INVALID, 33 [IF_TYPE_MMC] = UCLASS_MMC, 34 [IF_TYPE_SD] = UCLASS_INVALID, 35 [IF_TYPE_SATA] = UCLASS_AHCI, 36 [IF_TYPE_HOST] = UCLASS_ROOT, 37 [IF_TYPE_SYSTEMACE] = UCLASS_INVALID, 38 }; 39 40 static enum if_type if_typename_to_iftype(const char *if_typename) 41 { 42 int i; 43 44 for (i = 0; i < IF_TYPE_COUNT; i++) { 45 if (if_typename_str[i] && 46 !strcmp(if_typename, if_typename_str[i])) 47 return i; 48 } 49 50 return IF_TYPE_UNKNOWN; 51 } 52 53 static enum uclass_id if_type_to_uclass_id(enum if_type if_type) 54 { 55 return if_type_uclass_id[if_type]; 56 } 57 58 struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum) 59 { 60 struct blk_desc *desc; 61 struct udevice *dev; 62 int ret; 63 64 ret = blk_get_device(if_type, devnum, &dev); 65 if (ret) 66 return NULL; 67 desc = dev_get_uclass_platdata(dev); 68 69 return desc; 70 } 71 72 /* 73 * This function is complicated with driver model. We look up the interface 74 * name in a local table. This gives us an interface type which we can match 75 * against the uclass of the block device's parent. 76 */ 77 struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum) 78 { 79 enum uclass_id uclass_id; 80 enum if_type if_type; 81 struct udevice *dev; 82 struct uclass *uc; 83 int ret; 84 85 if_type = if_typename_to_iftype(if_typename); 86 if (if_type == IF_TYPE_UNKNOWN) { 87 debug("%s: Unknown interface type '%s'\n", __func__, 88 if_typename); 89 return NULL; 90 } 91 uclass_id = if_type_to_uclass_id(if_type); 92 if (uclass_id == UCLASS_INVALID) { 93 debug("%s: Unknown uclass for interface type'\n", 94 if_typename_str[if_type]); 95 return NULL; 96 } 97 98 ret = uclass_get(UCLASS_BLK, &uc); 99 if (ret) 100 return NULL; 101 uclass_foreach_dev(dev, uc) { 102 struct blk_desc *desc = dev_get_uclass_platdata(dev); 103 104 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 105 if_type, devnum, dev->name, desc->if_type, desc->devnum); 106 if (desc->devnum != devnum) 107 continue; 108 109 /* Find out the parent device uclass */ 110 if (device_get_uclass_id(dev->parent) != uclass_id) { 111 debug("%s: parent uclass %d, this dev %d\n", __func__, 112 device_get_uclass_id(dev->parent), uclass_id); 113 continue; 114 } 115 116 if (device_probe(dev)) 117 return NULL; 118 119 debug("%s: Device desc %p\n", __func__, desc); 120 return desc; 121 } 122 debug("%s: No device found\n", __func__); 123 124 return NULL; 125 } 126 127 /** 128 * get_desc() - Get the block device descriptor for the given device number 129 * 130 * @if_type: Interface type 131 * @devnum: Device number (0 = first) 132 * @descp: Returns block device descriptor on success 133 * @return 0 on success, -ENODEV if there is no such device and no device 134 * with a higher device number, -ENOENT if there is no such device but there 135 * is one with a higher number, or other -ve on other error. 136 */ 137 static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp) 138 { 139 bool found_more = false; 140 struct udevice *dev; 141 struct uclass *uc; 142 int ret; 143 144 *descp = NULL; 145 ret = uclass_get(UCLASS_BLK, &uc); 146 if (ret) 147 return ret; 148 uclass_foreach_dev(dev, uc) { 149 struct blk_desc *desc = dev_get_uclass_platdata(dev); 150 151 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 152 if_type, devnum, dev->name, desc->if_type, desc->devnum); 153 if (desc->if_type == if_type) { 154 if (desc->devnum == devnum) { 155 ret = device_probe(dev); 156 if (ret) 157 return ret; 158 159 *descp = desc; 160 return 0; 161 } else if (desc->devnum > devnum) { 162 found_more = true; 163 } 164 } 165 } 166 167 return found_more ? -ENOENT : -ENODEV; 168 } 169 170 int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart) 171 { 172 struct udevice *dev; 173 int ret; 174 175 ret = blk_get_device(if_type, devnum, &dev); 176 if (ret) 177 return ret; 178 179 return blk_select_hwpart(dev, hwpart); 180 } 181 182 int blk_list_part(enum if_type if_type) 183 { 184 struct blk_desc *desc; 185 int devnum, ok; 186 int ret; 187 188 for (ok = 0, devnum = 0;; ++devnum) { 189 ret = get_desc(if_type, devnum, &desc); 190 if (ret == -ENODEV) 191 break; 192 else if (ret) 193 continue; 194 if (desc->part_type != PART_TYPE_UNKNOWN) { 195 ++ok; 196 if (devnum) 197 putc('\n'); 198 part_print(desc); 199 } 200 } 201 if (!ok) 202 return -ENODEV; 203 204 return 0; 205 } 206 207 int blk_print_part_devnum(enum if_type if_type, int devnum) 208 { 209 struct blk_desc *desc; 210 int ret; 211 212 ret = get_desc(if_type, devnum, &desc); 213 if (ret) 214 return ret; 215 if (desc->type == DEV_TYPE_UNKNOWN) 216 return -ENOENT; 217 part_print(desc); 218 219 return 0; 220 } 221 222 void blk_list_devices(enum if_type if_type) 223 { 224 struct blk_desc *desc; 225 int ret; 226 int i; 227 228 for (i = 0;; ++i) { 229 ret = get_desc(if_type, i, &desc); 230 if (ret == -ENODEV) 231 break; 232 else if (ret) 233 continue; 234 if (desc->type == DEV_TYPE_UNKNOWN) 235 continue; /* list only known devices */ 236 printf("Device %d: ", i); 237 dev_print(desc); 238 } 239 } 240 241 int blk_print_device_num(enum if_type if_type, int devnum) 242 { 243 struct blk_desc *desc; 244 int ret; 245 246 ret = get_desc(if_type, devnum, &desc); 247 if (ret) 248 return ret; 249 printf("\nIDE device %d: ", devnum); 250 dev_print(desc); 251 252 return 0; 253 } 254 255 int blk_show_device(enum if_type if_type, int devnum) 256 { 257 struct blk_desc *desc; 258 int ret; 259 260 printf("\nDevice %d: ", devnum); 261 ret = get_desc(if_type, devnum, &desc); 262 if (ret == -ENODEV || ret == -ENOENT) { 263 printf("unknown device\n"); 264 return -ENODEV; 265 } 266 if (ret) 267 return ret; 268 dev_print(desc); 269 270 if (desc->type == DEV_TYPE_UNKNOWN) 271 return -ENOENT; 272 273 return 0; 274 } 275 276 ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start, 277 lbaint_t blkcnt, void *buffer) 278 { 279 struct blk_desc *desc; 280 ulong n; 281 int ret; 282 283 ret = get_desc(if_type, devnum, &desc); 284 if (ret) 285 return ret; 286 n = blk_dread(desc, start, blkcnt, buffer); 287 if (IS_ERR_VALUE(n)) 288 return n; 289 290 /* flush cache after read */ 291 flush_cache((ulong)buffer, blkcnt * desc->blksz); 292 293 return n; 294 } 295 296 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start, 297 lbaint_t blkcnt, const void *buffer) 298 { 299 struct blk_desc *desc; 300 int ret; 301 302 ret = get_desc(if_type, devnum, &desc); 303 if (ret) 304 return ret; 305 return blk_dwrite(desc, start, blkcnt, buffer); 306 } 307 308 int blk_select_hwpart(struct udevice *dev, int hwpart) 309 { 310 const struct blk_ops *ops = blk_get_ops(dev); 311 312 if (!ops) 313 return -ENOSYS; 314 if (!ops->select_hwpart) 315 return 0; 316 317 return ops->select_hwpart(dev, hwpart); 318 } 319 320 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart) 321 { 322 return blk_select_hwpart(desc->bdev, hwpart); 323 } 324 325 int blk_first_device(int if_type, struct udevice **devp) 326 { 327 struct blk_desc *desc; 328 int ret; 329 330 ret = uclass_first_device(UCLASS_BLK, devp); 331 if (ret) 332 return ret; 333 if (!*devp) 334 return -ENODEV; 335 do { 336 desc = dev_get_uclass_platdata(*devp); 337 if (desc->if_type == if_type) 338 return 0; 339 ret = uclass_next_device(devp); 340 if (ret) 341 return ret; 342 } while (*devp); 343 344 return -ENODEV; 345 } 346 347 int blk_next_device(struct udevice **devp) 348 { 349 struct blk_desc *desc; 350 int ret, if_type; 351 352 desc = dev_get_uclass_platdata(*devp); 353 if_type = desc->if_type; 354 do { 355 ret = uclass_next_device(devp); 356 if (ret) 357 return ret; 358 if (!*devp) 359 return -ENODEV; 360 desc = dev_get_uclass_platdata(*devp); 361 if (desc->if_type == if_type) 362 return 0; 363 } while (1); 364 } 365 366 int blk_get_device(int if_type, int devnum, struct udevice **devp) 367 { 368 struct uclass *uc; 369 struct udevice *dev; 370 int ret; 371 372 ret = uclass_get(UCLASS_BLK, &uc); 373 if (ret) 374 return ret; 375 uclass_foreach_dev(dev, uc) { 376 struct blk_desc *desc = dev_get_uclass_platdata(dev); 377 378 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 379 if_type, devnum, dev->name, desc->if_type, desc->devnum); 380 if (desc->if_type == if_type && desc->devnum == devnum) { 381 *devp = dev; 382 return device_probe(dev); 383 } 384 } 385 386 return -ENODEV; 387 } 388 389 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, 390 lbaint_t blkcnt, void *buffer) 391 { 392 struct udevice *dev = block_dev->bdev; 393 const struct blk_ops *ops = blk_get_ops(dev); 394 ulong blks_read; 395 396 if (!ops->read) 397 return -ENOSYS; 398 399 if (blkcache_read(block_dev->if_type, block_dev->devnum, 400 start, blkcnt, block_dev->blksz, buffer)) 401 return blkcnt; 402 blks_read = ops->read(dev, start, blkcnt, buffer); 403 if (blks_read == blkcnt) 404 blkcache_fill(block_dev->if_type, block_dev->devnum, 405 start, blkcnt, block_dev->blksz, buffer); 406 407 return blks_read; 408 } 409 410 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start, 411 lbaint_t blkcnt, const void *buffer) 412 { 413 struct udevice *dev = block_dev->bdev; 414 const struct blk_ops *ops = blk_get_ops(dev); 415 416 if (!ops->write) 417 return -ENOSYS; 418 419 blkcache_invalidate(block_dev->if_type, block_dev->devnum); 420 return ops->write(dev, start, blkcnt, buffer); 421 } 422 423 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, 424 lbaint_t blkcnt) 425 { 426 struct udevice *dev = block_dev->bdev; 427 const struct blk_ops *ops = blk_get_ops(dev); 428 429 if (!ops->erase) 430 return -ENOSYS; 431 432 blkcache_invalidate(block_dev->if_type, block_dev->devnum); 433 return ops->erase(dev, start, blkcnt); 434 } 435 436 int blk_prepare_device(struct udevice *dev) 437 { 438 struct blk_desc *desc = dev_get_uclass_platdata(dev); 439 440 part_init(desc); 441 442 return 0; 443 } 444 445 int blk_find_max_devnum(enum if_type if_type) 446 { 447 struct udevice *dev; 448 int max_devnum = -ENODEV; 449 struct uclass *uc; 450 int ret; 451 452 ret = uclass_get(UCLASS_BLK, &uc); 453 if (ret) 454 return ret; 455 uclass_foreach_dev(dev, uc) { 456 struct blk_desc *desc = dev_get_uclass_platdata(dev); 457 458 if (desc->if_type == if_type && desc->devnum > max_devnum) 459 max_devnum = desc->devnum; 460 } 461 462 return max_devnum; 463 } 464 465 int blk_create_device(struct udevice *parent, const char *drv_name, 466 const char *name, int if_type, int devnum, int blksz, 467 lbaint_t size, struct udevice **devp) 468 { 469 struct blk_desc *desc; 470 struct udevice *dev; 471 int ret; 472 473 if (devnum == -1) { 474 ret = blk_find_max_devnum(if_type); 475 if (ret == -ENODEV) 476 devnum = 0; 477 else if (ret < 0) 478 return ret; 479 else 480 devnum = ret + 1; 481 } 482 ret = device_bind_driver(parent, drv_name, name, &dev); 483 if (ret) 484 return ret; 485 desc = dev_get_uclass_platdata(dev); 486 desc->if_type = if_type; 487 desc->blksz = blksz; 488 desc->lba = size / blksz; 489 desc->part_type = PART_TYPE_UNKNOWN; 490 desc->bdev = dev; 491 desc->devnum = devnum; 492 *devp = dev; 493 494 return 0; 495 } 496 497 int blk_create_devicef(struct udevice *parent, const char *drv_name, 498 const char *name, int if_type, int devnum, int blksz, 499 lbaint_t size, struct udevice **devp) 500 { 501 char dev_name[30], *str; 502 int ret; 503 504 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name); 505 str = strdup(dev_name); 506 if (!str) 507 return -ENOMEM; 508 509 ret = blk_create_device(parent, drv_name, str, if_type, devnum, 510 blksz, size, devp); 511 if (ret) { 512 free(str); 513 return ret; 514 } 515 device_set_name_alloced(*devp); 516 517 return ret; 518 } 519 520 int blk_unbind_all(int if_type) 521 { 522 struct uclass *uc; 523 struct udevice *dev, *next; 524 int ret; 525 526 ret = uclass_get(UCLASS_BLK, &uc); 527 if (ret) 528 return ret; 529 uclass_foreach_dev_safe(dev, next, uc) { 530 struct blk_desc *desc = dev_get_uclass_platdata(dev); 531 532 if (desc->if_type == if_type) { 533 ret = device_remove(dev); 534 if (ret) 535 return ret; 536 ret = device_unbind(dev); 537 if (ret) 538 return ret; 539 } 540 } 541 542 return 0; 543 } 544 545 UCLASS_DRIVER(blk) = { 546 .id = UCLASS_BLK, 547 .name = "blk", 548 .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc), 549 }; 550