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