blob: a9a85aa37f366ef48b5de590c7c0e20f8d6a7217 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glasscceee552016-02-29 15:25:55 -07002/*
3 * Copyright (C) 2016 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glasscceee552016-02-29 15:25:55 -07005 */
6
Patrick Delaunay81313352021-04-27 11:02:19 +02007#define LOG_CATEGORY UCLASS_BLK
8
Simon Glasscceee552016-02-29 15:25:55 -07009#include <common.h>
10#include <blk.h>
11#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070013#include <malloc.h>
Simon Glass655306c2020-05-10 11:39:58 -060014#include <part.h>
Simon Glasscceee552016-02-29 15:25:55 -070015#include <dm/device-internal.h>
16#include <dm/lists.h>
Stefan Roeseef58a902017-11-29 16:46:42 +010017#include <dm/uclass-internal.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070018#include <linux/err.h>
Simon Glasscceee552016-02-29 15:25:55 -070019
Simon Glass95e6e032022-08-11 19:34:57 -060020static struct {
21 enum uclass_id id;
22 const char *name;
23} if_typename_str[] = {
Simon Glassdbfa32c2022-08-11 19:34:59 -060024 { UCLASS_IDE, "ide" },
25 { UCLASS_SCSI, "scsi" },
26 { UCLASS_USB, "usb" },
27 { UCLASS_MMC, "mmc" },
28 { UCLASS_AHCI, "sata" },
29 { UCLASS_ROOT, "host" },
30 { UCLASS_NVME, "nvme" },
31 { UCLASS_EFI_MEDIA, "efi" },
32 { UCLASS_EFI_LOADER, "efiloader" },
33 { UCLASS_VIRTIO, "virtio" },
34 { UCLASS_PVBLOCK, "pvblock" },
Simon Glass4131ad52016-05-01 11:36:08 -060035};
36
Simon Glass57b3d2e2022-08-11 19:35:01 -060037static enum uclass_id if_typename_to_iftype(const char *if_typename)
Simon Glass4131ad52016-05-01 11:36:08 -060038{
39 int i;
40
Simon Glass95e6e032022-08-11 19:34:57 -060041 for (i = 0; i < ARRAY_SIZE(if_typename_str); i++) {
42 if (!strcmp(if_typename, if_typename_str[i].name))
43 return if_typename_str[i].id;
Simon Glass4131ad52016-05-01 11:36:08 -060044 }
45
Simon Glassdbfa32c2022-08-11 19:34:59 -060046 return UCLASS_INVALID;
Simon Glass4131ad52016-05-01 11:36:08 -060047}
48
Simon Glass57b3d2e2022-08-11 19:35:01 -060049static enum uclass_id if_type_to_uclass_id(enum uclass_id if_type)
Simon Glass4131ad52016-05-01 11:36:08 -060050{
Simon Glassdbfa32c2022-08-11 19:34:59 -060051 /*
52 * This strange adjustment is used because we use UCLASS_MASS_STORAGE
53 * for USB storage devices, so need to return this as the uclass to
54 * use for USB. In fact USB_UCLASS is for USB controllers, not
55 * peripherals.
56 *
57 * The name of the UCLASS_MASS_STORAGE uclass driver is
58 * "usb_mass_storage", but we want to use "usb" in things like the
59 * 'part list' command and when showing interfaces.
60 *
61 * So for now we have this one-way conversion.
62 *
63 * The fix for this is possibly to:
64 * - rename UCLASS_MASS_STORAGE name to "usb"
65 * - rename UCLASS_USB name to "usb_ctlr"
66 * - use UCLASS_MASS_STORAGE instead of UCLASS_USB in if_typename_str
67 */
68 if (if_type == UCLASS_USB)
69 return UCLASS_MASS_STORAGE;
70
71 return if_type;
Simon Glass4131ad52016-05-01 11:36:08 -060072}
73
Simon Glass57b3d2e2022-08-11 19:35:01 -060074const char *blk_get_if_type_name(enum uclass_id if_type)
Simon Glass85af5a42017-07-29 11:34:53 -060075{
Simon Glass95e6e032022-08-11 19:34:57 -060076 int i;
77
78 for (i = 0; i < ARRAY_SIZE(if_typename_str); i++) {
Simon Glassdbfa32c2022-08-11 19:34:59 -060079 if (if_typename_str[i].id == if_type)
Simon Glass95e6e032022-08-11 19:34:57 -060080 return if_typename_str[i].name;
81 }
82
83 return "(none)";
Simon Glass85af5a42017-07-29 11:34:53 -060084}
85
Simon Glass57b3d2e2022-08-11 19:35:01 -060086struct blk_desc *blk_get_devnum_by_type(enum uclass_id if_type, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -060087{
88 struct blk_desc *desc;
89 struct udevice *dev;
90 int ret;
91
92 ret = blk_get_device(if_type, devnum, &dev);
93 if (ret)
94 return NULL;
Simon Glass71fa5b42020-12-03 16:55:18 -070095 desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -060096
97 return desc;
98}
99
100/*
101 * This function is complicated with driver model. We look up the interface
102 * name in a local table. This gives us an interface type which we can match
103 * against the uclass of the block device's parent.
104 */
105struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
106{
107 enum uclass_id uclass_id;
Simon Glass57b3d2e2022-08-11 19:35:01 -0600108 enum uclass_id type;
Simon Glass4131ad52016-05-01 11:36:08 -0600109 struct udevice *dev;
110 struct uclass *uc;
111 int ret;
112
Simon Glassb00361a2022-08-11 19:34:56 -0600113 type = if_typename_to_iftype(if_typename);
Simon Glassdbfa32c2022-08-11 19:34:59 -0600114 if (type == UCLASS_INVALID) {
Simon Glass4131ad52016-05-01 11:36:08 -0600115 debug("%s: Unknown interface type '%s'\n", __func__,
116 if_typename);
117 return NULL;
118 }
Simon Glassb00361a2022-08-11 19:34:56 -0600119 uclass_id = if_type_to_uclass_id(type);
Simon Glass4131ad52016-05-01 11:36:08 -0600120 if (uclass_id == UCLASS_INVALID) {
121 debug("%s: Unknown uclass for interface type'\n",
Simon Glass95e6e032022-08-11 19:34:57 -0600122 blk_get_if_type_name(type));
Simon Glass4131ad52016-05-01 11:36:08 -0600123 return NULL;
124 }
125
126 ret = uclass_get(UCLASS_BLK, &uc);
127 if (ret)
128 return NULL;
129 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700130 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600131
132 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
Simon Glassb00361a2022-08-11 19:34:56 -0600133 type, devnum, dev->name, desc->if_type, desc->devnum);
Simon Glass4131ad52016-05-01 11:36:08 -0600134 if (desc->devnum != devnum)
135 continue;
136
137 /* Find out the parent device uclass */
138 if (device_get_uclass_id(dev->parent) != uclass_id) {
139 debug("%s: parent uclass %d, this dev %d\n", __func__,
140 device_get_uclass_id(dev->parent), uclass_id);
141 continue;
142 }
143
144 if (device_probe(dev))
145 return NULL;
146
147 debug("%s: Device desc %p\n", __func__, desc);
148 return desc;
149 }
150 debug("%s: No device found\n", __func__);
151
152 return NULL;
153}
154
155/**
Tien Fong Chee10378522018-07-06 16:26:36 +0800156 * blk_get_by_device() - Get the block device descriptor for the given device
157 * @dev: Instance of a storage device
158 *
159 * Return: With block device descriptor on success , NULL if there is no such
160 * block device.
161 */
162struct blk_desc *blk_get_by_device(struct udevice *dev)
163{
Simon Glasscfd72932019-09-25 08:55:56 -0600164 struct udevice *child_dev;
Tien Fong Chee10378522018-07-06 16:26:36 +0800165
Simon Glasscfd72932019-09-25 08:55:56 -0600166 device_foreach_child(child_dev, dev) {
Tien Fong Chee10378522018-07-06 16:26:36 +0800167 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
168 continue;
169
Simon Glass71fa5b42020-12-03 16:55:18 -0700170 return dev_get_uclass_plat(child_dev);
Tien Fong Chee10378522018-07-06 16:26:36 +0800171 }
172
173 debug("%s: No block device found\n", __func__);
174
175 return NULL;
176}
177
178/**
Simon Glass4131ad52016-05-01 11:36:08 -0600179 * get_desc() - Get the block device descriptor for the given device number
180 *
181 * @if_type: Interface type
182 * @devnum: Device number (0 = first)
183 * @descp: Returns block device descriptor on success
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100184 * Return: 0 on success, -ENODEV if there is no such device and no device
Simon Glass4131ad52016-05-01 11:36:08 -0600185 * with a higher device number, -ENOENT if there is no such device but there
186 * is one with a higher number, or other -ve on other error.
187 */
Simon Glass57b3d2e2022-08-11 19:35:01 -0600188static int get_desc(enum uclass_id if_type, int devnum, struct blk_desc **descp)
Simon Glass4131ad52016-05-01 11:36:08 -0600189{
190 bool found_more = false;
191 struct udevice *dev;
192 struct uclass *uc;
193 int ret;
194
195 *descp = NULL;
196 ret = uclass_get(UCLASS_BLK, &uc);
197 if (ret)
198 return ret;
199 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700200 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600201
202 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
203 if_type, devnum, dev->name, desc->if_type, desc->devnum);
204 if (desc->if_type == if_type) {
205 if (desc->devnum == devnum) {
206 ret = device_probe(dev);
207 if (ret)
208 return ret;
209
Michal Simekf438b6b2016-11-16 17:37:42 +0100210 *descp = desc;
211 return 0;
Simon Glass4131ad52016-05-01 11:36:08 -0600212 } else if (desc->devnum > devnum) {
213 found_more = true;
214 }
215 }
216 }
217
218 return found_more ? -ENOENT : -ENODEV;
219}
220
Simon Glass57b3d2e2022-08-11 19:35:01 -0600221int blk_select_hwpart_devnum(enum uclass_id if_type, int devnum, int hwpart)
Simon Glass13c2c292016-05-01 13:52:30 -0600222{
223 struct udevice *dev;
224 int ret;
225
226 ret = blk_get_device(if_type, devnum, &dev);
227 if (ret)
228 return ret;
229
developerf50d8d12019-08-27 15:32:18 +0800230 return blk_select_hwpart(dev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600231}
232
Simon Glass57b3d2e2022-08-11 19:35:01 -0600233int blk_list_part(enum uclass_id if_type)
Simon Glass4131ad52016-05-01 11:36:08 -0600234{
235 struct blk_desc *desc;
236 int devnum, ok;
237 int ret;
238
239 for (ok = 0, devnum = 0;; ++devnum) {
240 ret = get_desc(if_type, devnum, &desc);
241 if (ret == -ENODEV)
242 break;
243 else if (ret)
244 continue;
245 if (desc->part_type != PART_TYPE_UNKNOWN) {
246 ++ok;
247 if (devnum)
248 putc('\n');
249 part_print(desc);
250 }
251 }
252 if (!ok)
253 return -ENODEV;
254
255 return 0;
256}
257
Simon Glass57b3d2e2022-08-11 19:35:01 -0600258int blk_print_part_devnum(enum uclass_id if_type, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600259{
260 struct blk_desc *desc;
261 int ret;
262
263 ret = get_desc(if_type, devnum, &desc);
264 if (ret)
265 return ret;
266 if (desc->type == DEV_TYPE_UNKNOWN)
267 return -ENOENT;
268 part_print(desc);
269
270 return 0;
271}
272
Simon Glass57b3d2e2022-08-11 19:35:01 -0600273void blk_list_devices(enum uclass_id if_type)
Simon Glass4131ad52016-05-01 11:36:08 -0600274{
275 struct blk_desc *desc;
276 int ret;
277 int i;
278
279 for (i = 0;; ++i) {
280 ret = get_desc(if_type, i, &desc);
281 if (ret == -ENODEV)
282 break;
283 else if (ret)
284 continue;
285 if (desc->type == DEV_TYPE_UNKNOWN)
286 continue; /* list only known devices */
287 printf("Device %d: ", i);
288 dev_print(desc);
289 }
290}
291
Simon Glass57b3d2e2022-08-11 19:35:01 -0600292int blk_print_device_num(enum uclass_id if_type, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600293{
294 struct blk_desc *desc;
295 int ret;
296
297 ret = get_desc(if_type, devnum, &desc);
298 if (ret)
299 return ret;
300 printf("\nIDE device %d: ", devnum);
301 dev_print(desc);
302
303 return 0;
304}
305
Simon Glass57b3d2e2022-08-11 19:35:01 -0600306int blk_show_device(enum uclass_id if_type, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600307{
308 struct blk_desc *desc;
309 int ret;
310
311 printf("\nDevice %d: ", devnum);
312 ret = get_desc(if_type, devnum, &desc);
313 if (ret == -ENODEV || ret == -ENOENT) {
314 printf("unknown device\n");
315 return -ENODEV;
316 }
317 if (ret)
318 return ret;
319 dev_print(desc);
320
321 if (desc->type == DEV_TYPE_UNKNOWN)
322 return -ENOENT;
323
324 return 0;
325}
326
Simon Glass57b3d2e2022-08-11 19:35:01 -0600327ulong blk_read_devnum(enum uclass_id if_type, int devnum, lbaint_t start,
Simon Glass4131ad52016-05-01 11:36:08 -0600328 lbaint_t blkcnt, void *buffer)
329{
330 struct blk_desc *desc;
331 ulong n;
332 int ret;
333
334 ret = get_desc(if_type, devnum, &desc);
335 if (ret)
336 return ret;
337 n = blk_dread(desc, start, blkcnt, buffer);
338 if (IS_ERR_VALUE(n))
339 return n;
340
Simon Glass4131ad52016-05-01 11:36:08 -0600341 return n;
342}
343
Simon Glass57b3d2e2022-08-11 19:35:01 -0600344ulong blk_write_devnum(enum uclass_id if_type, int devnum, lbaint_t start,
Simon Glass4131ad52016-05-01 11:36:08 -0600345 lbaint_t blkcnt, const void *buffer)
346{
347 struct blk_desc *desc;
348 int ret;
349
350 ret = get_desc(if_type, devnum, &desc);
351 if (ret)
352 return ret;
353 return blk_dwrite(desc, start, blkcnt, buffer);
354}
355
Simon Glass13c2c292016-05-01 13:52:30 -0600356int blk_select_hwpart(struct udevice *dev, int hwpart)
357{
358 const struct blk_ops *ops = blk_get_ops(dev);
359
360 if (!ops)
361 return -ENOSYS;
362 if (!ops->select_hwpart)
363 return 0;
364
365 return ops->select_hwpart(dev, hwpart);
366}
367
368int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
369{
developerf50d8d12019-08-27 15:32:18 +0800370 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600371}
372
Simon Glasscceee552016-02-29 15:25:55 -0700373int blk_first_device(int if_type, struct udevice **devp)
374{
375 struct blk_desc *desc;
376 int ret;
377
Stefan Roeseef58a902017-11-29 16:46:42 +0100378 ret = uclass_find_first_device(UCLASS_BLK, devp);
Simon Glasscceee552016-02-29 15:25:55 -0700379 if (ret)
380 return ret;
381 if (!*devp)
382 return -ENODEV;
383 do {
Simon Glass71fa5b42020-12-03 16:55:18 -0700384 desc = dev_get_uclass_plat(*devp);
Simon Glasscceee552016-02-29 15:25:55 -0700385 if (desc->if_type == if_type)
386 return 0;
Stefan Roeseef58a902017-11-29 16:46:42 +0100387 ret = uclass_find_next_device(devp);
Simon Glasscceee552016-02-29 15:25:55 -0700388 if (ret)
389 return ret;
390 } while (*devp);
391
392 return -ENODEV;
393}
394
395int blk_next_device(struct udevice **devp)
396{
397 struct blk_desc *desc;
398 int ret, if_type;
399
Simon Glass71fa5b42020-12-03 16:55:18 -0700400 desc = dev_get_uclass_plat(*devp);
Simon Glasscceee552016-02-29 15:25:55 -0700401 if_type = desc->if_type;
402 do {
Stefan Roeseef58a902017-11-29 16:46:42 +0100403 ret = uclass_find_next_device(devp);
Simon Glasscceee552016-02-29 15:25:55 -0700404 if (ret)
405 return ret;
406 if (!*devp)
407 return -ENODEV;
Simon Glass71fa5b42020-12-03 16:55:18 -0700408 desc = dev_get_uclass_plat(*devp);
Simon Glasscceee552016-02-29 15:25:55 -0700409 if (desc->if_type == if_type)
410 return 0;
411 } while (1);
412}
413
Simon Glassd5d4c102017-04-23 20:02:05 -0600414int blk_find_device(int if_type, int devnum, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700415{
416 struct uclass *uc;
417 struct udevice *dev;
418 int ret;
419
420 ret = uclass_get(UCLASS_BLK, &uc);
421 if (ret)
422 return ret;
423 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700424 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700425
426 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
427 if_type, devnum, dev->name, desc->if_type, desc->devnum);
428 if (desc->if_type == if_type && desc->devnum == devnum) {
429 *devp = dev;
Simon Glassd5d4c102017-04-23 20:02:05 -0600430 return 0;
Simon Glasscceee552016-02-29 15:25:55 -0700431 }
432 }
433
434 return -ENODEV;
435}
436
Simon Glassd5d4c102017-04-23 20:02:05 -0600437int blk_get_device(int if_type, int devnum, struct udevice **devp)
438{
439 int ret;
440
441 ret = blk_find_device(if_type, devnum, devp);
442 if (ret)
443 return ret;
444
445 return device_probe(*devp);
446}
447
Simon Glasscceee552016-02-29 15:25:55 -0700448unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
449 lbaint_t blkcnt, void *buffer)
450{
451 struct udevice *dev = block_dev->bdev;
452 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700453 ulong blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700454
455 if (!ops->read)
456 return -ENOSYS;
457
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700458 if (blkcache_read(block_dev->if_type, block_dev->devnum,
459 start, blkcnt, block_dev->blksz, buffer))
460 return blkcnt;
461 blks_read = ops->read(dev, start, blkcnt, buffer);
462 if (blks_read == blkcnt)
463 blkcache_fill(block_dev->if_type, block_dev->devnum,
464 start, blkcnt, block_dev->blksz, buffer);
465
466 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700467}
468
469unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
470 lbaint_t blkcnt, const void *buffer)
471{
472 struct udevice *dev = block_dev->bdev;
473 const struct blk_ops *ops = blk_get_ops(dev);
474
475 if (!ops->write)
476 return -ENOSYS;
477
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700478 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glasscceee552016-02-29 15:25:55 -0700479 return ops->write(dev, start, blkcnt, buffer);
480}
481
482unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
483 lbaint_t blkcnt)
484{
485 struct udevice *dev = block_dev->bdev;
486 const struct blk_ops *ops = blk_get_ops(dev);
487
488 if (!ops->erase)
489 return -ENOSYS;
490
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700491 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glasscceee552016-02-29 15:25:55 -0700492 return ops->erase(dev, start, blkcnt);
493}
494
Simon Glass4f269132017-05-27 11:37:17 -0600495int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
496{
497 struct udevice *dev;
498 enum uclass_id id;
499 int ret;
500
501 device_find_first_child(parent, &dev);
502 if (!dev) {
503 debug("%s: No block device found for parent '%s'\n", __func__,
504 parent->name);
505 return -ENODEV;
506 }
507 id = device_get_uclass_id(dev);
508 if (id != UCLASS_BLK) {
509 debug("%s: Incorrect uclass %s for block device '%s'\n",
510 __func__, uclass_get_name(id), dev->name);
511 return -ENOTBLK;
512 }
513 ret = device_probe(dev);
514 if (ret)
515 return ret;
516 *devp = dev;
517
518 return 0;
519}
520
Simon Glassf3086cf2022-04-24 23:31:03 -0600521const char *blk_get_devtype(struct udevice *dev)
522{
523 struct udevice *parent = dev_get_parent(dev);
524
525 return uclass_get_name(device_get_uclass_id(parent));
526};
527
Simon Glass57b3d2e2022-08-11 19:35:01 -0600528int blk_find_max_devnum(enum uclass_id if_type)
Simon Glassd089ba32016-05-01 11:36:28 -0600529{
530 struct udevice *dev;
531 int max_devnum = -ENODEV;
532 struct uclass *uc;
533 int ret;
534
535 ret = uclass_get(UCLASS_BLK, &uc);
536 if (ret)
537 return ret;
538 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700539 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd089ba32016-05-01 11:36:28 -0600540
541 if (desc->if_type == if_type && desc->devnum > max_devnum)
542 max_devnum = desc->devnum;
543 }
544
545 return max_devnum;
546}
547
Simon Glass57b3d2e2022-08-11 19:35:01 -0600548int blk_next_free_devnum(enum uclass_id if_type)
Simon Glassdbc38612017-04-23 20:02:06 -0600549{
550 int ret;
551
552 ret = blk_find_max_devnum(if_type);
553 if (ret == -ENODEV)
554 return 0;
555 if (ret < 0)
556 return ret;
557
558 return ret + 1;
559}
560
Simon Glassfc7a7442021-07-05 16:32:59 -0600561static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
562{
563 const struct blk_desc *desc = dev_get_uclass_plat(dev);
564 enum blk_flag_t flags;
565
566 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
567
568 return flags & req_flags ? 0 : 1;
569}
570
Simon Glass8e61f932022-02-28 12:08:35 -0700571int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
572{
573 int ret;
574
575 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
576 *devp && !blk_flags_check(*devp, flags);
577 ret = uclass_find_next_device(devp))
578 return 0;
579
580 return -ENODEV;
581}
582
583int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
584{
585 int ret;
586
587 for (ret = uclass_find_next_device(devp);
588 *devp && !blk_flags_check(*devp, flags);
589 ret = uclass_find_next_device(devp))
590 return 0;
591
592 return -ENODEV;
593}
594
Simon Glassfc7a7442021-07-05 16:32:59 -0600595int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
596{
597 int ret;
598
599 for (ret = uclass_first_device_err(UCLASS_BLK, devp);
600 !ret;
601 ret = uclass_next_device_err(devp)) {
602 if (!blk_flags_check(*devp, flags))
603 return 0;
604 }
605
606 return -ENODEV;
607}
608
609int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
610{
611 int ret;
612
613 for (ret = uclass_next_device_err(devp);
614 !ret;
615 ret = uclass_next_device_err(devp)) {
616 if (!blk_flags_check(*devp, flags))
617 return 0;
618 }
619
620 return -ENODEV;
621}
622
623int blk_count_devices(enum blk_flag_t flag)
624{
625 struct udevice *dev;
626 int count = 0;
627
628 blk_foreach_probe(flag, dev)
629 count++;
630
631 return count;
632}
633
Simon Glass57b3d2e2022-08-11 19:35:01 -0600634static int blk_claim_devnum(enum uclass_id if_type, int devnum)
Simon Glasse4fef742017-04-23 20:02:07 -0600635{
636 struct udevice *dev;
637 struct uclass *uc;
638 int ret;
639
640 ret = uclass_get(UCLASS_BLK, &uc);
641 if (ret)
642 return ret;
643 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700644 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse4fef742017-04-23 20:02:07 -0600645
646 if (desc->if_type == if_type && desc->devnum == devnum) {
647 int next = blk_next_free_devnum(if_type);
648
649 if (next < 0)
650 return next;
651 desc->devnum = next;
652 return 0;
653 }
654 }
655
656 return -ENOENT;
657}
658
Simon Glasscceee552016-02-29 15:25:55 -0700659int blk_create_device(struct udevice *parent, const char *drv_name,
660 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200661 lbaint_t lba, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700662{
663 struct blk_desc *desc;
664 struct udevice *dev;
665 int ret;
666
Simon Glassd089ba32016-05-01 11:36:28 -0600667 if (devnum == -1) {
Simon Glasse4fef742017-04-23 20:02:07 -0600668 devnum = blk_next_free_devnum(if_type);
669 } else {
670 ret = blk_claim_devnum(if_type, devnum);
671 if (ret < 0 && ret != -ENOENT)
Simon Glassd089ba32016-05-01 11:36:28 -0600672 return ret;
Simon Glassd089ba32016-05-01 11:36:28 -0600673 }
Simon Glasse4fef742017-04-23 20:02:07 -0600674 if (devnum < 0)
675 return devnum;
Simon Glass77f7fb82016-05-01 13:52:22 -0600676 ret = device_bind_driver(parent, drv_name, name, &dev);
677 if (ret)
678 return ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700679 desc = dev_get_uclass_plat(dev);
Simon Glass77f7fb82016-05-01 13:52:22 -0600680 desc->if_type = if_type;
681 desc->blksz = blksz;
Heinrich Schuchardt09ba4ea2019-10-25 12:15:31 +0200682 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200683 desc->lba = lba;
Simon Glass77f7fb82016-05-01 13:52:22 -0600684 desc->part_type = PART_TYPE_UNKNOWN;
685 desc->bdev = dev;
Simon Glasscceee552016-02-29 15:25:55 -0700686 desc->devnum = devnum;
687 *devp = dev;
688
689 return 0;
690}
691
Simon Glass966b6952016-05-01 11:36:29 -0600692int blk_create_devicef(struct udevice *parent, const char *drv_name,
693 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200694 lbaint_t lba, struct udevice **devp)
Simon Glass966b6952016-05-01 11:36:29 -0600695{
696 char dev_name[30], *str;
Simon Glass39e54922016-05-01 13:52:24 -0600697 int ret;
Simon Glass966b6952016-05-01 11:36:29 -0600698
699 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
700 str = strdup(dev_name);
701 if (!str)
702 return -ENOMEM;
703
Simon Glass39e54922016-05-01 13:52:24 -0600704 ret = blk_create_device(parent, drv_name, str, if_type, devnum,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200705 blksz, lba, devp);
Simon Glass39e54922016-05-01 13:52:24 -0600706 if (ret) {
707 free(str);
708 return ret;
709 }
710 device_set_name_alloced(*devp);
711
Simon Glass44505972017-07-29 11:34:59 -0600712 return 0;
Simon Glass966b6952016-05-01 11:36:29 -0600713}
714
AKASHI Takahiro3e32dbe2021-12-10 15:49:29 +0900715int blk_probe_or_unbind(struct udevice *dev)
716{
717 int ret;
718
719 ret = device_probe(dev);
720 if (ret) {
721 log_debug("probing %s failed\n", dev->name);
722 device_unbind(dev);
723 }
724
725 return ret;
726}
727
Simon Glasscceee552016-02-29 15:25:55 -0700728int blk_unbind_all(int if_type)
729{
730 struct uclass *uc;
731 struct udevice *dev, *next;
732 int ret;
733
734 ret = uclass_get(UCLASS_BLK, &uc);
735 if (ret)
736 return ret;
737 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700738 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700739
740 if (desc->if_type == if_type) {
Stefan Roese80b5bc92017-03-20 12:51:48 +0100741 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glasscceee552016-02-29 15:25:55 -0700742 if (ret)
743 return ret;
744 ret = device_unbind(dev);
745 if (ret)
746 return ret;
747 }
748 }
749
750 return 0;
751}
752
Bin Mengcbc3da82018-10-15 02:21:07 -0700753static int blk_post_probe(struct udevice *dev)
754{
Simon Glassf5ac3032022-08-11 19:34:45 -0600755 if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700756 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700757
Ovidiu Panait76160a02020-07-24 14:12:21 +0300758 part_init(desc);
AKASHI Takahiro358e6c72022-04-19 10:05:10 +0900759
760 if (desc->part_type != PART_TYPE_UNKNOWN &&
761 part_create_block_devices(dev))
762 debug("*** creating partitions failed\n");
Ovidiu Panait76160a02020-07-24 14:12:21 +0300763 }
Bin Mengcbc3da82018-10-15 02:21:07 -0700764
765 return 0;
766}
767
Simon Glasscceee552016-02-29 15:25:55 -0700768UCLASS_DRIVER(blk) = {
769 .id = UCLASS_BLK,
770 .name = "blk",
Bin Mengcbc3da82018-10-15 02:21:07 -0700771 .post_probe = blk_post_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700772 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glasscceee552016-02-29 15:25:55 -0700773};