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 } else if (desc->devnum > devnum) { 160 found_more = true; 161 } 162 } 163 } 164 165 return found_more ? -ENOENT : -ENODEV; 166 } 167 168 int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart) 169 { 170 struct udevice *dev; 171 int ret; 172 173 ret = blk_get_device(if_type, devnum, &dev); 174 if (ret) 175 return ret; 176 177 return blk_select_hwpart(dev, hwpart); 178 } 179 180 int blk_list_part(enum if_type if_type) 181 { 182 struct blk_desc *desc; 183 int devnum, ok; 184 int ret; 185 186 for (ok = 0, devnum = 0;; ++devnum) { 187 ret = get_desc(if_type, devnum, &desc); 188 if (ret == -ENODEV) 189 break; 190 else if (ret) 191 continue; 192 if (desc->part_type != PART_TYPE_UNKNOWN) { 193 ++ok; 194 if (devnum) 195 putc('\n'); 196 part_print(desc); 197 } 198 } 199 if (!ok) 200 return -ENODEV; 201 202 return 0; 203 } 204 205 int blk_print_part_devnum(enum if_type if_type, int devnum) 206 { 207 struct blk_desc *desc; 208 int ret; 209 210 ret = get_desc(if_type, devnum, &desc); 211 if (ret) 212 return ret; 213 if (desc->type == DEV_TYPE_UNKNOWN) 214 return -ENOENT; 215 part_print(desc); 216 217 return 0; 218 } 219 220 void blk_list_devices(enum if_type if_type) 221 { 222 struct blk_desc *desc; 223 int ret; 224 int i; 225 226 for (i = 0;; ++i) { 227 ret = get_desc(if_type, i, &desc); 228 if (ret == -ENODEV) 229 break; 230 else if (ret) 231 continue; 232 if (desc->type == DEV_TYPE_UNKNOWN) 233 continue; /* list only known devices */ 234 printf("Device %d: ", i); 235 dev_print(desc); 236 } 237 } 238 239 int blk_print_device_num(enum if_type if_type, int devnum) 240 { 241 struct blk_desc *desc; 242 int ret; 243 244 ret = get_desc(if_type, devnum, &desc); 245 if (ret) 246 return ret; 247 printf("\nIDE device %d: ", devnum); 248 dev_print(desc); 249 250 return 0; 251 } 252 253 int blk_show_device(enum if_type if_type, int devnum) 254 { 255 struct blk_desc *desc; 256 int ret; 257 258 printf("\nDevice %d: ", devnum); 259 ret = get_desc(if_type, devnum, &desc); 260 if (ret == -ENODEV || ret == -ENOENT) { 261 printf("unknown device\n"); 262 return -ENODEV; 263 } 264 if (ret) 265 return ret; 266 dev_print(desc); 267 268 if (desc->type == DEV_TYPE_UNKNOWN) 269 return -ENOENT; 270 271 return 0; 272 } 273 274 ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start, 275 lbaint_t blkcnt, void *buffer) 276 { 277 struct blk_desc *desc; 278 ulong n; 279 int ret; 280 281 ret = get_desc(if_type, devnum, &desc); 282 if (ret) 283 return ret; 284 n = blk_dread(desc, start, blkcnt, buffer); 285 if (IS_ERR_VALUE(n)) 286 return n; 287 288 /* flush cache after read */ 289 flush_cache((ulong)buffer, blkcnt * desc->blksz); 290 291 return n; 292 } 293 294 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start, 295 lbaint_t blkcnt, const void *buffer) 296 { 297 struct blk_desc *desc; 298 int ret; 299 300 ret = get_desc(if_type, devnum, &desc); 301 if (ret) 302 return ret; 303 return blk_dwrite(desc, start, blkcnt, buffer); 304 } 305 306 int blk_select_hwpart(struct udevice *dev, int hwpart) 307 { 308 const struct blk_ops *ops = blk_get_ops(dev); 309 310 if (!ops) 311 return -ENOSYS; 312 if (!ops->select_hwpart) 313 return 0; 314 315 return ops->select_hwpart(dev, hwpart); 316 } 317 318 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart) 319 { 320 return blk_select_hwpart(desc->bdev, hwpart); 321 } 322 323 int blk_first_device(int if_type, struct udevice **devp) 324 { 325 struct blk_desc *desc; 326 int ret; 327 328 ret = uclass_first_device(UCLASS_BLK, devp); 329 if (ret) 330 return ret; 331 if (!*devp) 332 return -ENODEV; 333 do { 334 desc = dev_get_uclass_platdata(*devp); 335 if (desc->if_type == if_type) 336 return 0; 337 ret = uclass_next_device(devp); 338 if (ret) 339 return ret; 340 } while (*devp); 341 342 return -ENODEV; 343 } 344 345 int blk_next_device(struct udevice **devp) 346 { 347 struct blk_desc *desc; 348 int ret, if_type; 349 350 desc = dev_get_uclass_platdata(*devp); 351 if_type = desc->if_type; 352 do { 353 ret = uclass_next_device(devp); 354 if (ret) 355 return ret; 356 if (!*devp) 357 return -ENODEV; 358 desc = dev_get_uclass_platdata(*devp); 359 if (desc->if_type == if_type) 360 return 0; 361 } while (1); 362 } 363 364 int blk_get_device(int if_type, int devnum, struct udevice **devp) 365 { 366 struct uclass *uc; 367 struct udevice *dev; 368 int ret; 369 370 ret = uclass_get(UCLASS_BLK, &uc); 371 if (ret) 372 return ret; 373 uclass_foreach_dev(dev, uc) { 374 struct blk_desc *desc = dev_get_uclass_platdata(dev); 375 376 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 377 if_type, devnum, dev->name, desc->if_type, desc->devnum); 378 if (desc->if_type == if_type && desc->devnum == devnum) { 379 *devp = dev; 380 return device_probe(dev); 381 } 382 } 383 384 return -ENODEV; 385 } 386 387 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, 388 lbaint_t blkcnt, void *buffer) 389 { 390 struct udevice *dev = block_dev->bdev; 391 const struct blk_ops *ops = blk_get_ops(dev); 392 ulong blks_read; 393 394 if (!ops->read) 395 return -ENOSYS; 396 397 if (blkcache_read(block_dev->if_type, block_dev->devnum, 398 start, blkcnt, block_dev->blksz, buffer)) 399 return blkcnt; 400 blks_read = ops->read(dev, start, blkcnt, buffer); 401 if (blks_read == blkcnt) 402 blkcache_fill(block_dev->if_type, block_dev->devnum, 403 start, blkcnt, block_dev->blksz, buffer); 404 405 return blks_read; 406 } 407 408 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start, 409 lbaint_t blkcnt, const void *buffer) 410 { 411 struct udevice *dev = block_dev->bdev; 412 const struct blk_ops *ops = blk_get_ops(dev); 413 414 if (!ops->write) 415 return -ENOSYS; 416 417 blkcache_invalidate(block_dev->if_type, block_dev->devnum); 418 return ops->write(dev, start, blkcnt, buffer); 419 } 420 421 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, 422 lbaint_t blkcnt) 423 { 424 struct udevice *dev = block_dev->bdev; 425 const struct blk_ops *ops = blk_get_ops(dev); 426 427 if (!ops->erase) 428 return -ENOSYS; 429 430 blkcache_invalidate(block_dev->if_type, block_dev->devnum); 431 return ops->erase(dev, start, blkcnt); 432 } 433 434 int blk_prepare_device(struct udevice *dev) 435 { 436 struct blk_desc *desc = dev_get_uclass_platdata(dev); 437 438 part_init(desc); 439 440 return 0; 441 } 442 443 int blk_find_max_devnum(enum if_type if_type) 444 { 445 struct udevice *dev; 446 int max_devnum = -ENODEV; 447 struct uclass *uc; 448 int ret; 449 450 ret = uclass_get(UCLASS_BLK, &uc); 451 if (ret) 452 return ret; 453 uclass_foreach_dev(dev, uc) { 454 struct blk_desc *desc = dev_get_uclass_platdata(dev); 455 456 if (desc->if_type == if_type && desc->devnum > max_devnum) 457 max_devnum = desc->devnum; 458 } 459 460 return max_devnum; 461 } 462 463 int blk_create_device(struct udevice *parent, const char *drv_name, 464 const char *name, int if_type, int devnum, int blksz, 465 lbaint_t size, struct udevice **devp) 466 { 467 struct blk_desc *desc; 468 struct udevice *dev; 469 int ret; 470 471 if (devnum == -1) { 472 ret = blk_find_max_devnum(if_type); 473 if (ret == -ENODEV) 474 devnum = 0; 475 else if (ret < 0) 476 return ret; 477 else 478 devnum = ret + 1; 479 } 480 ret = device_bind_driver(parent, drv_name, name, &dev); 481 if (ret) 482 return ret; 483 desc = dev_get_uclass_platdata(dev); 484 desc->if_type = if_type; 485 desc->blksz = blksz; 486 desc->lba = size / blksz; 487 desc->part_type = PART_TYPE_UNKNOWN; 488 desc->bdev = dev; 489 desc->devnum = devnum; 490 *devp = dev; 491 492 return 0; 493 } 494 495 int blk_create_devicef(struct udevice *parent, const char *drv_name, 496 const char *name, int if_type, int devnum, int blksz, 497 lbaint_t size, struct udevice **devp) 498 { 499 char dev_name[30], *str; 500 int ret; 501 502 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name); 503 str = strdup(dev_name); 504 if (!str) 505 return -ENOMEM; 506 507 ret = blk_create_device(parent, drv_name, str, if_type, devnum, 508 blksz, size, devp); 509 if (ret) { 510 free(str); 511 return ret; 512 } 513 device_set_name_alloced(*devp); 514 515 return ret; 516 } 517 518 int blk_unbind_all(int if_type) 519 { 520 struct uclass *uc; 521 struct udevice *dev, *next; 522 int ret; 523 524 ret = uclass_get(UCLASS_BLK, &uc); 525 if (ret) 526 return ret; 527 uclass_foreach_dev_safe(dev, next, uc) { 528 struct blk_desc *desc = dev_get_uclass_platdata(dev); 529 530 if (desc->if_type == if_type) { 531 ret = device_remove(dev); 532 if (ret) 533 return ret; 534 ret = device_unbind(dev); 535 if (ret) 536 return ret; 537 } 538 } 539 540 return 0; 541 } 542 543 UCLASS_DRIVER(blk) = { 544 .id = UCLASS_BLK, 545 .name = "blk", 546 .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc), 547 }; 548