1
2
3
4
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
93
94
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
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
148
149
150
151
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
171
172
173
174
175
176
177
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;
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