blob: cb73faaedaf5452e5257d1b7c555da27ce6f1b5c [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;
Simon Glass8149b152022-09-17 09:00:09 -060023} uclass_idname_str[] = {
Simon Glasse33a5c62022-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" },
Simon Glass95201812022-10-29 19:47:17 -060029 { UCLASS_HOST, "host" },
Simon Glasse33a5c62022-08-11 19:34:59 -060030 { UCLASS_NVME, "nvme" },
31 { UCLASS_EFI_MEDIA, "efi" },
32 { UCLASS_EFI_LOADER, "efiloader" },
33 { UCLASS_VIRTIO, "virtio" },
34 { UCLASS_PVBLOCK, "pvblock" },
Tobias Waldekranzc41e2092023-02-16 16:33:49 +010035 { UCLASS_BLKMAP, "blkmap" },
Simon Glassd508c822016-05-01 11:36:08 -060036};
37
Simon Glass8149b152022-09-17 09:00:09 -060038static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
Simon Glassd508c822016-05-01 11:36:08 -060039{
40 int i;
41
Simon Glass8149b152022-09-17 09:00:09 -060042 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
43 if (!strcmp(uclass_idname, uclass_idname_str[i].name))
44 return uclass_idname_str[i].id;
Simon Glassd508c822016-05-01 11:36:08 -060045 }
46
Simon Glasse33a5c62022-08-11 19:34:59 -060047 return UCLASS_INVALID;
Simon Glassd508c822016-05-01 11:36:08 -060048}
49
Simon Glass8149b152022-09-17 09:00:09 -060050static enum uclass_id conv_uclass_id(enum uclass_id uclass_id)
Simon Glassd508c822016-05-01 11:36:08 -060051{
Simon Glasse33a5c62022-08-11 19:34:59 -060052 /*
53 * This strange adjustment is used because we use UCLASS_MASS_STORAGE
54 * for USB storage devices, so need to return this as the uclass to
55 * use for USB. In fact USB_UCLASS is for USB controllers, not
56 * peripherals.
57 *
58 * The name of the UCLASS_MASS_STORAGE uclass driver is
59 * "usb_mass_storage", but we want to use "usb" in things like the
60 * 'part list' command and when showing interfaces.
61 *
62 * So for now we have this one-way conversion.
63 *
64 * The fix for this is possibly to:
65 * - rename UCLASS_MASS_STORAGE name to "usb"
66 * - rename UCLASS_USB name to "usb_ctlr"
67 * - use UCLASS_MASS_STORAGE instead of UCLASS_USB in if_typename_str
68 */
Simon Glass8149b152022-09-17 09:00:09 -060069 if (uclass_id == UCLASS_USB)
Simon Glasse33a5c62022-08-11 19:34:59 -060070 return UCLASS_MASS_STORAGE;
Simon Glass8149b152022-09-17 09:00:09 -060071 return uclass_id;
Simon Glassd508c822016-05-01 11:36:08 -060072}
73
Simon Glass8149b152022-09-17 09:00:09 -060074const char *blk_get_uclass_name(enum uclass_id uclass_id)
Simon Glass6faa4ed2017-07-29 11:34:53 -060075{
Simon Glassbb2c9a32022-08-11 19:34:57 -060076 int i;
77
Simon Glass8149b152022-09-17 09:00:09 -060078 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
79 if (uclass_idname_str[i].id == uclass_id)
80 return uclass_idname_str[i].name;
Simon Glassbb2c9a32022-08-11 19:34:57 -060081 }
82
83 return "(none)";
Simon Glass6faa4ed2017-07-29 11:34:53 -060084}
85
Simon Glass8149b152022-09-17 09:00:09 -060086struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
Simon Glassd508c822016-05-01 11:36:08 -060087{
88 struct blk_desc *desc;
89 struct udevice *dev;
90 int ret;
91
Simon Glass8149b152022-09-17 09:00:09 -060092 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glassd508c822016-05-01 11:36:08 -060093 if (ret)
94 return NULL;
Simon Glasscaa4daa2020-12-03 16:55:18 -070095 desc = dev_get_uclass_plat(dev);
Simon Glassd508c822016-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 */
Simon Glass8149b152022-09-17 09:00:09 -0600105struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
Simon Glassd508c822016-05-01 11:36:08 -0600106{
107 enum uclass_id uclass_id;
Simon Glassec8bdc92022-08-11 19:35:01 -0600108 enum uclass_id type;
Simon Glassd508c822016-05-01 11:36:08 -0600109 struct udevice *dev;
110 struct uclass *uc;
111 int ret;
112
Simon Glass8149b152022-09-17 09:00:09 -0600113 type = uclass_name_to_iftype(uclass_idname);
Simon Glasse33a5c62022-08-11 19:34:59 -0600114 if (type == UCLASS_INVALID) {
Simon Glassd508c822016-05-01 11:36:08 -0600115 debug("%s: Unknown interface type '%s'\n", __func__,
Simon Glass8149b152022-09-17 09:00:09 -0600116 uclass_idname);
Simon Glassd508c822016-05-01 11:36:08 -0600117 return NULL;
118 }
Simon Glass8149b152022-09-17 09:00:09 -0600119 uclass_id = conv_uclass_id(type);
Simon Glassd508c822016-05-01 11:36:08 -0600120 if (uclass_id == UCLASS_INVALID) {
121 debug("%s: Unknown uclass for interface type'\n",
Simon Glass8149b152022-09-17 09:00:09 -0600122 blk_get_uclass_name(type));
Simon Glassd508c822016-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 Glasscaa4daa2020-12-03 16:55:18 -0700130 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd508c822016-05-01 11:36:08 -0600131
Simon Glass8149b152022-09-17 09:00:09 -0600132 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
133 type, devnum, dev->name, desc->uclass_id, desc->devnum);
Simon Glassd508c822016-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 Cheebc53d262018-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 Glasse5f73902019-09-25 08:55:56 -0600164 struct udevice *child_dev;
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800165
Simon Glasse5f73902019-09-25 08:55:56 -0600166 device_foreach_child(child_dev, dev) {
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800167 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
168 continue;
169
Simon Glasscaa4daa2020-12-03 16:55:18 -0700170 return dev_get_uclass_plat(child_dev);
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800171 }
172
173 debug("%s: No block device found\n", __func__);
174
175 return NULL;
176}
177
178/**
Simon Glassd508c822016-05-01 11:36:08 -0600179 * get_desc() - Get the block device descriptor for the given device number
180 *
Simon Glass8149b152022-09-17 09:00:09 -0600181 * @uclass_id: Interface type
Simon Glassd508c822016-05-01 11:36:08 -0600182 * @devnum: Device number (0 = first)
183 * @descp: Returns block device descriptor on success
Heinrich Schuchardt185f8122022-01-19 18:05:50 +0100184 * Return: 0 on success, -ENODEV if there is no such device and no device
Simon Glassd508c822016-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 Glass8149b152022-09-17 09:00:09 -0600188static int get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
Simon Glassd508c822016-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 Glasscaa4daa2020-12-03 16:55:18 -0700200 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd508c822016-05-01 11:36:08 -0600201
Simon Glass8149b152022-09-17 09:00:09 -0600202 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
203 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
204 if (desc->uclass_id == uclass_id) {
Simon Glassd508c822016-05-01 11:36:08 -0600205 if (desc->devnum == devnum) {
206 ret = device_probe(dev);
207 if (ret)
208 return ret;
209
Michal Simek4408f6f2016-11-16 17:37:42 +0100210 *descp = desc;
211 return 0;
Simon Glassd508c822016-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 Glass8149b152022-09-17 09:00:09 -0600221int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
Simon Glasscd0fb552016-05-01 13:52:30 -0600222{
223 struct udevice *dev;
224 int ret;
225
Simon Glass8149b152022-09-17 09:00:09 -0600226 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glasscd0fb552016-05-01 13:52:30 -0600227 if (ret)
228 return ret;
229
Weijie Gao1ce88472019-08-27 15:32:18 +0800230 return blk_select_hwpart(dev, hwpart);
Simon Glasscd0fb552016-05-01 13:52:30 -0600231}
232
Simon Glass8149b152022-09-17 09:00:09 -0600233int blk_list_part(enum uclass_id uclass_id)
Simon Glassd508c822016-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) {
Simon Glass8149b152022-09-17 09:00:09 -0600240 ret = get_desc(uclass_id, devnum, &desc);
Simon Glassd508c822016-05-01 11:36:08 -0600241 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 Glass8149b152022-09-17 09:00:09 -0600258int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
Simon Glassd508c822016-05-01 11:36:08 -0600259{
260 struct blk_desc *desc;
261 int ret;
262
Simon Glass8149b152022-09-17 09:00:09 -0600263 ret = get_desc(uclass_id, devnum, &desc);
Simon Glassd508c822016-05-01 11:36:08 -0600264 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 Glass8149b152022-09-17 09:00:09 -0600273void blk_list_devices(enum uclass_id uclass_id)
Simon Glassd508c822016-05-01 11:36:08 -0600274{
275 struct blk_desc *desc;
276 int ret;
277 int i;
278
279 for (i = 0;; ++i) {
Simon Glass8149b152022-09-17 09:00:09 -0600280 ret = get_desc(uclass_id, i, &desc);
Simon Glassd508c822016-05-01 11:36:08 -0600281 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 Glass8149b152022-09-17 09:00:09 -0600292int blk_print_device_num(enum uclass_id uclass_id, int devnum)
Simon Glassd508c822016-05-01 11:36:08 -0600293{
294 struct blk_desc *desc;
295 int ret;
296
Simon Glass8149b152022-09-17 09:00:09 -0600297 ret = get_desc(uclass_id, devnum, &desc);
Simon Glassd508c822016-05-01 11:36:08 -0600298 if (ret)
299 return ret;
300 printf("\nIDE device %d: ", devnum);
301 dev_print(desc);
302
303 return 0;
304}
305
Simon Glass8149b152022-09-17 09:00:09 -0600306int blk_show_device(enum uclass_id uclass_id, int devnum)
Simon Glassd508c822016-05-01 11:36:08 -0600307{
308 struct blk_desc *desc;
309 int ret;
310
311 printf("\nDevice %d: ", devnum);
Simon Glass8149b152022-09-17 09:00:09 -0600312 ret = get_desc(uclass_id, devnum, &desc);
Simon Glassd508c822016-05-01 11:36:08 -0600313 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 Glass8149b152022-09-17 09:00:09 -0600327ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
Simon Glassd508c822016-05-01 11:36:08 -0600328 lbaint_t blkcnt, void *buffer)
329{
330 struct blk_desc *desc;
331 ulong n;
332 int ret;
333
Simon Glass8149b152022-09-17 09:00:09 -0600334 ret = get_desc(uclass_id, devnum, &desc);
Simon Glassd508c822016-05-01 11:36:08 -0600335 if (ret)
336 return ret;
337 n = blk_dread(desc, start, blkcnt, buffer);
338 if (IS_ERR_VALUE(n))
339 return n;
340
Simon Glassd508c822016-05-01 11:36:08 -0600341 return n;
342}
343
Simon Glass8149b152022-09-17 09:00:09 -0600344ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
Simon Glassd508c822016-05-01 11:36:08 -0600345 lbaint_t blkcnt, const void *buffer)
346{
347 struct blk_desc *desc;
348 int ret;
349
Simon Glass8149b152022-09-17 09:00:09 -0600350 ret = get_desc(uclass_id, devnum, &desc);
Simon Glassd508c822016-05-01 11:36:08 -0600351 if (ret)
352 return ret;
353 return blk_dwrite(desc, start, blkcnt, buffer);
354}
355
Simon Glasscd0fb552016-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{
Weijie Gao1ce88472019-08-27 15:32:18 +0800370 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glasscd0fb552016-05-01 13:52:30 -0600371}
372
Michal Suchanek168a0e42022-09-27 23:23:53 +0200373static int _blk_next_device(int uclass_id, struct udevice **devp)
Simon Glass09d71aa2016-02-29 15:25:55 -0700374{
375 struct blk_desc *desc;
Michal Suchanek168a0e42022-09-27 23:23:53 +0200376 int ret = 0;
Simon Glass09d71aa2016-02-29 15:25:55 -0700377
Michal Suchanek168a0e42022-09-27 23:23:53 +0200378 for (; *devp; uclass_find_next_device(devp)) {
379 desc = dev_get_uclass_plat(*devp);
380 if (desc->uclass_id == uclass_id) {
381 ret = device_probe(*devp);
382 if (!ret)
383 return 0;
384 }
385 }
386
Simon Glass09d71aa2016-02-29 15:25:55 -0700387 if (ret)
388 return ret;
Simon Glass09d71aa2016-02-29 15:25:55 -0700389
390 return -ENODEV;
391}
392
Michal Suchanek168a0e42022-09-27 23:23:53 +0200393int blk_first_device(int uclass_id, struct udevice **devp)
394{
395 uclass_find_first_device(UCLASS_BLK, devp);
396
397 return _blk_next_device(uclass_id, devp);
398}
399
Simon Glass09d71aa2016-02-29 15:25:55 -0700400int blk_next_device(struct udevice **devp)
401{
402 struct blk_desc *desc;
Michal Suchanek168a0e42022-09-27 23:23:53 +0200403 int uclass_id;
Simon Glass09d71aa2016-02-29 15:25:55 -0700404
Simon Glasscaa4daa2020-12-03 16:55:18 -0700405 desc = dev_get_uclass_plat(*devp);
Simon Glass8149b152022-09-17 09:00:09 -0600406 uclass_id = desc->uclass_id;
Michal Suchanek168a0e42022-09-27 23:23:53 +0200407 uclass_find_next_device(devp);
408
409 return _blk_next_device(uclass_id, devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700410}
411
Simon Glass8149b152022-09-17 09:00:09 -0600412int blk_find_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glass09d71aa2016-02-29 15:25:55 -0700413{
414 struct uclass *uc;
415 struct udevice *dev;
416 int ret;
417
418 ret = uclass_get(UCLASS_BLK, &uc);
419 if (ret)
420 return ret;
421 uclass_foreach_dev(dev, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700422 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass09d71aa2016-02-29 15:25:55 -0700423
Simon Glass8149b152022-09-17 09:00:09 -0600424 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
425 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
426 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
Simon Glass09d71aa2016-02-29 15:25:55 -0700427 *devp = dev;
Simon Glass61392812017-04-23 20:02:05 -0600428 return 0;
Simon Glass09d71aa2016-02-29 15:25:55 -0700429 }
430 }
431
432 return -ENODEV;
433}
434
Simon Glass8149b152022-09-17 09:00:09 -0600435int blk_get_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glass61392812017-04-23 20:02:05 -0600436{
437 int ret;
438
Simon Glass8149b152022-09-17 09:00:09 -0600439 ret = blk_find_device(uclass_id, devnum, devp);
Simon Glass61392812017-04-23 20:02:05 -0600440 if (ret)
441 return ret;
442
443 return device_probe(*devp);
444}
445
Simon Glass606b9262022-10-20 18:22:54 -0600446long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
Simon Glass09d71aa2016-02-29 15:25:55 -0700447{
Simon Glass606b9262022-10-20 18:22:54 -0600448 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass09d71aa2016-02-29 15:25:55 -0700449 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsone40cf342016-03-28 10:05:44 -0700450 ulong blks_read;
Simon Glass09d71aa2016-02-29 15:25:55 -0700451
452 if (!ops->read)
453 return -ENOSYS;
454
Simon Glass606b9262022-10-20 18:22:54 -0600455 if (blkcache_read(desc->uclass_id, desc->devnum,
456 start, blkcnt, desc->blksz, buf))
Eric Nelsone40cf342016-03-28 10:05:44 -0700457 return blkcnt;
Simon Glass606b9262022-10-20 18:22:54 -0600458 blks_read = ops->read(dev, start, blkcnt, buf);
Eric Nelsone40cf342016-03-28 10:05:44 -0700459 if (blks_read == blkcnt)
Simon Glass606b9262022-10-20 18:22:54 -0600460 blkcache_fill(desc->uclass_id, desc->devnum, start, blkcnt,
461 desc->blksz, buf);
Eric Nelsone40cf342016-03-28 10:05:44 -0700462
463 return blks_read;
Simon Glass09d71aa2016-02-29 15:25:55 -0700464}
465
Simon Glass606b9262022-10-20 18:22:54 -0600466long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
467 const void *buf)
Simon Glass09d71aa2016-02-29 15:25:55 -0700468{
Simon Glass606b9262022-10-20 18:22:54 -0600469 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass09d71aa2016-02-29 15:25:55 -0700470 const struct blk_ops *ops = blk_get_ops(dev);
471
472 if (!ops->write)
473 return -ENOSYS;
474
Simon Glass606b9262022-10-20 18:22:54 -0600475 blkcache_invalidate(desc->uclass_id, desc->devnum);
476
477 return ops->write(dev, start, blkcnt, buf);
Simon Glass09d71aa2016-02-29 15:25:55 -0700478}
479
Simon Glass606b9262022-10-20 18:22:54 -0600480long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
Simon Glass09d71aa2016-02-29 15:25:55 -0700481{
Simon Glass606b9262022-10-20 18:22:54 -0600482 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass09d71aa2016-02-29 15:25:55 -0700483 const struct blk_ops *ops = blk_get_ops(dev);
484
485 if (!ops->erase)
486 return -ENOSYS;
487
Simon Glass606b9262022-10-20 18:22:54 -0600488 blkcache_invalidate(desc->uclass_id, desc->devnum);
489
Simon Glass09d71aa2016-02-29 15:25:55 -0700490 return ops->erase(dev, start, blkcnt);
491}
492
Simon Glass606b9262022-10-20 18:22:54 -0600493ulong blk_dread(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
494 void *buffer)
495{
496 return blk_read(desc->bdev, start, blkcnt, buffer);
497}
498
499ulong blk_dwrite(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
500 const void *buffer)
501{
502 return blk_write(desc->bdev, start, blkcnt, buffer);
503}
504
505ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt)
506{
507 return blk_erase(desc->bdev, start, blkcnt);
508}
509
Simon Glass41e75102022-10-29 19:47:14 -0600510int blk_find_from_parent(struct udevice *parent, struct udevice **devp)
Simon Glass9f103b92017-05-27 11:37:17 -0600511{
512 struct udevice *dev;
Simon Glass9f103b92017-05-27 11:37:17 -0600513
Simon Glass41e75102022-10-29 19:47:14 -0600514 if (device_find_first_child_by_uclass(parent, UCLASS_BLK, &dev)) {
Simon Glass9f103b92017-05-27 11:37:17 -0600515 debug("%s: No block device found for parent '%s'\n", __func__,
516 parent->name);
517 return -ENODEV;
518 }
Simon Glass41e75102022-10-29 19:47:14 -0600519 *devp = dev;
520
521 return 0;
522}
523
524int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
525{
526 struct udevice *dev;
527 int ret;
528
529 ret = blk_find_from_parent(parent, &dev);
530 if (ret)
531 return ret;
Simon Glass9f103b92017-05-27 11:37:17 -0600532 ret = device_probe(dev);
533 if (ret)
534 return ret;
535 *devp = dev;
536
537 return 0;
538}
539
Simon Glass87571b72022-04-24 23:31:03 -0600540const char *blk_get_devtype(struct udevice *dev)
541{
542 struct udevice *parent = dev_get_parent(dev);
543
544 return uclass_get_name(device_get_uclass_id(parent));
545};
546
Simon Glass8149b152022-09-17 09:00:09 -0600547int blk_find_max_devnum(enum uclass_id uclass_id)
Simon Glass52138fd2016-05-01 11:36:28 -0600548{
549 struct udevice *dev;
550 int max_devnum = -ENODEV;
551 struct uclass *uc;
552 int ret;
553
554 ret = uclass_get(UCLASS_BLK, &uc);
555 if (ret)
556 return ret;
557 uclass_foreach_dev(dev, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700558 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass52138fd2016-05-01 11:36:28 -0600559
Simon Glass8149b152022-09-17 09:00:09 -0600560 if (desc->uclass_id == uclass_id && desc->devnum > max_devnum)
Simon Glass52138fd2016-05-01 11:36:28 -0600561 max_devnum = desc->devnum;
562 }
563
564 return max_devnum;
565}
566
Simon Glass8149b152022-09-17 09:00:09 -0600567int blk_next_free_devnum(enum uclass_id uclass_id)
Simon Glasse8abbb52017-04-23 20:02:06 -0600568{
569 int ret;
570
Simon Glass8149b152022-09-17 09:00:09 -0600571 ret = blk_find_max_devnum(uclass_id);
Simon Glasse8abbb52017-04-23 20:02:06 -0600572 if (ret == -ENODEV)
573 return 0;
574 if (ret < 0)
575 return ret;
576
577 return ret + 1;
578}
579
Simon Glass96f37b02021-07-05 16:32:59 -0600580static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
581{
582 const struct blk_desc *desc = dev_get_uclass_plat(dev);
583 enum blk_flag_t flags;
584
585 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
586
587 return flags & req_flags ? 0 : 1;
588}
589
Simon Glass49e86682022-02-28 12:08:35 -0700590int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
591{
592 int ret;
593
594 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
595 *devp && !blk_flags_check(*devp, flags);
596 ret = uclass_find_next_device(devp))
597 return 0;
598
599 return -ENODEV;
600}
601
602int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
603{
604 int ret;
605
606 for (ret = uclass_find_next_device(devp);
607 *devp && !blk_flags_check(*devp, flags);
608 ret = uclass_find_next_device(devp))
609 return 0;
610
611 return -ENODEV;
612}
613
Simon Glass96f37b02021-07-05 16:32:59 -0600614int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
615{
Michal Suchanek9b7474d2022-10-12 21:58:01 +0200616 for (uclass_first_device(UCLASS_BLK, devp);
617 *devp;
618 uclass_next_device(devp)) {
Simon Glass96f37b02021-07-05 16:32:59 -0600619 if (!blk_flags_check(*devp, flags))
620 return 0;
621 }
622
623 return -ENODEV;
624}
625
626int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
627{
Michal Suchanek9b7474d2022-10-12 21:58:01 +0200628 for (uclass_next_device(devp);
629 *devp;
630 uclass_next_device(devp)) {
Simon Glass96f37b02021-07-05 16:32:59 -0600631 if (!blk_flags_check(*devp, flags))
632 return 0;
633 }
634
635 return -ENODEV;
636}
637
638int blk_count_devices(enum blk_flag_t flag)
639{
640 struct udevice *dev;
641 int count = 0;
642
643 blk_foreach_probe(flag, dev)
644 count++;
645
646 return count;
647}
648
Simon Glass8149b152022-09-17 09:00:09 -0600649static int blk_claim_devnum(enum uclass_id uclass_id, int devnum)
Simon Glasse48eeb92017-04-23 20:02:07 -0600650{
651 struct udevice *dev;
652 struct uclass *uc;
653 int ret;
654
655 ret = uclass_get(UCLASS_BLK, &uc);
656 if (ret)
657 return ret;
658 uclass_foreach_dev(dev, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700659 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse48eeb92017-04-23 20:02:07 -0600660
Simon Glass8149b152022-09-17 09:00:09 -0600661 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
662 int next = blk_next_free_devnum(uclass_id);
Simon Glasse48eeb92017-04-23 20:02:07 -0600663
664 if (next < 0)
665 return next;
666 desc->devnum = next;
667 return 0;
668 }
669 }
670
671 return -ENOENT;
672}
673
Simon Glass09d71aa2016-02-29 15:25:55 -0700674int blk_create_device(struct udevice *parent, const char *drv_name,
Simon Glass8149b152022-09-17 09:00:09 -0600675 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200676 lbaint_t lba, struct udevice **devp)
Simon Glass09d71aa2016-02-29 15:25:55 -0700677{
678 struct blk_desc *desc;
679 struct udevice *dev;
680 int ret;
681
Simon Glass52138fd2016-05-01 11:36:28 -0600682 if (devnum == -1) {
Simon Glass8149b152022-09-17 09:00:09 -0600683 devnum = blk_next_free_devnum(uclass_id);
Simon Glasse48eeb92017-04-23 20:02:07 -0600684 } else {
Simon Glass8149b152022-09-17 09:00:09 -0600685 ret = blk_claim_devnum(uclass_id, devnum);
Simon Glasse48eeb92017-04-23 20:02:07 -0600686 if (ret < 0 && ret != -ENOENT)
Simon Glass52138fd2016-05-01 11:36:28 -0600687 return ret;
Simon Glass52138fd2016-05-01 11:36:28 -0600688 }
Simon Glasse48eeb92017-04-23 20:02:07 -0600689 if (devnum < 0)
690 return devnum;
Simon Glass72a85c02016-05-01 13:52:22 -0600691 ret = device_bind_driver(parent, drv_name, name, &dev);
692 if (ret)
693 return ret;
Simon Glasscaa4daa2020-12-03 16:55:18 -0700694 desc = dev_get_uclass_plat(dev);
Simon Glass8149b152022-09-17 09:00:09 -0600695 desc->uclass_id = uclass_id;
Simon Glass72a85c02016-05-01 13:52:22 -0600696 desc->blksz = blksz;
Heinrich Schuchardtee504142019-10-25 12:15:31 +0200697 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200698 desc->lba = lba;
Simon Glass72a85c02016-05-01 13:52:22 -0600699 desc->part_type = PART_TYPE_UNKNOWN;
700 desc->bdev = dev;
Simon Glass09d71aa2016-02-29 15:25:55 -0700701 desc->devnum = devnum;
702 *devp = dev;
703
704 return 0;
705}
706
Simon Glass9107c972016-05-01 11:36:29 -0600707int blk_create_devicef(struct udevice *parent, const char *drv_name,
Simon Glass8149b152022-09-17 09:00:09 -0600708 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200709 lbaint_t lba, struct udevice **devp)
Simon Glass9107c972016-05-01 11:36:29 -0600710{
711 char dev_name[30], *str;
Simon Glassd0773522016-05-01 13:52:24 -0600712 int ret;
Simon Glass9107c972016-05-01 11:36:29 -0600713
714 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
715 str = strdup(dev_name);
716 if (!str)
717 return -ENOMEM;
718
Simon Glass8149b152022-09-17 09:00:09 -0600719 ret = blk_create_device(parent, drv_name, str, uclass_id, devnum,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200720 blksz, lba, devp);
Simon Glassd0773522016-05-01 13:52:24 -0600721 if (ret) {
722 free(str);
723 return ret;
724 }
725 device_set_name_alloced(*devp);
726
Simon Glass7074b2a2017-07-29 11:34:59 -0600727 return 0;
Simon Glass9107c972016-05-01 11:36:29 -0600728}
729
AKASHI Takahiro19b241c2021-12-10 15:49:29 +0900730int blk_probe_or_unbind(struct udevice *dev)
731{
732 int ret;
733
734 ret = device_probe(dev);
735 if (ret) {
736 log_debug("probing %s failed\n", dev->name);
737 device_unbind(dev);
738 }
739
740 return ret;
741}
742
Simon Glass8149b152022-09-17 09:00:09 -0600743int blk_unbind_all(int uclass_id)
Simon Glass09d71aa2016-02-29 15:25:55 -0700744{
745 struct uclass *uc;
746 struct udevice *dev, *next;
747 int ret;
748
749 ret = uclass_get(UCLASS_BLK, &uc);
750 if (ret)
751 return ret;
752 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700753 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass09d71aa2016-02-29 15:25:55 -0700754
Simon Glass8149b152022-09-17 09:00:09 -0600755 if (desc->uclass_id == uclass_id) {
Stefan Roese706865a2017-03-20 12:51:48 +0100756 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glass09d71aa2016-02-29 15:25:55 -0700757 if (ret)
758 return ret;
759 ret = device_unbind(dev);
760 if (ret)
761 return ret;
762 }
763 }
764
765 return 0;
766}
767
Bin Mengd0851c82018-10-15 02:21:07 -0700768static int blk_post_probe(struct udevice *dev)
769{
Simon Glassa51eb8d2022-08-11 19:34:45 -0600770 if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700771 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengd0851c82018-10-15 02:21:07 -0700772
Ovidiu Panait3a4b52a2020-07-24 14:12:21 +0300773 part_init(desc);
AKASHI Takahirobf760312022-04-19 10:05:10 +0900774
775 if (desc->part_type != PART_TYPE_UNKNOWN &&
776 part_create_block_devices(dev))
777 debug("*** creating partitions failed\n");
Ovidiu Panait3a4b52a2020-07-24 14:12:21 +0300778 }
Bin Mengd0851c82018-10-15 02:21:07 -0700779
780 return 0;
781}
782
Simon Glass09d71aa2016-02-29 15:25:55 -0700783UCLASS_DRIVER(blk) = {
784 .id = UCLASS_BLK,
785 .name = "blk",
Bin Mengd0851c82018-10-15 02:21:07 -0700786 .post_probe = blk_post_probe,
Simon Glasscaa4daa2020-12-03 16:55:18 -0700787 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glass09d71aa2016-02-29 15:25:55 -0700788};