blob: 6aac92d99627dd003c586a975e68f84ddf75f21d [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
Marek Vasutddfa0882023-08-14 01:46:48 +020020#define blk_get_ops(dev) ((struct blk_ops *)(dev)->driver->ops)
21
Simon Glass95e6e032022-08-11 19:34:57 -060022static struct {
23 enum uclass_id id;
24 const char *name;
Simon Glassfada3f92022-09-17 09:00:09 -060025} uclass_idname_str[] = {
Simon Glassdbfa32c2022-08-11 19:34:59 -060026 { UCLASS_IDE, "ide" },
27 { UCLASS_SCSI, "scsi" },
28 { UCLASS_USB, "usb" },
29 { UCLASS_MMC, "mmc" },
30 { UCLASS_AHCI, "sata" },
Simon Glasse57f8d42022-10-29 19:47:17 -060031 { UCLASS_HOST, "host" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060032 { UCLASS_NVME, "nvme" },
Abdellatif El Khlifi857360c2023-04-17 10:11:52 +010033 { UCLASS_NVMXIP, "nvmxip" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060034 { UCLASS_EFI_MEDIA, "efi" },
35 { UCLASS_EFI_LOADER, "efiloader" },
36 { UCLASS_VIRTIO, "virtio" },
37 { UCLASS_PVBLOCK, "pvblock" },
Tobias Waldekranz4f76dd32023-02-16 16:33:49 +010038 { UCLASS_BLKMAP, "blkmap" },
Simon Glass4131ad52016-05-01 11:36:08 -060039};
40
Simon Glassfada3f92022-09-17 09:00:09 -060041static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
Simon Glass4131ad52016-05-01 11:36:08 -060042{
43 int i;
44
Simon Glassfada3f92022-09-17 09:00:09 -060045 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
46 if (!strcmp(uclass_idname, uclass_idname_str[i].name))
47 return uclass_idname_str[i].id;
Simon Glass4131ad52016-05-01 11:36:08 -060048 }
49
Simon Glassdbfa32c2022-08-11 19:34:59 -060050 return UCLASS_INVALID;
Simon Glass4131ad52016-05-01 11:36:08 -060051}
52
Simon Glassfada3f92022-09-17 09:00:09 -060053static enum uclass_id conv_uclass_id(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -060054{
Simon Glassdbfa32c2022-08-11 19:34:59 -060055 /*
56 * This strange adjustment is used because we use UCLASS_MASS_STORAGE
57 * for USB storage devices, so need to return this as the uclass to
58 * use for USB. In fact USB_UCLASS is for USB controllers, not
59 * peripherals.
60 *
61 * The name of the UCLASS_MASS_STORAGE uclass driver is
62 * "usb_mass_storage", but we want to use "usb" in things like the
63 * 'part list' command and when showing interfaces.
64 *
65 * So for now we have this one-way conversion.
66 *
67 * The fix for this is possibly to:
68 * - rename UCLASS_MASS_STORAGE name to "usb"
69 * - rename UCLASS_USB name to "usb_ctlr"
70 * - use UCLASS_MASS_STORAGE instead of UCLASS_USB in if_typename_str
71 */
Simon Glassfada3f92022-09-17 09:00:09 -060072 if (uclass_id == UCLASS_USB)
Simon Glassdbfa32c2022-08-11 19:34:59 -060073 return UCLASS_MASS_STORAGE;
Simon Glassfada3f92022-09-17 09:00:09 -060074 return uclass_id;
Simon Glass4131ad52016-05-01 11:36:08 -060075}
76
Simon Glassfada3f92022-09-17 09:00:09 -060077const char *blk_get_uclass_name(enum uclass_id uclass_id)
Simon Glass85af5a42017-07-29 11:34:53 -060078{
Simon Glass95e6e032022-08-11 19:34:57 -060079 int i;
80
Simon Glassfada3f92022-09-17 09:00:09 -060081 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
82 if (uclass_idname_str[i].id == uclass_id)
83 return uclass_idname_str[i].name;
Simon Glass95e6e032022-08-11 19:34:57 -060084 }
85
86 return "(none)";
Simon Glass85af5a42017-07-29 11:34:53 -060087}
88
Simon Glassfada3f92022-09-17 09:00:09 -060089struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -060090{
91 struct blk_desc *desc;
92 struct udevice *dev;
93 int ret;
94
Simon Glassfada3f92022-09-17 09:00:09 -060095 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass4131ad52016-05-01 11:36:08 -060096 if (ret)
97 return NULL;
Simon Glass71fa5b42020-12-03 16:55:18 -070098 desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -060099
100 return desc;
101}
102
103/*
104 * This function is complicated with driver model. We look up the interface
105 * name in a local table. This gives us an interface type which we can match
106 * against the uclass of the block device's parent.
107 */
Simon Glassfada3f92022-09-17 09:00:09 -0600108struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600109{
110 enum uclass_id uclass_id;
Simon Glass57b3d2e2022-08-11 19:35:01 -0600111 enum uclass_id type;
Simon Glass4131ad52016-05-01 11:36:08 -0600112 struct udevice *dev;
113 struct uclass *uc;
114 int ret;
115
Simon Glassfada3f92022-09-17 09:00:09 -0600116 type = uclass_name_to_iftype(uclass_idname);
Simon Glassdbfa32c2022-08-11 19:34:59 -0600117 if (type == UCLASS_INVALID) {
Simon Glass4131ad52016-05-01 11:36:08 -0600118 debug("%s: Unknown interface type '%s'\n", __func__,
Simon Glassfada3f92022-09-17 09:00:09 -0600119 uclass_idname);
Simon Glass4131ad52016-05-01 11:36:08 -0600120 return NULL;
121 }
Simon Glassfada3f92022-09-17 09:00:09 -0600122 uclass_id = conv_uclass_id(type);
Simon Glass4131ad52016-05-01 11:36:08 -0600123 if (uclass_id == UCLASS_INVALID) {
124 debug("%s: Unknown uclass for interface type'\n",
Simon Glassfada3f92022-09-17 09:00:09 -0600125 blk_get_uclass_name(type));
Simon Glass4131ad52016-05-01 11:36:08 -0600126 return NULL;
127 }
128
129 ret = uclass_get(UCLASS_BLK, &uc);
130 if (ret)
131 return NULL;
132 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700133 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600134
Simon Glassfada3f92022-09-17 09:00:09 -0600135 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
136 type, devnum, dev->name, desc->uclass_id, desc->devnum);
Simon Glass4131ad52016-05-01 11:36:08 -0600137 if (desc->devnum != devnum)
138 continue;
139
140 /* Find out the parent device uclass */
141 if (device_get_uclass_id(dev->parent) != uclass_id) {
142 debug("%s: parent uclass %d, this dev %d\n", __func__,
143 device_get_uclass_id(dev->parent), uclass_id);
144 continue;
145 }
146
147 if (device_probe(dev))
148 return NULL;
149
150 debug("%s: Device desc %p\n", __func__, desc);
151 return desc;
152 }
153 debug("%s: No device found\n", __func__);
154
155 return NULL;
156}
157
158/**
Tien Fong Chee10378522018-07-06 16:26:36 +0800159 * blk_get_by_device() - Get the block device descriptor for the given device
160 * @dev: Instance of a storage device
161 *
162 * Return: With block device descriptor on success , NULL if there is no such
163 * block device.
164 */
165struct blk_desc *blk_get_by_device(struct udevice *dev)
166{
Simon Glasscfd72932019-09-25 08:55:56 -0600167 struct udevice *child_dev;
Tien Fong Chee10378522018-07-06 16:26:36 +0800168
Simon Glasscfd72932019-09-25 08:55:56 -0600169 device_foreach_child(child_dev, dev) {
Tien Fong Chee10378522018-07-06 16:26:36 +0800170 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
171 continue;
172
Simon Glass71fa5b42020-12-03 16:55:18 -0700173 return dev_get_uclass_plat(child_dev);
Tien Fong Chee10378522018-07-06 16:26:36 +0800174 }
175
176 debug("%s: No block device found\n", __func__);
177
178 return NULL;
179}
180
181/**
Simon Glass4131ad52016-05-01 11:36:08 -0600182 * get_desc() - Get the block device descriptor for the given device number
183 *
Simon Glassfada3f92022-09-17 09:00:09 -0600184 * @uclass_id: Interface type
Simon Glass4131ad52016-05-01 11:36:08 -0600185 * @devnum: Device number (0 = first)
186 * @descp: Returns block device descriptor on success
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100187 * Return: 0 on success, -ENODEV if there is no such device and no device
Simon Glass4131ad52016-05-01 11:36:08 -0600188 * with a higher device number, -ENOENT if there is no such device but there
189 * is one with a higher number, or other -ve on other error.
190 */
Simon Glassfada3f92022-09-17 09:00:09 -0600191static int get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
Simon Glass4131ad52016-05-01 11:36:08 -0600192{
193 bool found_more = false;
194 struct udevice *dev;
195 struct uclass *uc;
196 int ret;
197
198 *descp = NULL;
199 ret = uclass_get(UCLASS_BLK, &uc);
200 if (ret)
201 return ret;
202 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700203 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600204
Simon Glassfada3f92022-09-17 09:00:09 -0600205 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
206 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
207 if (desc->uclass_id == uclass_id) {
Simon Glass4131ad52016-05-01 11:36:08 -0600208 if (desc->devnum == devnum) {
209 ret = device_probe(dev);
210 if (ret)
211 return ret;
212
Michal Simekf438b6b2016-11-16 17:37:42 +0100213 *descp = desc;
214 return 0;
Simon Glass4131ad52016-05-01 11:36:08 -0600215 } else if (desc->devnum > devnum) {
216 found_more = true;
217 }
218 }
219 }
220
221 return found_more ? -ENOENT : -ENODEV;
222}
223
Simon Glassfada3f92022-09-17 09:00:09 -0600224int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
Simon Glass13c2c292016-05-01 13:52:30 -0600225{
226 struct udevice *dev;
227 int ret;
228
Simon Glassfada3f92022-09-17 09:00:09 -0600229 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass13c2c292016-05-01 13:52:30 -0600230 if (ret)
231 return ret;
232
developerf50d8d12019-08-27 15:32:18 +0800233 return blk_select_hwpart(dev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600234}
235
Simon Glassfada3f92022-09-17 09:00:09 -0600236int blk_list_part(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600237{
238 struct blk_desc *desc;
239 int devnum, ok;
240 int ret;
241
242 for (ok = 0, devnum = 0;; ++devnum) {
Simon Glassfada3f92022-09-17 09:00:09 -0600243 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600244 if (ret == -ENODEV)
245 break;
246 else if (ret)
247 continue;
248 if (desc->part_type != PART_TYPE_UNKNOWN) {
249 ++ok;
250 if (devnum)
251 putc('\n');
252 part_print(desc);
253 }
254 }
255 if (!ok)
256 return -ENODEV;
257
258 return 0;
259}
260
Simon Glassfada3f92022-09-17 09:00:09 -0600261int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600262{
263 struct blk_desc *desc;
264 int ret;
265
Simon Glassfada3f92022-09-17 09:00:09 -0600266 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600267 if (ret)
268 return ret;
269 if (desc->type == DEV_TYPE_UNKNOWN)
270 return -ENOENT;
271 part_print(desc);
272
273 return 0;
274}
275
Simon Glassfada3f92022-09-17 09:00:09 -0600276void blk_list_devices(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600277{
278 struct blk_desc *desc;
279 int ret;
280 int i;
281
282 for (i = 0;; ++i) {
Simon Glassfada3f92022-09-17 09:00:09 -0600283 ret = get_desc(uclass_id, i, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600284 if (ret == -ENODEV)
285 break;
286 else if (ret)
287 continue;
288 if (desc->type == DEV_TYPE_UNKNOWN)
289 continue; /* list only known devices */
290 printf("Device %d: ", i);
291 dev_print(desc);
292 }
293}
294
Simon Glassfada3f92022-09-17 09:00:09 -0600295int blk_print_device_num(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600296{
297 struct blk_desc *desc;
298 int ret;
299
Simon Glassfada3f92022-09-17 09:00:09 -0600300 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600301 if (ret)
302 return ret;
303 printf("\nIDE device %d: ", devnum);
304 dev_print(desc);
305
306 return 0;
307}
308
Simon Glassfada3f92022-09-17 09:00:09 -0600309int blk_show_device(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600310{
311 struct blk_desc *desc;
312 int ret;
313
314 printf("\nDevice %d: ", devnum);
Simon Glassfada3f92022-09-17 09:00:09 -0600315 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600316 if (ret == -ENODEV || ret == -ENOENT) {
317 printf("unknown device\n");
318 return -ENODEV;
319 }
320 if (ret)
321 return ret;
322 dev_print(desc);
323
324 if (desc->type == DEV_TYPE_UNKNOWN)
325 return -ENOENT;
326
327 return 0;
328}
329
Simon Glassfada3f92022-09-17 09:00:09 -0600330ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
Simon Glass4131ad52016-05-01 11:36:08 -0600331 lbaint_t blkcnt, void *buffer)
332{
333 struct blk_desc *desc;
334 ulong n;
335 int ret;
336
Simon Glassfada3f92022-09-17 09:00:09 -0600337 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600338 if (ret)
339 return ret;
340 n = blk_dread(desc, start, blkcnt, buffer);
341 if (IS_ERR_VALUE(n))
342 return n;
343
Simon Glass4131ad52016-05-01 11:36:08 -0600344 return n;
345}
346
Simon Glassfada3f92022-09-17 09:00:09 -0600347ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
Simon Glass4131ad52016-05-01 11:36:08 -0600348 lbaint_t blkcnt, const void *buffer)
349{
350 struct blk_desc *desc;
351 int ret;
352
Simon Glassfada3f92022-09-17 09:00:09 -0600353 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600354 if (ret)
355 return ret;
356 return blk_dwrite(desc, start, blkcnt, buffer);
357}
358
Simon Glass13c2c292016-05-01 13:52:30 -0600359int blk_select_hwpart(struct udevice *dev, int hwpart)
360{
361 const struct blk_ops *ops = blk_get_ops(dev);
362
363 if (!ops)
364 return -ENOSYS;
365 if (!ops->select_hwpart)
366 return 0;
367
368 return ops->select_hwpart(dev, hwpart);
369}
370
371int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
372{
developerf50d8d12019-08-27 15:32:18 +0800373 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600374}
375
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200376static int _blk_next_device(int uclass_id, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700377{
378 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200379 int ret = 0;
380
381 for (; *devp; uclass_find_next_device(devp)) {
382 desc = dev_get_uclass_plat(*devp);
383 if (desc->uclass_id == uclass_id) {
384 ret = device_probe(*devp);
385 if (!ret)
386 return 0;
387 }
388 }
Simon Glasscceee552016-02-29 15:25:55 -0700389
Simon Glasscceee552016-02-29 15:25:55 -0700390 if (ret)
391 return ret;
Simon Glasscceee552016-02-29 15:25:55 -0700392
393 return -ENODEV;
394}
395
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200396int blk_first_device(int uclass_id, struct udevice **devp)
397{
398 uclass_find_first_device(UCLASS_BLK, devp);
399
400 return _blk_next_device(uclass_id, devp);
401}
402
Simon Glasscceee552016-02-29 15:25:55 -0700403int blk_next_device(struct udevice **devp)
404{
405 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200406 int uclass_id;
Simon Glasscceee552016-02-29 15:25:55 -0700407
Simon Glass71fa5b42020-12-03 16:55:18 -0700408 desc = dev_get_uclass_plat(*devp);
Simon Glassfada3f92022-09-17 09:00:09 -0600409 uclass_id = desc->uclass_id;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200410 uclass_find_next_device(devp);
411
412 return _blk_next_device(uclass_id, devp);
Simon Glasscceee552016-02-29 15:25:55 -0700413}
414
Simon Glassfada3f92022-09-17 09:00:09 -0600415int blk_find_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700416{
417 struct uclass *uc;
418 struct udevice *dev;
419 int ret;
420
421 ret = uclass_get(UCLASS_BLK, &uc);
422 if (ret)
423 return ret;
424 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700425 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700426
Simon Glassfada3f92022-09-17 09:00:09 -0600427 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
428 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
429 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
Simon Glasscceee552016-02-29 15:25:55 -0700430 *devp = dev;
Simon Glassd5d4c102017-04-23 20:02:05 -0600431 return 0;
Simon Glasscceee552016-02-29 15:25:55 -0700432 }
433 }
434
435 return -ENODEV;
436}
437
Simon Glassfada3f92022-09-17 09:00:09 -0600438int blk_get_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glassd5d4c102017-04-23 20:02:05 -0600439{
440 int ret;
441
Simon Glassfada3f92022-09-17 09:00:09 -0600442 ret = blk_find_device(uclass_id, devnum, devp);
Simon Glassd5d4c102017-04-23 20:02:05 -0600443 if (ret)
444 return ret;
445
446 return device_probe(*devp);
447}
448
Simon Glass18861002022-10-20 18:22:54 -0600449long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700450{
Simon Glass18861002022-10-20 18:22:54 -0600451 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700452 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
Simon Glass18861002022-10-20 18:22:54 -0600458 if (blkcache_read(desc->uclass_id, desc->devnum,
459 start, blkcnt, desc->blksz, buf))
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700460 return blkcnt;
Simon Glass18861002022-10-20 18:22:54 -0600461 blks_read = ops->read(dev, start, blkcnt, buf);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700462 if (blks_read == blkcnt)
Simon Glass18861002022-10-20 18:22:54 -0600463 blkcache_fill(desc->uclass_id, desc->devnum, start, blkcnt,
464 desc->blksz, buf);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700465
466 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700467}
468
Simon Glass18861002022-10-20 18:22:54 -0600469long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
470 const void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700471{
Simon Glass18861002022-10-20 18:22:54 -0600472 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700473 const struct blk_ops *ops = blk_get_ops(dev);
474
475 if (!ops->write)
476 return -ENOSYS;
477
Simon Glass18861002022-10-20 18:22:54 -0600478 blkcache_invalidate(desc->uclass_id, desc->devnum);
479
480 return ops->write(dev, start, blkcnt, buf);
Simon Glasscceee552016-02-29 15:25:55 -0700481}
482
Simon Glass18861002022-10-20 18:22:54 -0600483long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
Simon Glasscceee552016-02-29 15:25:55 -0700484{
Simon Glass18861002022-10-20 18:22:54 -0600485 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700486 const struct blk_ops *ops = blk_get_ops(dev);
487
488 if (!ops->erase)
489 return -ENOSYS;
490
Simon Glass18861002022-10-20 18:22:54 -0600491 blkcache_invalidate(desc->uclass_id, desc->devnum);
492
Simon Glasscceee552016-02-29 15:25:55 -0700493 return ops->erase(dev, start, blkcnt);
494}
495
Simon Glass18861002022-10-20 18:22:54 -0600496ulong blk_dread(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
497 void *buffer)
498{
499 return blk_read(desc->bdev, start, blkcnt, buffer);
500}
501
502ulong blk_dwrite(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
503 const void *buffer)
504{
505 return blk_write(desc->bdev, start, blkcnt, buffer);
506}
507
508ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt)
509{
510 return blk_erase(desc->bdev, start, blkcnt);
511}
512
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600513int blk_find_from_parent(struct udevice *parent, struct udevice **devp)
Simon Glass4f269132017-05-27 11:37:17 -0600514{
515 struct udevice *dev;
Simon Glass4f269132017-05-27 11:37:17 -0600516
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600517 if (device_find_first_child_by_uclass(parent, UCLASS_BLK, &dev)) {
Simon Glass4f269132017-05-27 11:37:17 -0600518 debug("%s: No block device found for parent '%s'\n", __func__,
519 parent->name);
520 return -ENODEV;
521 }
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600522 *devp = dev;
523
524 return 0;
525}
526
527int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
528{
529 struct udevice *dev;
530 int ret;
531
532 ret = blk_find_from_parent(parent, &dev);
533 if (ret)
534 return ret;
Simon Glass4f269132017-05-27 11:37:17 -0600535 ret = device_probe(dev);
536 if (ret)
537 return ret;
538 *devp = dev;
539
540 return 0;
541}
542
Simon Glassf3086cf2022-04-24 23:31:03 -0600543const char *blk_get_devtype(struct udevice *dev)
544{
545 struct udevice *parent = dev_get_parent(dev);
546
547 return uclass_get_name(device_get_uclass_id(parent));
548};
549
Simon Glassfada3f92022-09-17 09:00:09 -0600550int blk_find_max_devnum(enum uclass_id uclass_id)
Simon Glassd089ba32016-05-01 11:36:28 -0600551{
552 struct udevice *dev;
553 int max_devnum = -ENODEV;
554 struct uclass *uc;
555 int ret;
556
557 ret = uclass_get(UCLASS_BLK, &uc);
558 if (ret)
559 return ret;
560 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700561 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd089ba32016-05-01 11:36:28 -0600562
Simon Glassfada3f92022-09-17 09:00:09 -0600563 if (desc->uclass_id == uclass_id && desc->devnum > max_devnum)
Simon Glassd089ba32016-05-01 11:36:28 -0600564 max_devnum = desc->devnum;
565 }
566
567 return max_devnum;
568}
569
Simon Glassfada3f92022-09-17 09:00:09 -0600570int blk_next_free_devnum(enum uclass_id uclass_id)
Simon Glassdbc38612017-04-23 20:02:06 -0600571{
572 int ret;
573
Simon Glassfada3f92022-09-17 09:00:09 -0600574 ret = blk_find_max_devnum(uclass_id);
Simon Glassdbc38612017-04-23 20:02:06 -0600575 if (ret == -ENODEV)
576 return 0;
577 if (ret < 0)
578 return ret;
579
580 return ret + 1;
581}
582
Simon Glassfc7a7442021-07-05 16:32:59 -0600583static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
584{
585 const struct blk_desc *desc = dev_get_uclass_plat(dev);
586 enum blk_flag_t flags;
587
588 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
589
590 return flags & req_flags ? 0 : 1;
591}
592
Simon Glass8e61f932022-02-28 12:08:35 -0700593int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
594{
595 int ret;
596
597 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
598 *devp && !blk_flags_check(*devp, flags);
599 ret = uclass_find_next_device(devp))
600 return 0;
601
602 return -ENODEV;
603}
604
605int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
606{
607 int ret;
608
609 for (ret = uclass_find_next_device(devp);
610 *devp && !blk_flags_check(*devp, flags);
611 ret = uclass_find_next_device(devp))
612 return 0;
613
614 return -ENODEV;
615}
616
Simon Glassfc7a7442021-07-05 16:32:59 -0600617int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
618{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200619 for (uclass_first_device(UCLASS_BLK, devp);
620 *devp;
621 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600622 if (!blk_flags_check(*devp, flags))
623 return 0;
624 }
625
626 return -ENODEV;
627}
628
629int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
630{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200631 for (uclass_next_device(devp);
632 *devp;
633 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600634 if (!blk_flags_check(*devp, flags))
635 return 0;
636 }
637
638 return -ENODEV;
639}
640
641int blk_count_devices(enum blk_flag_t flag)
642{
643 struct udevice *dev;
644 int count = 0;
645
646 blk_foreach_probe(flag, dev)
647 count++;
648
649 return count;
650}
651
Simon Glassfada3f92022-09-17 09:00:09 -0600652static int blk_claim_devnum(enum uclass_id uclass_id, int devnum)
Simon Glasse4fef742017-04-23 20:02:07 -0600653{
654 struct udevice *dev;
655 struct uclass *uc;
656 int ret;
657
658 ret = uclass_get(UCLASS_BLK, &uc);
659 if (ret)
660 return ret;
661 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700662 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse4fef742017-04-23 20:02:07 -0600663
Simon Glassfada3f92022-09-17 09:00:09 -0600664 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
665 int next = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600666
667 if (next < 0)
668 return next;
669 desc->devnum = next;
670 return 0;
671 }
672 }
673
674 return -ENOENT;
675}
676
Simon Glasscceee552016-02-29 15:25:55 -0700677int blk_create_device(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600678 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200679 lbaint_t lba, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700680{
681 struct blk_desc *desc;
682 struct udevice *dev;
683 int ret;
684
Simon Glassd089ba32016-05-01 11:36:28 -0600685 if (devnum == -1) {
Simon Glassfada3f92022-09-17 09:00:09 -0600686 devnum = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600687 } else {
Simon Glassfada3f92022-09-17 09:00:09 -0600688 ret = blk_claim_devnum(uclass_id, devnum);
Simon Glasse4fef742017-04-23 20:02:07 -0600689 if (ret < 0 && ret != -ENOENT)
Simon Glassd089ba32016-05-01 11:36:28 -0600690 return ret;
Simon Glassd089ba32016-05-01 11:36:28 -0600691 }
Simon Glasse4fef742017-04-23 20:02:07 -0600692 if (devnum < 0)
693 return devnum;
Simon Glass77f7fb82016-05-01 13:52:22 -0600694 ret = device_bind_driver(parent, drv_name, name, &dev);
695 if (ret)
696 return ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700697 desc = dev_get_uclass_plat(dev);
Simon Glassfada3f92022-09-17 09:00:09 -0600698 desc->uclass_id = uclass_id;
Simon Glass77f7fb82016-05-01 13:52:22 -0600699 desc->blksz = blksz;
Heinrich Schuchardt09ba4ea2019-10-25 12:15:31 +0200700 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200701 desc->lba = lba;
Simon Glass77f7fb82016-05-01 13:52:22 -0600702 desc->part_type = PART_TYPE_UNKNOWN;
703 desc->bdev = dev;
Simon Glasscceee552016-02-29 15:25:55 -0700704 desc->devnum = devnum;
705 *devp = dev;
706
707 return 0;
708}
709
Simon Glass966b6952016-05-01 11:36:29 -0600710int blk_create_devicef(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600711 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200712 lbaint_t lba, struct udevice **devp)
Simon Glass966b6952016-05-01 11:36:29 -0600713{
714 char dev_name[30], *str;
Simon Glass39e54922016-05-01 13:52:24 -0600715 int ret;
Simon Glass966b6952016-05-01 11:36:29 -0600716
717 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
718 str = strdup(dev_name);
719 if (!str)
720 return -ENOMEM;
721
Simon Glassfada3f92022-09-17 09:00:09 -0600722 ret = blk_create_device(parent, drv_name, str, uclass_id, devnum,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200723 blksz, lba, devp);
Simon Glass39e54922016-05-01 13:52:24 -0600724 if (ret) {
725 free(str);
726 return ret;
727 }
728 device_set_name_alloced(*devp);
729
Simon Glass44505972017-07-29 11:34:59 -0600730 return 0;
Simon Glass966b6952016-05-01 11:36:29 -0600731}
732
AKASHI Takahiro3e32dbe2021-12-10 15:49:29 +0900733int blk_probe_or_unbind(struct udevice *dev)
734{
735 int ret;
736
737 ret = device_probe(dev);
738 if (ret) {
739 log_debug("probing %s failed\n", dev->name);
740 device_unbind(dev);
741 }
742
743 return ret;
744}
745
Simon Glassfada3f92022-09-17 09:00:09 -0600746int blk_unbind_all(int uclass_id)
Simon Glasscceee552016-02-29 15:25:55 -0700747{
748 struct uclass *uc;
749 struct udevice *dev, *next;
750 int ret;
751
752 ret = uclass_get(UCLASS_BLK, &uc);
753 if (ret)
754 return ret;
755 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700756 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700757
Simon Glassfada3f92022-09-17 09:00:09 -0600758 if (desc->uclass_id == uclass_id) {
Stefan Roese80b5bc92017-03-20 12:51:48 +0100759 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glasscceee552016-02-29 15:25:55 -0700760 if (ret)
761 return ret;
762 ret = device_unbind(dev);
763 if (ret)
764 return ret;
765 }
766 }
767
768 return 0;
769}
770
Marek Vasut14fafef2023-08-14 01:46:47 +0200771static int part_create_block_devices(struct udevice *blk_dev)
772{
773 int part, count;
774 struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
775 struct disk_partition info;
776 struct disk_part *part_data;
777 char devname[32];
778 struct udevice *dev;
779 int ret;
780
781 if (!CONFIG_IS_ENABLED(PARTITIONS) || !blk_enabled())
782 return 0;
783
784 if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
785 return 0;
786
787 /* Add devices for each partition */
788 for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
789 if (part_get_info(desc, part, &info))
790 continue;
791 snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
792 part);
793
794 ret = device_bind_driver(blk_dev, "blk_partition",
795 strdup(devname), &dev);
796 if (ret)
797 return ret;
798
799 part_data = dev_get_uclass_plat(dev);
800 part_data->partnum = part;
801 part_data->gpt_part_info = info;
802 count++;
803
804 ret = device_probe(dev);
805 if (ret) {
806 debug("Can't probe\n");
807 count--;
808 device_unbind(dev);
809
810 continue;
811 }
812 }
813 debug("%s: %d partitions found in %s\n", __func__, count,
814 blk_dev->name);
815
816 return 0;
817}
818
Bin Mengcbc3da82018-10-15 02:21:07 -0700819static int blk_post_probe(struct udevice *dev)
820{
Simon Glassf5ac3032022-08-11 19:34:45 -0600821 if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700822 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700823
Ovidiu Panait76160a02020-07-24 14:12:21 +0300824 part_init(desc);
AKASHI Takahiro358e6c72022-04-19 10:05:10 +0900825
826 if (desc->part_type != PART_TYPE_UNKNOWN &&
827 part_create_block_devices(dev))
828 debug("*** creating partitions failed\n");
Ovidiu Panait76160a02020-07-24 14:12:21 +0300829 }
Bin Mengcbc3da82018-10-15 02:21:07 -0700830
831 return 0;
832}
833
Simon Glasscceee552016-02-29 15:25:55 -0700834UCLASS_DRIVER(blk) = {
835 .id = UCLASS_BLK,
836 .name = "blk",
Bin Mengcbc3da82018-10-15 02:21:07 -0700837 .post_probe = blk_post_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700838 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glasscceee552016-02-29 15:25:55 -0700839};