blob: a68158c3f2548949c2a1c967fa3da40d52e4c3d0 [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 Glassbb2c9a32022-08-11 19:34:57 -060020static struct {
21 enum uclass_id id;
22 const char *name;
23} if_typename_str[] = {
24 { IF_TYPE_IDE, "ide" },
25 { IF_TYPE_SCSI, "scsi" },
26 { IF_TYPE_USB, "usb" },
27 { IF_TYPE_MMC, "mmc" },
28 { IF_TYPE_SCSI, "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" },
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_USB] = UCLASS_MASS_STORAGE,
Simon Glassd508c822016-05-01 11:36:08 -060041 [IF_TYPE_MMC] = UCLASS_MMC,
Simon Glassd508c822016-05-01 11:36:08 -060042 [IF_TYPE_SATA] = UCLASS_AHCI,
43 [IF_TYPE_HOST] = UCLASS_ROOT,
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010044 [IF_TYPE_NVME] = UCLASS_NVME,
Simon Glass42b7f422021-12-04 08:56:31 -070045 [IF_TYPE_EFI_MEDIA] = UCLASS_EFI_MEDIA,
Simon Glass2abd8d12021-12-04 08:56:30 -070046 [IF_TYPE_EFI_LOADER] = UCLASS_EFI_LOADER,
Tuomas Tynkkynen4ad54ec2018-10-15 02:21:10 -070047 [IF_TYPE_VIRTIO] = UCLASS_VIRTIO,
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +030048 [IF_TYPE_PVBLOCK] = UCLASS_PVBLOCK,
Simon Glassd508c822016-05-01 11:36:08 -060049};
50
51static enum if_type if_typename_to_iftype(const char *if_typename)
52{
53 int i;
54
Simon Glassbb2c9a32022-08-11 19:34:57 -060055 for (i = 0; i < ARRAY_SIZE(if_typename_str); i++) {
56 if (!strcmp(if_typename, if_typename_str[i].name))
57 return if_typename_str[i].id;
Simon Glassd508c822016-05-01 11:36:08 -060058 }
59
60 return IF_TYPE_UNKNOWN;
61}
62
63static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
64{
65 return if_type_uclass_id[if_type];
66}
67
Simon Glass6faa4ed2017-07-29 11:34:53 -060068const char *blk_get_if_type_name(enum if_type if_type)
69{
Simon Glassbb2c9a32022-08-11 19:34:57 -060070 int i;
71
72 for (i = 0; i < ARRAY_SIZE(if_typename_str); i++) {
73 if ((int)if_typename_str[i].id == if_type)
74 return if_typename_str[i].name;
75 }
76
77 return "(none)";
Simon Glass6faa4ed2017-07-29 11:34:53 -060078}
79
Simon Glassd508c822016-05-01 11:36:08 -060080struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
81{
82 struct blk_desc *desc;
83 struct udevice *dev;
84 int ret;
85
86 ret = blk_get_device(if_type, devnum, &dev);
87 if (ret)
88 return NULL;
Simon Glasscaa4daa2020-12-03 16:55:18 -070089 desc = dev_get_uclass_plat(dev);
Simon Glassd508c822016-05-01 11:36:08 -060090
91 return desc;
92}
93
94/*
95 * This function is complicated with driver model. We look up the interface
96 * name in a local table. This gives us an interface type which we can match
97 * against the uclass of the block device's parent.
98 */
99struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
100{
101 enum uclass_id uclass_id;
Simon Glassb8f8f6c2022-08-11 19:34:56 -0600102 enum if_type type;
Simon Glassd508c822016-05-01 11:36:08 -0600103 struct udevice *dev;
104 struct uclass *uc;
105 int ret;
106
Simon Glassb8f8f6c2022-08-11 19:34:56 -0600107 type = if_typename_to_iftype(if_typename);
108 if (type == IF_TYPE_UNKNOWN) {
Simon Glassd508c822016-05-01 11:36:08 -0600109 debug("%s: Unknown interface type '%s'\n", __func__,
110 if_typename);
111 return NULL;
112 }
Simon Glassb8f8f6c2022-08-11 19:34:56 -0600113 uclass_id = if_type_to_uclass_id(type);
Simon Glassd508c822016-05-01 11:36:08 -0600114 if (uclass_id == UCLASS_INVALID) {
115 debug("%s: Unknown uclass for interface type'\n",
Simon Glassbb2c9a32022-08-11 19:34:57 -0600116 blk_get_if_type_name(type));
Simon Glassd508c822016-05-01 11:36:08 -0600117 return NULL;
118 }
119
120 ret = uclass_get(UCLASS_BLK, &uc);
121 if (ret)
122 return NULL;
123 uclass_foreach_dev(dev, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700124 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd508c822016-05-01 11:36:08 -0600125
126 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
Simon Glassb8f8f6c2022-08-11 19:34:56 -0600127 type, devnum, dev->name, desc->if_type, desc->devnum);
Simon Glassd508c822016-05-01 11:36:08 -0600128 if (desc->devnum != devnum)
129 continue;
130
131 /* Find out the parent device uclass */
132 if (device_get_uclass_id(dev->parent) != uclass_id) {
133 debug("%s: parent uclass %d, this dev %d\n", __func__,
134 device_get_uclass_id(dev->parent), uclass_id);
135 continue;
136 }
137
138 if (device_probe(dev))
139 return NULL;
140
141 debug("%s: Device desc %p\n", __func__, desc);
142 return desc;
143 }
144 debug("%s: No device found\n", __func__);
145
146 return NULL;
147}
148
149/**
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800150 * blk_get_by_device() - Get the block device descriptor for the given device
151 * @dev: Instance of a storage device
152 *
153 * Return: With block device descriptor on success , NULL if there is no such
154 * block device.
155 */
156struct blk_desc *blk_get_by_device(struct udevice *dev)
157{
Simon Glasse5f73902019-09-25 08:55:56 -0600158 struct udevice *child_dev;
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800159
Simon Glasse5f73902019-09-25 08:55:56 -0600160 device_foreach_child(child_dev, dev) {
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800161 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
162 continue;
163
Simon Glasscaa4daa2020-12-03 16:55:18 -0700164 return dev_get_uclass_plat(child_dev);
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800165 }
166
167 debug("%s: No block device found\n", __func__);
168
169 return NULL;
170}
171
172/**
Simon Glassd508c822016-05-01 11:36:08 -0600173 * get_desc() - Get the block device descriptor for the given device number
174 *
175 * @if_type: Interface type
176 * @devnum: Device number (0 = first)
177 * @descp: Returns block device descriptor on success
Heinrich Schuchardt185f8122022-01-19 18:05:50 +0100178 * Return: 0 on success, -ENODEV if there is no such device and no device
Simon Glassd508c822016-05-01 11:36:08 -0600179 * with a higher device number, -ENOENT if there is no such device but there
180 * is one with a higher number, or other -ve on other error.
181 */
182static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
183{
184 bool found_more = false;
185 struct udevice *dev;
186 struct uclass *uc;
187 int ret;
188
189 *descp = NULL;
190 ret = uclass_get(UCLASS_BLK, &uc);
191 if (ret)
192 return ret;
193 uclass_foreach_dev(dev, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700194 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd508c822016-05-01 11:36:08 -0600195
196 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
197 if_type, devnum, dev->name, desc->if_type, desc->devnum);
198 if (desc->if_type == if_type) {
199 if (desc->devnum == devnum) {
200 ret = device_probe(dev);
201 if (ret)
202 return ret;
203
Michal Simek4408f6f2016-11-16 17:37:42 +0100204 *descp = desc;
205 return 0;
Simon Glassd508c822016-05-01 11:36:08 -0600206 } else if (desc->devnum > devnum) {
207 found_more = true;
208 }
209 }
210 }
211
212 return found_more ? -ENOENT : -ENODEV;
213}
214
Simon Glasscd0fb552016-05-01 13:52:30 -0600215int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
216{
217 struct udevice *dev;
218 int ret;
219
220 ret = blk_get_device(if_type, devnum, &dev);
221 if (ret)
222 return ret;
223
Weijie Gao1ce88472019-08-27 15:32:18 +0800224 return blk_select_hwpart(dev, hwpart);
Simon Glasscd0fb552016-05-01 13:52:30 -0600225}
226
Simon Glassd508c822016-05-01 11:36:08 -0600227int blk_list_part(enum if_type if_type)
228{
229 struct blk_desc *desc;
230 int devnum, ok;
231 int ret;
232
233 for (ok = 0, devnum = 0;; ++devnum) {
234 ret = get_desc(if_type, devnum, &desc);
235 if (ret == -ENODEV)
236 break;
237 else if (ret)
238 continue;
239 if (desc->part_type != PART_TYPE_UNKNOWN) {
240 ++ok;
241 if (devnum)
242 putc('\n');
243 part_print(desc);
244 }
245 }
246 if (!ok)
247 return -ENODEV;
248
249 return 0;
250}
251
252int blk_print_part_devnum(enum if_type if_type, int devnum)
253{
254 struct blk_desc *desc;
255 int ret;
256
257 ret = get_desc(if_type, devnum, &desc);
258 if (ret)
259 return ret;
260 if (desc->type == DEV_TYPE_UNKNOWN)
261 return -ENOENT;
262 part_print(desc);
263
264 return 0;
265}
266
267void blk_list_devices(enum if_type if_type)
268{
269 struct blk_desc *desc;
270 int ret;
271 int i;
272
273 for (i = 0;; ++i) {
274 ret = get_desc(if_type, i, &desc);
275 if (ret == -ENODEV)
276 break;
277 else if (ret)
278 continue;
279 if (desc->type == DEV_TYPE_UNKNOWN)
280 continue; /* list only known devices */
281 printf("Device %d: ", i);
282 dev_print(desc);
283 }
284}
285
286int blk_print_device_num(enum if_type if_type, int devnum)
287{
288 struct blk_desc *desc;
289 int ret;
290
291 ret = get_desc(if_type, devnum, &desc);
292 if (ret)
293 return ret;
294 printf("\nIDE device %d: ", devnum);
295 dev_print(desc);
296
297 return 0;
298}
299
300int blk_show_device(enum if_type if_type, int devnum)
301{
302 struct blk_desc *desc;
303 int ret;
304
305 printf("\nDevice %d: ", devnum);
306 ret = get_desc(if_type, devnum, &desc);
307 if (ret == -ENODEV || ret == -ENOENT) {
308 printf("unknown device\n");
309 return -ENODEV;
310 }
311 if (ret)
312 return ret;
313 dev_print(desc);
314
315 if (desc->type == DEV_TYPE_UNKNOWN)
316 return -ENOENT;
317
318 return 0;
319}
320
321ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
322 lbaint_t blkcnt, void *buffer)
323{
324 struct blk_desc *desc;
325 ulong n;
326 int ret;
327
328 ret = get_desc(if_type, devnum, &desc);
329 if (ret)
330 return ret;
331 n = blk_dread(desc, start, blkcnt, buffer);
332 if (IS_ERR_VALUE(n))
333 return n;
334
Simon Glassd508c822016-05-01 11:36:08 -0600335 return n;
336}
337
338ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
339 lbaint_t blkcnt, const void *buffer)
340{
341 struct blk_desc *desc;
342 int ret;
343
344 ret = get_desc(if_type, devnum, &desc);
345 if (ret)
346 return ret;
347 return blk_dwrite(desc, start, blkcnt, buffer);
348}
349
Simon Glasscd0fb552016-05-01 13:52:30 -0600350int blk_select_hwpart(struct udevice *dev, int hwpart)
351{
352 const struct blk_ops *ops = blk_get_ops(dev);
353
354 if (!ops)
355 return -ENOSYS;
356 if (!ops->select_hwpart)
357 return 0;
358
359 return ops->select_hwpart(dev, hwpart);
360}
361
362int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
363{
Weijie Gao1ce88472019-08-27 15:32:18 +0800364 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glasscd0fb552016-05-01 13:52:30 -0600365}
366
Simon Glass09d71aa2016-02-29 15:25:55 -0700367int blk_first_device(int if_type, struct udevice **devp)
368{
369 struct blk_desc *desc;
370 int ret;
371
Stefan Roese8a5cbc02017-11-29 16:46:42 +0100372 ret = uclass_find_first_device(UCLASS_BLK, devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700373 if (ret)
374 return ret;
375 if (!*devp)
376 return -ENODEV;
377 do {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700378 desc = dev_get_uclass_plat(*devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700379 if (desc->if_type == if_type)
380 return 0;
Stefan Roese8a5cbc02017-11-29 16:46:42 +0100381 ret = uclass_find_next_device(devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700382 if (ret)
383 return ret;
384 } while (*devp);
385
386 return -ENODEV;
387}
388
389int blk_next_device(struct udevice **devp)
390{
391 struct blk_desc *desc;
392 int ret, if_type;
393
Simon Glasscaa4daa2020-12-03 16:55:18 -0700394 desc = dev_get_uclass_plat(*devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700395 if_type = desc->if_type;
396 do {
Stefan Roese8a5cbc02017-11-29 16:46:42 +0100397 ret = uclass_find_next_device(devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700398 if (ret)
399 return ret;
400 if (!*devp)
401 return -ENODEV;
Simon Glasscaa4daa2020-12-03 16:55:18 -0700402 desc = dev_get_uclass_plat(*devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700403 if (desc->if_type == if_type)
404 return 0;
405 } while (1);
406}
407
Simon Glass61392812017-04-23 20:02:05 -0600408int blk_find_device(int if_type, int devnum, struct udevice **devp)
Simon Glass09d71aa2016-02-29 15:25:55 -0700409{
410 struct uclass *uc;
411 struct udevice *dev;
412 int ret;
413
414 ret = uclass_get(UCLASS_BLK, &uc);
415 if (ret)
416 return ret;
417 uclass_foreach_dev(dev, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700418 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass09d71aa2016-02-29 15:25:55 -0700419
420 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
421 if_type, devnum, dev->name, desc->if_type, desc->devnum);
422 if (desc->if_type == if_type && desc->devnum == devnum) {
423 *devp = dev;
Simon Glass61392812017-04-23 20:02:05 -0600424 return 0;
Simon Glass09d71aa2016-02-29 15:25:55 -0700425 }
426 }
427
428 return -ENODEV;
429}
430
Simon Glass61392812017-04-23 20:02:05 -0600431int blk_get_device(int if_type, int devnum, struct udevice **devp)
432{
433 int ret;
434
435 ret = blk_find_device(if_type, devnum, devp);
436 if (ret)
437 return ret;
438
439 return device_probe(*devp);
440}
441
Simon Glass09d71aa2016-02-29 15:25:55 -0700442unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
443 lbaint_t blkcnt, void *buffer)
444{
445 struct udevice *dev = block_dev->bdev;
446 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsone40cf342016-03-28 10:05:44 -0700447 ulong blks_read;
Simon Glass09d71aa2016-02-29 15:25:55 -0700448
449 if (!ops->read)
450 return -ENOSYS;
451
Eric Nelsone40cf342016-03-28 10:05:44 -0700452 if (blkcache_read(block_dev->if_type, block_dev->devnum,
453 start, blkcnt, block_dev->blksz, buffer))
454 return blkcnt;
455 blks_read = ops->read(dev, start, blkcnt, buffer);
456 if (blks_read == blkcnt)
457 blkcache_fill(block_dev->if_type, block_dev->devnum,
458 start, blkcnt, block_dev->blksz, buffer);
459
460 return blks_read;
Simon Glass09d71aa2016-02-29 15:25:55 -0700461}
462
463unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
464 lbaint_t blkcnt, const void *buffer)
465{
466 struct udevice *dev = block_dev->bdev;
467 const struct blk_ops *ops = blk_get_ops(dev);
468
469 if (!ops->write)
470 return -ENOSYS;
471
Eric Nelsone40cf342016-03-28 10:05:44 -0700472 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glass09d71aa2016-02-29 15:25:55 -0700473 return ops->write(dev, start, blkcnt, buffer);
474}
475
476unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
477 lbaint_t blkcnt)
478{
479 struct udevice *dev = block_dev->bdev;
480 const struct blk_ops *ops = blk_get_ops(dev);
481
482 if (!ops->erase)
483 return -ENOSYS;
484
Eric Nelsone40cf342016-03-28 10:05:44 -0700485 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glass09d71aa2016-02-29 15:25:55 -0700486 return ops->erase(dev, start, blkcnt);
487}
488
Simon Glass9f103b92017-05-27 11:37:17 -0600489int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
490{
491 struct udevice *dev;
492 enum uclass_id id;
493 int ret;
494
495 device_find_first_child(parent, &dev);
496 if (!dev) {
497 debug("%s: No block device found for parent '%s'\n", __func__,
498 parent->name);
499 return -ENODEV;
500 }
501 id = device_get_uclass_id(dev);
502 if (id != UCLASS_BLK) {
503 debug("%s: Incorrect uclass %s for block device '%s'\n",
504 __func__, uclass_get_name(id), dev->name);
505 return -ENOTBLK;
506 }
507 ret = device_probe(dev);
508 if (ret)
509 return ret;
510 *devp = dev;
511
512 return 0;
513}
514
Simon Glass87571b72022-04-24 23:31:03 -0600515const char *blk_get_devtype(struct udevice *dev)
516{
517 struct udevice *parent = dev_get_parent(dev);
518
519 return uclass_get_name(device_get_uclass_id(parent));
520};
521
Simon Glass52138fd2016-05-01 11:36:28 -0600522int blk_find_max_devnum(enum if_type if_type)
523{
524 struct udevice *dev;
525 int max_devnum = -ENODEV;
526 struct uclass *uc;
527 int ret;
528
529 ret = uclass_get(UCLASS_BLK, &uc);
530 if (ret)
531 return ret;
532 uclass_foreach_dev(dev, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700533 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass52138fd2016-05-01 11:36:28 -0600534
535 if (desc->if_type == if_type && desc->devnum > max_devnum)
536 max_devnum = desc->devnum;
537 }
538
539 return max_devnum;
540}
541
Bin Mengc879eeb2018-10-15 02:21:09 -0700542int blk_next_free_devnum(enum if_type if_type)
Simon Glasse8abbb52017-04-23 20:02:06 -0600543{
544 int ret;
545
546 ret = blk_find_max_devnum(if_type);
547 if (ret == -ENODEV)
548 return 0;
549 if (ret < 0)
550 return ret;
551
552 return ret + 1;
553}
554
Simon Glass96f37b02021-07-05 16:32:59 -0600555static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
556{
557 const struct blk_desc *desc = dev_get_uclass_plat(dev);
558 enum blk_flag_t flags;
559
560 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
561
562 return flags & req_flags ? 0 : 1;
563}
564
Simon Glass49e86682022-02-28 12:08:35 -0700565int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
566{
567 int ret;
568
569 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
570 *devp && !blk_flags_check(*devp, flags);
571 ret = uclass_find_next_device(devp))
572 return 0;
573
574 return -ENODEV;
575}
576
577int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
578{
579 int ret;
580
581 for (ret = uclass_find_next_device(devp);
582 *devp && !blk_flags_check(*devp, flags);
583 ret = uclass_find_next_device(devp))
584 return 0;
585
586 return -ENODEV;
587}
588
Simon Glass96f37b02021-07-05 16:32:59 -0600589int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
590{
591 int ret;
592
593 for (ret = uclass_first_device_err(UCLASS_BLK, devp);
594 !ret;
595 ret = uclass_next_device_err(devp)) {
596 if (!blk_flags_check(*devp, flags))
597 return 0;
598 }
599
600 return -ENODEV;
601}
602
603int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
604{
605 int ret;
606
607 for (ret = uclass_next_device_err(devp);
608 !ret;
609 ret = uclass_next_device_err(devp)) {
610 if (!blk_flags_check(*devp, flags))
611 return 0;
612 }
613
614 return -ENODEV;
615}
616
617int blk_count_devices(enum blk_flag_t flag)
618{
619 struct udevice *dev;
620 int count = 0;
621
622 blk_foreach_probe(flag, dev)
623 count++;
624
625 return count;
626}
627
Simon Glasse48eeb92017-04-23 20:02:07 -0600628static int blk_claim_devnum(enum if_type if_type, int devnum)
629{
630 struct udevice *dev;
631 struct uclass *uc;
632 int ret;
633
634 ret = uclass_get(UCLASS_BLK, &uc);
635 if (ret)
636 return ret;
637 uclass_foreach_dev(dev, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700638 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse48eeb92017-04-23 20:02:07 -0600639
640 if (desc->if_type == if_type && desc->devnum == devnum) {
641 int next = blk_next_free_devnum(if_type);
642
643 if (next < 0)
644 return next;
645 desc->devnum = next;
646 return 0;
647 }
648 }
649
650 return -ENOENT;
651}
652
Simon Glass09d71aa2016-02-29 15:25:55 -0700653int blk_create_device(struct udevice *parent, const char *drv_name,
654 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200655 lbaint_t lba, struct udevice **devp)
Simon Glass09d71aa2016-02-29 15:25:55 -0700656{
657 struct blk_desc *desc;
658 struct udevice *dev;
659 int ret;
660
Simon Glass52138fd2016-05-01 11:36:28 -0600661 if (devnum == -1) {
Simon Glasse48eeb92017-04-23 20:02:07 -0600662 devnum = blk_next_free_devnum(if_type);
663 } else {
664 ret = blk_claim_devnum(if_type, devnum);
665 if (ret < 0 && ret != -ENOENT)
Simon Glass52138fd2016-05-01 11:36:28 -0600666 return ret;
Simon Glass52138fd2016-05-01 11:36:28 -0600667 }
Simon Glasse48eeb92017-04-23 20:02:07 -0600668 if (devnum < 0)
669 return devnum;
Simon Glass72a85c02016-05-01 13:52:22 -0600670 ret = device_bind_driver(parent, drv_name, name, &dev);
671 if (ret)
672 return ret;
Simon Glasscaa4daa2020-12-03 16:55:18 -0700673 desc = dev_get_uclass_plat(dev);
Simon Glass72a85c02016-05-01 13:52:22 -0600674 desc->if_type = if_type;
675 desc->blksz = blksz;
Heinrich Schuchardtee504142019-10-25 12:15:31 +0200676 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200677 desc->lba = lba;
Simon Glass72a85c02016-05-01 13:52:22 -0600678 desc->part_type = PART_TYPE_UNKNOWN;
679 desc->bdev = dev;
Simon Glass09d71aa2016-02-29 15:25:55 -0700680 desc->devnum = devnum;
681 *devp = dev;
682
683 return 0;
684}
685
Simon Glass9107c972016-05-01 11:36:29 -0600686int blk_create_devicef(struct udevice *parent, const char *drv_name,
687 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200688 lbaint_t lba, struct udevice **devp)
Simon Glass9107c972016-05-01 11:36:29 -0600689{
690 char dev_name[30], *str;
Simon Glassd0773522016-05-01 13:52:24 -0600691 int ret;
Simon Glass9107c972016-05-01 11:36:29 -0600692
693 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
694 str = strdup(dev_name);
695 if (!str)
696 return -ENOMEM;
697
Simon Glassd0773522016-05-01 13:52:24 -0600698 ret = blk_create_device(parent, drv_name, str, if_type, devnum,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200699 blksz, lba, devp);
Simon Glassd0773522016-05-01 13:52:24 -0600700 if (ret) {
701 free(str);
702 return ret;
703 }
704 device_set_name_alloced(*devp);
705
Simon Glass7074b2a2017-07-29 11:34:59 -0600706 return 0;
Simon Glass9107c972016-05-01 11:36:29 -0600707}
708
AKASHI Takahiro19b241c2021-12-10 15:49:29 +0900709int blk_probe_or_unbind(struct udevice *dev)
710{
711 int ret;
712
713 ret = device_probe(dev);
714 if (ret) {
715 log_debug("probing %s failed\n", dev->name);
716 device_unbind(dev);
717 }
718
719 return ret;
720}
721
Simon Glass09d71aa2016-02-29 15:25:55 -0700722int blk_unbind_all(int if_type)
723{
724 struct uclass *uc;
725 struct udevice *dev, *next;
726 int ret;
727
728 ret = uclass_get(UCLASS_BLK, &uc);
729 if (ret)
730 return ret;
731 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700732 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass09d71aa2016-02-29 15:25:55 -0700733
734 if (desc->if_type == if_type) {
Stefan Roese706865a2017-03-20 12:51:48 +0100735 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glass09d71aa2016-02-29 15:25:55 -0700736 if (ret)
737 return ret;
738 ret = device_unbind(dev);
739 if (ret)
740 return ret;
741 }
742 }
743
744 return 0;
745}
746
Bin Mengd0851c82018-10-15 02:21:07 -0700747static int blk_post_probe(struct udevice *dev)
748{
Simon Glassa51eb8d2022-08-11 19:34:45 -0600749 if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700750 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengd0851c82018-10-15 02:21:07 -0700751
Ovidiu Panait3a4b52a2020-07-24 14:12:21 +0300752 part_init(desc);
AKASHI Takahirobf760312022-04-19 10:05:10 +0900753
754 if (desc->part_type != PART_TYPE_UNKNOWN &&
755 part_create_block_devices(dev))
756 debug("*** creating partitions failed\n");
Ovidiu Panait3a4b52a2020-07-24 14:12:21 +0300757 }
Bin Mengd0851c82018-10-15 02:21:07 -0700758
759 return 0;
760}
761
Simon Glass09d71aa2016-02-29 15:25:55 -0700762UCLASS_DRIVER(blk) = {
763 .id = UCLASS_BLK,
764 .name = "blk",
Bin Mengd0851c82018-10-15 02:21:07 -0700765 .post_probe = blk_post_probe,
Simon Glasscaa4daa2020-12-03 16:55:18 -0700766 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glass09d71aa2016-02-29 15:25:55 -0700767};