blob: 21c5209bb63e647192b794f48249ba42cda1a1e5 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass09d71aa2016-02-29 15:25:55 -07002/*
3 * Copyright (C) 2016 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glass09d71aa2016-02-29 15:25:55 -07005 */
6
Patrick Delaunayb953ec22021-04-27 11:02:19 +02007#define LOG_CATEGORY UCLASS_BLK
8
Simon Glass09d71aa2016-02-29 15:25:55 -07009#include <common.h>
10#include <blk.h>
11#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060012#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070013#include <malloc.h>
Simon Glasse6f6f9e2020-05-10 11:39:58 -060014#include <part.h>
Simon Glass09d71aa2016-02-29 15:25:55 -070015#include <dm/device-internal.h>
16#include <dm/lists.h>
Stefan Roese8a5cbc02017-11-29 16:46:42 +010017#include <dm/uclass-internal.h>
Simon Glass61b29b82020-02-03 07:36:15 -070018#include <linux/err.h>
Simon Glass09d71aa2016-02-29 15:25:55 -070019
Simon Glassd508c822016-05-01 11:36:08 -060020static 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",
Zhikang Zhangffab6942017-08-03 02:30:56 -070030 [IF_TYPE_NVME] = "nvme",
Simon Glass42b7f422021-12-04 08:56:31 -070031 [IF_TYPE_EFI_MEDIA] = "efi",
Simon Glass2abd8d12021-12-04 08:56:30 -070032 [IF_TYPE_EFI_LOADER] = "efiloader",
Tuomas Tynkkynen4ad54ec2018-10-15 02:21:10 -070033 [IF_TYPE_VIRTIO] = "virtio",
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +030034 [IF_TYPE_PVBLOCK] = "pvblock",
Simon Glassd508c822016-05-01 11:36:08 -060035};
36
37static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
Bin Meng68e6f222017-09-10 05:12:51 -070038 [IF_TYPE_IDE] = UCLASS_IDE,
Michal Simeke8a016b2016-09-08 15:06:45 +020039 [IF_TYPE_SCSI] = UCLASS_SCSI,
Simon Glassd508c822016-05-01 11:36:08 -060040 [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,
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010047 [IF_TYPE_NVME] = UCLASS_NVME,
Simon Glass42b7f422021-12-04 08:56:31 -070048 [IF_TYPE_EFI_MEDIA] = UCLASS_EFI_MEDIA,
Simon Glass2abd8d12021-12-04 08:56:30 -070049 [IF_TYPE_EFI_LOADER] = UCLASS_EFI_LOADER,
Tuomas Tynkkynen4ad54ec2018-10-15 02:21:10 -070050 [IF_TYPE_VIRTIO] = UCLASS_VIRTIO,
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +030051 [IF_TYPE_PVBLOCK] = UCLASS_PVBLOCK,
Simon Glassd508c822016-05-01 11:36:08 -060052};
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
Simon Glass6faa4ed2017-07-29 11:34:53 -060072const char *blk_get_if_type_name(enum if_type if_type)
73{
74 return if_typename_str[if_type];
75}
76
Simon Glassd508c822016-05-01 11:36:08 -060077struct 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;
Simon Glasscaa4daa2020-12-03 16:55:18 -070086 desc = dev_get_uclass_plat(dev);
Simon Glassd508c822016-05-01 11:36:08 -060087
88 return desc;
89}
90
91/*
92 * This function is complicated with driver model. We look up the interface
93 * name in a local table. This gives us an interface type which we can match
94 * against the uclass of the block device's parent.
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) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700121 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd508c822016-05-01 11:36:08 -0600122
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 /* Find out the parent device uclass */
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/**
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800147 * blk_get_by_device() - Get the block device descriptor for the given device
148 * @dev: Instance of a storage device
149 *
150 * Return: With block device descriptor on success , NULL if there is no such
151 * block device.
152 */
153struct blk_desc *blk_get_by_device(struct udevice *dev)
154{
Simon Glasse5f73902019-09-25 08:55:56 -0600155 struct udevice *child_dev;
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800156
Simon Glasse5f73902019-09-25 08:55:56 -0600157 device_foreach_child(child_dev, dev) {
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800158 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
159 continue;
160
Simon Glasscaa4daa2020-12-03 16:55:18 -0700161 return dev_get_uclass_plat(child_dev);
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800162 }
163
164 debug("%s: No block device found\n", __func__);
165
166 return NULL;
167}
168
169/**
Simon Glassd508c822016-05-01 11:36:08 -0600170 * get_desc() - Get the block device descriptor for the given device number
171 *
172 * @if_type: Interface type
173 * @devnum: Device number (0 = first)
174 * @descp: Returns block device descriptor on success
Heinrich Schuchardt185f8122022-01-19 18:05:50 +0100175 * Return: 0 on success, -ENODEV if there is no such device and no device
Simon Glassd508c822016-05-01 11:36:08 -0600176 * with a higher device number, -ENOENT if there is no such device but there
177 * is one with a higher number, or other -ve on other error.
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) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700191 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd508c822016-05-01 11:36:08 -0600192
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
Michal Simek4408f6f2016-11-16 17:37:42 +0100201 *descp = desc;
202 return 0;
Simon Glassd508c822016-05-01 11:36:08 -0600203 } else if (desc->devnum > devnum) {
204 found_more = true;
205 }
206 }
207 }
208
209 return found_more ? -ENOENT : -ENODEV;
210}
211
Simon Glasscd0fb552016-05-01 13:52:30 -0600212int 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
Weijie Gao1ce88472019-08-27 15:32:18 +0800221 return blk_select_hwpart(dev, hwpart);
Simon Glasscd0fb552016-05-01 13:52:30 -0600222}
223
Simon Glassd508c822016-05-01 11:36:08 -0600224int 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; /* list only known devices */
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
Simon Glassd508c822016-05-01 11:36:08 -0600332 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
Simon Glasscd0fb552016-05-01 13:52:30 -0600347int 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{
Weijie Gao1ce88472019-08-27 15:32:18 +0800361 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glasscd0fb552016-05-01 13:52:30 -0600362}
363
Simon Glass09d71aa2016-02-29 15:25:55 -0700364int blk_first_device(int if_type, struct udevice **devp)
365{
366 struct blk_desc *desc;
367 int ret;
368
Stefan Roese8a5cbc02017-11-29 16:46:42 +0100369 ret = uclass_find_first_device(UCLASS_BLK, devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700370 if (ret)
371 return ret;
372 if (!*devp)
373 return -ENODEV;
374 do {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700375 desc = dev_get_uclass_plat(*devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700376 if (desc->if_type == if_type)
377 return 0;
Stefan Roese8a5cbc02017-11-29 16:46:42 +0100378 ret = uclass_find_next_device(devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700379 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
Simon Glasscaa4daa2020-12-03 16:55:18 -0700391 desc = dev_get_uclass_plat(*devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700392 if_type = desc->if_type;
393 do {
Stefan Roese8a5cbc02017-11-29 16:46:42 +0100394 ret = uclass_find_next_device(devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700395 if (ret)
396 return ret;
397 if (!*devp)
398 return -ENODEV;
Simon Glasscaa4daa2020-12-03 16:55:18 -0700399 desc = dev_get_uclass_plat(*devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700400 if (desc->if_type == if_type)
401 return 0;
402 } while (1);
403}
404
Simon Glass61392812017-04-23 20:02:05 -0600405int blk_find_device(int if_type, int devnum, struct udevice **devp)
Simon Glass09d71aa2016-02-29 15:25:55 -0700406{
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) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700415 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass09d71aa2016-02-29 15:25:55 -0700416
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;
Simon Glass61392812017-04-23 20:02:05 -0600421 return 0;
Simon Glass09d71aa2016-02-29 15:25:55 -0700422 }
423 }
424
425 return -ENODEV;
426}
427
Simon Glass61392812017-04-23 20:02:05 -0600428int 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
Simon Glass09d71aa2016-02-29 15:25:55 -0700439unsigned 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);
Eric Nelsone40cf342016-03-28 10:05:44 -0700444 ulong blks_read;
Simon Glass09d71aa2016-02-29 15:25:55 -0700445
446 if (!ops->read)
447 return -ENOSYS;
448
Eric Nelsone40cf342016-03-28 10:05:44 -0700449 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;
Simon Glass09d71aa2016-02-29 15:25:55 -0700458}
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
Eric Nelsone40cf342016-03-28 10:05:44 -0700469 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glass09d71aa2016-02-29 15:25:55 -0700470 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
Eric Nelsone40cf342016-03-28 10:05:44 -0700482 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glass09d71aa2016-02-29 15:25:55 -0700483 return ops->erase(dev, start, blkcnt);
484}
485
Simon Glass9f103b92017-05-27 11:37:17 -0600486int 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
Simon Glass87571b72022-04-24 23:31:03 -0600512const char *blk_get_devtype(struct udevice *dev)
513{
514 struct udevice *parent = dev_get_parent(dev);
515
516 return uclass_get_name(device_get_uclass_id(parent));
517};
518
Simon Glass52138fd2016-05-01 11:36:28 -0600519int blk_find_max_devnum(enum if_type if_type)
520{
521 struct udevice *dev;
522 int max_devnum = -ENODEV;
523 struct uclass *uc;
524 int ret;
525
526 ret = uclass_get(UCLASS_BLK, &uc);
527 if (ret)
528 return ret;
529 uclass_foreach_dev(dev, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700530 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass52138fd2016-05-01 11:36:28 -0600531
532 if (desc->if_type == if_type && desc->devnum > max_devnum)
533 max_devnum = desc->devnum;
534 }
535
536 return max_devnum;
537}
538
Bin Mengc879eeb2018-10-15 02:21:09 -0700539int blk_next_free_devnum(enum if_type if_type)
Simon Glasse8abbb52017-04-23 20:02:06 -0600540{
541 int ret;
542
543 ret = blk_find_max_devnum(if_type);
544 if (ret == -ENODEV)
545 return 0;
546 if (ret < 0)
547 return ret;
548
549 return ret + 1;
550}
551
Simon Glass96f37b02021-07-05 16:32:59 -0600552static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
553{
554 const struct blk_desc *desc = dev_get_uclass_plat(dev);
555 enum blk_flag_t flags;
556
557 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
558
559 return flags & req_flags ? 0 : 1;
560}
561
Simon Glass49e86682022-02-28 12:08:35 -0700562int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
563{
564 int ret;
565
566 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
567 *devp && !blk_flags_check(*devp, flags);
568 ret = uclass_find_next_device(devp))
569 return 0;
570
571 return -ENODEV;
572}
573
574int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
575{
576 int ret;
577
578 for (ret = uclass_find_next_device(devp);
579 *devp && !blk_flags_check(*devp, flags);
580 ret = uclass_find_next_device(devp))
581 return 0;
582
583 return -ENODEV;
584}
585
Simon Glass96f37b02021-07-05 16:32:59 -0600586int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
587{
588 int ret;
589
590 for (ret = uclass_first_device_err(UCLASS_BLK, devp);
591 !ret;
592 ret = uclass_next_device_err(devp)) {
593 if (!blk_flags_check(*devp, flags))
594 return 0;
595 }
596
597 return -ENODEV;
598}
599
600int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
601{
602 int ret;
603
604 for (ret = uclass_next_device_err(devp);
605 !ret;
606 ret = uclass_next_device_err(devp)) {
607 if (!blk_flags_check(*devp, flags))
608 return 0;
609 }
610
611 return -ENODEV;
612}
613
614int blk_count_devices(enum blk_flag_t flag)
615{
616 struct udevice *dev;
617 int count = 0;
618
619 blk_foreach_probe(flag, dev)
620 count++;
621
622 return count;
623}
624
Simon Glasse48eeb92017-04-23 20:02:07 -0600625static int blk_claim_devnum(enum if_type if_type, int devnum)
626{
627 struct udevice *dev;
628 struct uclass *uc;
629 int ret;
630
631 ret = uclass_get(UCLASS_BLK, &uc);
632 if (ret)
633 return ret;
634 uclass_foreach_dev(dev, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700635 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse48eeb92017-04-23 20:02:07 -0600636
637 if (desc->if_type == if_type && desc->devnum == devnum) {
638 int next = blk_next_free_devnum(if_type);
639
640 if (next < 0)
641 return next;
642 desc->devnum = next;
643 return 0;
644 }
645 }
646
647 return -ENOENT;
648}
649
Simon Glass09d71aa2016-02-29 15:25:55 -0700650int blk_create_device(struct udevice *parent, const char *drv_name,
651 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200652 lbaint_t lba, struct udevice **devp)
Simon Glass09d71aa2016-02-29 15:25:55 -0700653{
654 struct blk_desc *desc;
655 struct udevice *dev;
656 int ret;
657
Simon Glass52138fd2016-05-01 11:36:28 -0600658 if (devnum == -1) {
Simon Glasse48eeb92017-04-23 20:02:07 -0600659 devnum = blk_next_free_devnum(if_type);
660 } else {
661 ret = blk_claim_devnum(if_type, devnum);
662 if (ret < 0 && ret != -ENOENT)
Simon Glass52138fd2016-05-01 11:36:28 -0600663 return ret;
Simon Glass52138fd2016-05-01 11:36:28 -0600664 }
Simon Glasse48eeb92017-04-23 20:02:07 -0600665 if (devnum < 0)
666 return devnum;
Simon Glass72a85c02016-05-01 13:52:22 -0600667 ret = device_bind_driver(parent, drv_name, name, &dev);
668 if (ret)
669 return ret;
Simon Glasscaa4daa2020-12-03 16:55:18 -0700670 desc = dev_get_uclass_plat(dev);
Simon Glass72a85c02016-05-01 13:52:22 -0600671 desc->if_type = if_type;
672 desc->blksz = blksz;
Heinrich Schuchardtee504142019-10-25 12:15:31 +0200673 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200674 desc->lba = lba;
Simon Glass72a85c02016-05-01 13:52:22 -0600675 desc->part_type = PART_TYPE_UNKNOWN;
676 desc->bdev = dev;
Simon Glass09d71aa2016-02-29 15:25:55 -0700677 desc->devnum = devnum;
678 *devp = dev;
679
680 return 0;
681}
682
Simon Glass9107c972016-05-01 11:36:29 -0600683int blk_create_devicef(struct udevice *parent, const char *drv_name,
684 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200685 lbaint_t lba, struct udevice **devp)
Simon Glass9107c972016-05-01 11:36:29 -0600686{
687 char dev_name[30], *str;
Simon Glassd0773522016-05-01 13:52:24 -0600688 int ret;
Simon Glass9107c972016-05-01 11:36:29 -0600689
690 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
691 str = strdup(dev_name);
692 if (!str)
693 return -ENOMEM;
694
Simon Glassd0773522016-05-01 13:52:24 -0600695 ret = blk_create_device(parent, drv_name, str, if_type, devnum,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200696 blksz, lba, devp);
Simon Glassd0773522016-05-01 13:52:24 -0600697 if (ret) {
698 free(str);
699 return ret;
700 }
701 device_set_name_alloced(*devp);
702
Simon Glass7074b2a2017-07-29 11:34:59 -0600703 return 0;
Simon Glass9107c972016-05-01 11:36:29 -0600704}
705
AKASHI Takahiro19b241c2021-12-10 15:49:29 +0900706int blk_probe_or_unbind(struct udevice *dev)
707{
708 int ret;
709
710 ret = device_probe(dev);
711 if (ret) {
712 log_debug("probing %s failed\n", dev->name);
713 device_unbind(dev);
714 }
715
716 return ret;
717}
718
Simon Glass09d71aa2016-02-29 15:25:55 -0700719int blk_unbind_all(int if_type)
720{
721 struct uclass *uc;
722 struct udevice *dev, *next;
723 int ret;
724
725 ret = uclass_get(UCLASS_BLK, &uc);
726 if (ret)
727 return ret;
728 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700729 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass09d71aa2016-02-29 15:25:55 -0700730
731 if (desc->if_type == if_type) {
Stefan Roese706865a2017-03-20 12:51:48 +0100732 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glass09d71aa2016-02-29 15:25:55 -0700733 if (ret)
734 return ret;
735 ret = device_unbind(dev);
736 if (ret)
737 return ret;
738 }
739 }
740
741 return 0;
742}
743
Bin Mengd0851c82018-10-15 02:21:07 -0700744static int blk_post_probe(struct udevice *dev)
745{
Simon Glass88ca8e22022-03-11 12:10:01 -0700746 if (CONFIG_IS_ENABLED(PARTITIONS) &&
Ovidiu Panait3a4b52a2020-07-24 14:12:21 +0300747 IS_ENABLED(CONFIG_HAVE_BLOCK_DEVICE)) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700748 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengd0851c82018-10-15 02:21:07 -0700749
Ovidiu Panait3a4b52a2020-07-24 14:12:21 +0300750 part_init(desc);
AKASHI Takahirobf760312022-04-19 10:05:10 +0900751
752 if (desc->part_type != PART_TYPE_UNKNOWN &&
753 part_create_block_devices(dev))
754 debug("*** creating partitions failed\n");
Ovidiu Panait3a4b52a2020-07-24 14:12:21 +0300755 }
Bin Mengd0851c82018-10-15 02:21:07 -0700756
757 return 0;
758}
759
Simon Glass09d71aa2016-02-29 15:25:55 -0700760UCLASS_DRIVER(blk) = {
761 .id = UCLASS_BLK,
762 .name = "blk",
Bin Mengd0851c82018-10-15 02:21:07 -0700763 .post_probe = blk_post_probe,
Simon Glasscaa4daa2020-12-03 16:55:18 -0700764 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glass09d71aa2016-02-29 15:25:55 -0700765};