1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #define LOG_CATEGORY UCLASS_BLK
8 
9 #include <common.h>
10 #include <blk.h>
11 #include <dm.h>
12 #include <log.h>
13 #include <malloc.h>
14 #include <part.h>
15 #include <dm/device-internal.h>
16 #include <dm/lists.h>
17 #include <dm/uclass-internal.h>
18 #include <linux/err.h>
19 
20 static struct {
21 	enum uclass_id id;
22 	const char *name;
23 } uclass_idname_str[] = {
24 	{ UCLASS_IDE, "ide" },
25 	{ UCLASS_SCSI, "scsi" },
26 	{ UCLASS_USB, "usb" },
27 	{ UCLASS_MMC,  "mmc" },
28 	{ UCLASS_AHCI, "sata" },
29 	{ UCLASS_HOST, "host" },
30 	{ UCLASS_NVME, "nvme" },
31 	{ UCLASS_NVMXIP, "nvmxip" },
32 	{ UCLASS_EFI_MEDIA, "efi" },
33 	{ UCLASS_EFI_LOADER, "efiloader" },
34 	{ UCLASS_VIRTIO, "virtio" },
35 	{ UCLASS_PVBLOCK, "pvblock" },
36 	{ UCLASS_BLKMAP, "blkmap" },
37 };
38 
uclass_name_to_iftype(const char * uclass_idname)39 static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
40 {
41 	int i;
42 
43 	for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
44 		if (!strcmp(uclass_idname, uclass_idname_str[i].name))
45 			return uclass_idname_str[i].id;
46 	}
47 
48 	return UCLASS_INVALID;
49 }
50 
conv_uclass_id(enum uclass_id uclass_id)51 static enum uclass_id conv_uclass_id(enum uclass_id uclass_id)
52 {
53 	/*
54 	 * This strange adjustment is used because we use UCLASS_MASS_STORAGE
55 	 * for USB storage devices, so need to return this as the uclass to
56 	 * use for USB. In fact USB_UCLASS is for USB controllers, not
57 	 * peripherals.
58 	 *
59 	 * The name of the UCLASS_MASS_STORAGE uclass driver is
60 	 * "usb_mass_storage", but we want to use "usb" in things like the
61 	 * 'part list' command and when showing interfaces.
62 	 *
63 	 * So for now we have this one-way conversion.
64 	 *
65 	 * The fix for this is possibly to:
66 	 *    - rename UCLASS_MASS_STORAGE name to "usb"
67 	 *    - rename UCLASS_USB name to "usb_ctlr"
68 	 *    - use UCLASS_MASS_STORAGE instead of UCLASS_USB in if_typename_str
69 	 */
70 	if (uclass_id == UCLASS_USB)
71 		return UCLASS_MASS_STORAGE;
72 	return uclass_id;
73 }
74 
blk_get_uclass_name(enum uclass_id uclass_id)75 const char *blk_get_uclass_name(enum uclass_id uclass_id)
76 {
77 	int i;
78 
79 	for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
80 		if (uclass_idname_str[i].id == uclass_id)
81 			return uclass_idname_str[i].name;
82 	}
83 
84 	return "(none)";
85 }
86 
blk_get_devnum_by_uclass_id(enum uclass_id uclass_id,int devnum)87 struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
88 {
89 	struct blk_desc *desc;
90 	struct udevice *dev;
91 	int ret;
92 
93 	ret = blk_get_device(uclass_id, devnum, &dev);
94 	if (ret)
95 		return NULL;
96 	desc = dev_get_uclass_plat(dev);
97 
98 	return desc;
99 }
100 
101 /*
102  * This function is complicated with driver model. We look up the interface
103  * name in a local table. This gives us an interface type which we can match
104  * against the uclass of the block device's parent.
105  */
blk_get_devnum_by_uclass_idname(const char * uclass_idname,int devnum)106 struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
107 {
108 	enum uclass_id uclass_id;
109 	enum uclass_id type;
110 	struct udevice *dev;
111 	struct uclass *uc;
112 	int ret;
113 
114 	type = uclass_name_to_iftype(uclass_idname);
115 	if (type == UCLASS_INVALID) {
116 		debug("%s: Unknown interface type '%s'\n", __func__,
117 		      uclass_idname);
118 		return NULL;
119 	}
120 	uclass_id = conv_uclass_id(type);
121 	if (uclass_id == UCLASS_INVALID) {
122 		debug("%s: Unknown uclass for interface type'\n",
123 		      blk_get_uclass_name(type));
124 		return NULL;
125 	}
126 
127 	ret = uclass_get(UCLASS_BLK, &uc);
128 	if (ret)
129 		return NULL;
130 	uclass_foreach_dev(dev, uc) {
131 		struct blk_desc *desc = dev_get_uclass_plat(dev);
132 
133 		debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
134 		      type, devnum, dev->name, desc->uclass_id, desc->devnum);
135 		if (desc->devnum != devnum)
136 			continue;
137 
138 		/* Find out the parent device uclass */
139 		if (device_get_uclass_id(dev->parent) != uclass_id) {
140 			debug("%s: parent uclass %d, this dev %d\n", __func__,
141 			      device_get_uclass_id(dev->parent), uclass_id);
142 			continue;
143 		}
144 
145 		if (device_probe(dev))
146 			return NULL;
147 
148 		debug("%s: Device desc %p\n", __func__, desc);
149 		return desc;
150 	}
151 	debug("%s: No device found\n", __func__);
152 
153 	return NULL;
154 }
155 
156 /**
157  * blk_get_by_device() - Get the block device descriptor for the given device
158  * @dev:	Instance of a storage device
159  *
160  * Return: With block device descriptor on success , NULL if there is no such
161  *	   block device.
162  */
blk_get_by_device(struct udevice * dev)163 struct blk_desc *blk_get_by_device(struct udevice *dev)
164 {
165 	struct udevice *child_dev;
166 
167 	device_foreach_child(child_dev, dev) {
168 		if (device_get_uclass_id(child_dev) != UCLASS_BLK)
169 			continue;
170 
171 		return dev_get_uclass_plat(child_dev);
172 	}
173 
174 	debug("%s: No block device found\n", __func__);
175 
176 	return NULL;
177 }
178 
179 /**
180  * get_desc() - Get the block device descriptor for the given device number
181  *
182  * @uclass_id:	Interface type
183  * @devnum:	Device number (0 = first)
184  * @descp:	Returns block device descriptor on success
185  * Return: 0 on success, -ENODEV if there is no such device and no device
186  * with a higher device number, -ENOENT if there is no such device but there
187  * is one with a higher number, or other -ve on other error.
188  */
get_desc(enum uclass_id uclass_id,int devnum,struct blk_desc ** descp)189 static int get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
190 {
191 	bool found_more = false;
192 	struct udevice *dev;
193 	struct uclass *uc;
194 	int ret;
195 
196 	*descp = NULL;
197 	ret = uclass_get(UCLASS_BLK, &uc);
198 	if (ret)
199 		return ret;
200 	uclass_foreach_dev(dev, uc) {
201 		struct blk_desc *desc = dev_get_uclass_plat(dev);
202 
203 		debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
204 		      uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
205 		if (desc->uclass_id == uclass_id) {
206 			if (desc->devnum == devnum) {
207 				ret = device_probe(dev);
208 				if (ret)
209 					return ret;
210 
211 				*descp = desc;
212 				return 0;
213 			} else if (desc->devnum > devnum) {
214 				found_more = true;
215 			}
216 		}
217 	}
218 
219 	return found_more ? -ENOENT : -ENODEV;
220 }
221 
blk_select_hwpart_devnum(enum uclass_id uclass_id,int devnum,int hwpart)222 int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
223 {
224 	struct udevice *dev;
225 	int ret;
226 
227 	ret = blk_get_device(uclass_id, devnum, &dev);
228 	if (ret)
229 		return ret;
230 
231 	return blk_select_hwpart(dev, hwpart);
232 }
233 
blk_list_part(enum uclass_id uclass_id)234 int blk_list_part(enum uclass_id uclass_id)
235 {
236 	struct blk_desc *desc;
237 	int devnum, ok;
238 	int ret;
239 
240 	for (ok = 0, devnum = 0;; ++devnum) {
241 		ret = get_desc(uclass_id, devnum, &desc);
242 		if (ret == -ENODEV)
243 			break;
244 		else if (ret)
245 			continue;
246 		if (desc->part_type != PART_TYPE_UNKNOWN) {
247 			++ok;
248 			if (devnum)
249 				putc('\n');
250 			part_print(desc);
251 		}
252 	}
253 	if (!ok)
254 		return -ENODEV;
255 
256 	return 0;
257 }
258 
blk_print_part_devnum(enum uclass_id uclass_id,int devnum)259 int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
260 {
261 	struct blk_desc *desc;
262 	int ret;
263 
264 	ret = get_desc(uclass_id, devnum, &desc);
265 	if (ret)
266 		return ret;
267 	if (desc->type == DEV_TYPE_UNKNOWN)
268 		return -ENOENT;
269 	part_print(desc);
270 
271 	return 0;
272 }
273 
blk_list_devices(enum uclass_id uclass_id)274 void blk_list_devices(enum uclass_id uclass_id)
275 {
276 	struct blk_desc *desc;
277 	int ret;
278 	int i;
279 
280 	for (i = 0;; ++i) {
281 		ret = get_desc(uclass_id, i, &desc);
282 		if (ret == -ENODEV)
283 			break;
284 		else if (ret)
285 			continue;
286 		if (desc->type == DEV_TYPE_UNKNOWN)
287 			continue;  /* list only known devices */
288 		printf("Device %d: ", i);
289 		dev_print(desc);
290 	}
291 }
292 
blk_print_device_num(enum uclass_id uclass_id,int devnum)293 int blk_print_device_num(enum uclass_id uclass_id, int devnum)
294 {
295 	struct blk_desc *desc;
296 	int ret;
297 
298 	ret = get_desc(uclass_id, devnum, &desc);
299 	if (ret)
300 		return ret;
301 	printf("\nIDE device %d: ", devnum);
302 	dev_print(desc);
303 
304 	return 0;
305 }
306 
blk_show_device(enum uclass_id uclass_id,int devnum)307 int blk_show_device(enum uclass_id uclass_id, int devnum)
308 {
309 	struct blk_desc *desc;
310 	int ret;
311 
312 	printf("\nDevice %d: ", devnum);
313 	ret = get_desc(uclass_id, devnum, &desc);
314 	if (ret == -ENODEV || ret == -ENOENT) {
315 		printf("unknown device\n");
316 		return -ENODEV;
317 	}
318 	if (ret)
319 		return ret;
320 	dev_print(desc);
321 
322 	if (desc->type == DEV_TYPE_UNKNOWN)
323 		return -ENOENT;
324 
325 	return 0;
326 }
327 
blk_read_devnum(enum uclass_id uclass_id,int devnum,lbaint_t start,lbaint_t blkcnt,void * buffer)328 ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
329 		      lbaint_t blkcnt, void *buffer)
330 {
331 	struct blk_desc *desc;
332 	ulong n;
333 	int ret;
334 
335 	ret = get_desc(uclass_id, devnum, &desc);
336 	if (ret)
337 		return ret;
338 	n = blk_dread(desc, start, blkcnt, buffer);
339 	if (IS_ERR_VALUE(n))
340 		return n;
341 
342 	return n;
343 }
344 
blk_write_devnum(enum uclass_id uclass_id,int devnum,lbaint_t start,lbaint_t blkcnt,const void * buffer)345 ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
346 		       lbaint_t blkcnt, const void *buffer)
347 {
348 	struct blk_desc *desc;
349 	int ret;
350 
351 	ret = get_desc(uclass_id, devnum, &desc);
352 	if (ret)
353 		return ret;
354 	return blk_dwrite(desc, start, blkcnt, buffer);
355 }
356 
blk_select_hwpart(struct udevice * dev,int hwpart)357 int blk_select_hwpart(struct udevice *dev, int hwpart)
358 {
359 	const struct blk_ops *ops = blk_get_ops(dev);
360 
361 	if (!ops)
362 		return -ENOSYS;
363 	if (!ops->select_hwpart)
364 		return 0;
365 
366 	return ops->select_hwpart(dev, hwpart);
367 }
368 
blk_dselect_hwpart(struct blk_desc * desc,int hwpart)369 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
370 {
371 	return blk_select_hwpart(desc->bdev, hwpart);
372 }
373 
_blk_next_device(int uclass_id,struct udevice ** devp)374 static int _blk_next_device(int uclass_id, struct udevice **devp)
375 {
376 	struct blk_desc *desc;
377 	int ret = 0;
378 
379 	for (; *devp; uclass_find_next_device(devp)) {
380 		desc = dev_get_uclass_plat(*devp);
381 		if (desc->uclass_id == uclass_id) {
382 			ret = device_probe(*devp);
383 			if (!ret)
384 				return 0;
385 		}
386 	}
387 
388 	if (ret)
389 		return ret;
390 
391 	return -ENODEV;
392 }
393 
blk_first_device(int uclass_id,struct udevice ** devp)394 int blk_first_device(int uclass_id, struct udevice **devp)
395 {
396 	uclass_find_first_device(UCLASS_BLK, devp);
397 
398 	return _blk_next_device(uclass_id, devp);
399 }
400 
blk_next_device(struct udevice ** devp)401 int blk_next_device(struct udevice **devp)
402 {
403 	struct blk_desc *desc;
404 	int uclass_id;
405 
406 	desc = dev_get_uclass_plat(*devp);
407 	uclass_id = desc->uclass_id;
408 	uclass_find_next_device(devp);
409 
410 	return _blk_next_device(uclass_id, devp);
411 }
412 
blk_find_device(int uclass_id,int devnum,struct udevice ** devp)413 int blk_find_device(int uclass_id, int devnum, struct udevice **devp)
414 {
415 	struct uclass *uc;
416 	struct udevice *dev;
417 	int ret;
418 
419 	ret = uclass_get(UCLASS_BLK, &uc);
420 	if (ret)
421 		return ret;
422 	uclass_foreach_dev(dev, uc) {
423 		struct blk_desc *desc = dev_get_uclass_plat(dev);
424 
425 		debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
426 		      uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
427 		if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
428 			*devp = dev;
429 			return 0;
430 		}
431 	}
432 
433 	return -ENODEV;
434 }
435 
blk_get_device(int uclass_id,int devnum,struct udevice ** devp)436 int blk_get_device(int uclass_id, int devnum, struct udevice **devp)
437 {
438 	int ret;
439 
440 	ret = blk_find_device(uclass_id, devnum, devp);
441 	if (ret)
442 		return ret;
443 
444 	return device_probe(*devp);
445 }
446 
blk_read(struct udevice * dev,lbaint_t start,lbaint_t blkcnt,void * buf)447 long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
448 {
449 	struct blk_desc *desc = dev_get_uclass_plat(dev);
450 	const struct blk_ops *ops = blk_get_ops(dev);
451 	ulong blks_read;
452 
453 	if (!ops->read)
454 		return -ENOSYS;
455 
456 	if (blkcache_read(desc->uclass_id, desc->devnum,
457 			  start, blkcnt, desc->blksz, buf))
458 		return blkcnt;
459 	blks_read = ops->read(dev, start, blkcnt, buf);
460 	if (blks_read == blkcnt)
461 		blkcache_fill(desc->uclass_id, desc->devnum, start, blkcnt,
462 			      desc->blksz, buf);
463 
464 	return blks_read;
465 }
466 
blk_write(struct udevice * dev,lbaint_t start,lbaint_t blkcnt,const void * buf)467 long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
468 	       const void *buf)
469 {
470 	struct blk_desc *desc = dev_get_uclass_plat(dev);
471 	const struct blk_ops *ops = blk_get_ops(dev);
472 
473 	if (!ops->write)
474 		return -ENOSYS;
475 
476 	blkcache_invalidate(desc->uclass_id, desc->devnum);
477 
478 	return ops->write(dev, start, blkcnt, buf);
479 }
480 
blk_erase(struct udevice * dev,lbaint_t start,lbaint_t blkcnt)481 long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
482 {
483 	struct blk_desc *desc = dev_get_uclass_plat(dev);
484 	const struct blk_ops *ops = blk_get_ops(dev);
485 
486 	if (!ops->erase)
487 		return -ENOSYS;
488 
489 	blkcache_invalidate(desc->uclass_id, desc->devnum);
490 
491 	return ops->erase(dev, start, blkcnt);
492 }
493 
blk_dread(struct blk_desc * desc,lbaint_t start,lbaint_t blkcnt,void * buffer)494 ulong blk_dread(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
495 		void *buffer)
496 {
497 	return blk_read(desc->bdev, start, blkcnt, buffer);
498 }
499 
blk_dwrite(struct blk_desc * desc,lbaint_t start,lbaint_t blkcnt,const void * buffer)500 ulong blk_dwrite(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
501 		 const void *buffer)
502 {
503 	return blk_write(desc->bdev, start, blkcnt, buffer);
504 }
505 
blk_derase(struct blk_desc * desc,lbaint_t start,lbaint_t blkcnt)506 ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt)
507 {
508 	return blk_erase(desc->bdev, start, blkcnt);
509 }
510 
blk_find_from_parent(struct udevice * parent,struct udevice ** devp)511 int blk_find_from_parent(struct udevice *parent, struct udevice **devp)
512 {
513 	struct udevice *dev;
514 
515 	if (device_find_first_child_by_uclass(parent, UCLASS_BLK, &dev)) {
516 		debug("%s: No block device found for parent '%s'\n", __func__,
517 		      parent->name);
518 		return -ENODEV;
519 	}
520 	*devp = dev;
521 
522 	return 0;
523 }
524 
blk_get_from_parent(struct udevice * parent,struct udevice ** devp)525 int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
526 {
527 	struct udevice *dev;
528 	int ret;
529 
530 	ret = blk_find_from_parent(parent, &dev);
531 	if (ret)
532 		return ret;
533 	ret = device_probe(dev);
534 	if (ret)
535 		return ret;
536 	*devp = dev;
537 
538 	return 0;
539 }
540 
blk_get_devtype(struct udevice * dev)541 const char *blk_get_devtype(struct udevice *dev)
542 {
543 	struct udevice *parent = dev_get_parent(dev);
544 
545 	return uclass_get_name(device_get_uclass_id(parent));
546 };
547 
blk_find_max_devnum(enum uclass_id uclass_id)548 int blk_find_max_devnum(enum uclass_id uclass_id)
549 {
550 	struct udevice *dev;
551 	int max_devnum = -ENODEV;
552 	struct uclass *uc;
553 	int ret;
554 
555 	ret = uclass_get(UCLASS_BLK, &uc);
556 	if (ret)
557 		return ret;
558 	uclass_foreach_dev(dev, uc) {
559 		struct blk_desc *desc = dev_get_uclass_plat(dev);
560 
561 		if (desc->uclass_id == uclass_id && desc->devnum > max_devnum)
562 			max_devnum = desc->devnum;
563 	}
564 
565 	return max_devnum;
566 }
567 
blk_next_free_devnum(enum uclass_id uclass_id)568 int blk_next_free_devnum(enum uclass_id uclass_id)
569 {
570 	int ret;
571 
572 	ret = blk_find_max_devnum(uclass_id);
573 	if (ret == -ENODEV)
574 		return 0;
575 	if (ret < 0)
576 		return ret;
577 
578 	return ret + 1;
579 }
580 
blk_flags_check(struct udevice * dev,enum blk_flag_t req_flags)581 static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
582 {
583 	const struct blk_desc *desc = dev_get_uclass_plat(dev);
584 	enum blk_flag_t flags;
585 
586 	flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
587 
588 	return flags & req_flags ? 0 : 1;
589 }
590 
blk_find_first(enum blk_flag_t flags,struct udevice ** devp)591 int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
592 {
593 	int ret;
594 
595 	for (ret = uclass_find_first_device(UCLASS_BLK, devp);
596 	     *devp && !blk_flags_check(*devp, flags);
597 	     ret = uclass_find_next_device(devp))
598 		return 0;
599 
600 	return -ENODEV;
601 }
602 
blk_find_next(enum blk_flag_t flags,struct udevice ** devp)603 int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
604 {
605 	int ret;
606 
607 	for (ret = uclass_find_next_device(devp);
608 	     *devp && !blk_flags_check(*devp, flags);
609 	     ret = uclass_find_next_device(devp))
610 		return 0;
611 
612 	return -ENODEV;
613 }
614 
blk_first_device_err(enum blk_flag_t flags,struct udevice ** devp)615 int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
616 {
617 	for (uclass_first_device(UCLASS_BLK, devp);
618 	     *devp;
619 	     uclass_next_device(devp)) {
620 		if (!blk_flags_check(*devp, flags))
621 			return 0;
622 	}
623 
624 	return -ENODEV;
625 }
626 
blk_next_device_err(enum blk_flag_t flags,struct udevice ** devp)627 int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
628 {
629 	for (uclass_next_device(devp);
630 	     *devp;
631 	     uclass_next_device(devp)) {
632 		if (!blk_flags_check(*devp, flags))
633 			return 0;
634 	}
635 
636 	return -ENODEV;
637 }
638 
blk_count_devices(enum blk_flag_t flag)639 int blk_count_devices(enum blk_flag_t flag)
640 {
641 	struct udevice *dev;
642 	int count = 0;
643 
644 	blk_foreach_probe(flag, dev)
645 		count++;
646 
647 	return count;
648 }
649 
blk_claim_devnum(enum uclass_id uclass_id,int devnum)650 static int blk_claim_devnum(enum uclass_id uclass_id, int devnum)
651 {
652 	struct udevice *dev;
653 	struct uclass *uc;
654 	int ret;
655 
656 	ret = uclass_get(UCLASS_BLK, &uc);
657 	if (ret)
658 		return ret;
659 	uclass_foreach_dev(dev, uc) {
660 		struct blk_desc *desc = dev_get_uclass_plat(dev);
661 
662 		if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
663 			int next = blk_next_free_devnum(uclass_id);
664 
665 			if (next < 0)
666 				return next;
667 			desc->devnum = next;
668 			return 0;
669 		}
670 	}
671 
672 	return -ENOENT;
673 }
674 
blk_create_device(struct udevice * parent,const char * drv_name,const char * name,int uclass_id,int devnum,int blksz,lbaint_t lba,struct udevice ** devp)675 int blk_create_device(struct udevice *parent, const char *drv_name,
676 		      const char *name, int uclass_id, int devnum, int blksz,
677 		      lbaint_t lba, struct udevice **devp)
678 {
679 	struct blk_desc *desc;
680 	struct udevice *dev;
681 	int ret;
682 
683 	if (devnum == -1) {
684 		devnum = blk_next_free_devnum(uclass_id);
685 	} else {
686 		ret = blk_claim_devnum(uclass_id, devnum);
687 		if (ret < 0 && ret != -ENOENT)
688 			return ret;
689 	}
690 	if (devnum < 0)
691 		return devnum;
692 	ret = device_bind_driver(parent, drv_name, name, &dev);
693 	if (ret)
694 		return ret;
695 	desc = dev_get_uclass_plat(dev);
696 	desc->uclass_id = uclass_id;
697 	desc->blksz = blksz;
698 	desc->log2blksz = LOG2(desc->blksz);
699 	desc->lba = lba;
700 	desc->part_type = PART_TYPE_UNKNOWN;
701 	desc->bdev = dev;
702 	desc->devnum = devnum;
703 	*devp = dev;
704 
705 	return 0;
706 }
707 
blk_create_devicef(struct udevice * parent,const char * drv_name,const char * name,int uclass_id,int devnum,int blksz,lbaint_t lba,struct udevice ** devp)708 int blk_create_devicef(struct udevice *parent, const char *drv_name,
709 		       const char *name, int uclass_id, int devnum, int blksz,
710 		       lbaint_t lba, struct udevice **devp)
711 {
712 	char dev_name[30], *str;
713 	int ret;
714 
715 	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
716 	str = strdup(dev_name);
717 	if (!str)
718 		return -ENOMEM;
719 
720 	ret = blk_create_device(parent, drv_name, str, uclass_id, devnum,
721 				blksz, lba, devp);
722 	if (ret) {
723 		free(str);
724 		return ret;
725 	}
726 	device_set_name_alloced(*devp);
727 
728 	return 0;
729 }
730 
blk_probe_or_unbind(struct udevice * dev)731 int blk_probe_or_unbind(struct udevice *dev)
732 {
733 	int ret;
734 
735 	ret = device_probe(dev);
736 	if (ret) {
737 		log_debug("probing %s failed\n", dev->name);
738 		device_unbind(dev);
739 	}
740 
741 	return ret;
742 }
743 
blk_unbind_all(int uclass_id)744 int blk_unbind_all(int uclass_id)
745 {
746 	struct uclass *uc;
747 	struct udevice *dev, *next;
748 	int ret;
749 
750 	ret = uclass_get(UCLASS_BLK, &uc);
751 	if (ret)
752 		return ret;
753 	uclass_foreach_dev_safe(dev, next, uc) {
754 		struct blk_desc *desc = dev_get_uclass_plat(dev);
755 
756 		if (desc->uclass_id == uclass_id) {
757 			ret = device_remove(dev, DM_REMOVE_NORMAL);
758 			if (ret)
759 				return ret;
760 			ret = device_unbind(dev);
761 			if (ret)
762 				return ret;
763 		}
764 	}
765 
766 	return 0;
767 }
768 
blk_post_probe(struct udevice * dev)769 static int blk_post_probe(struct udevice *dev)
770 {
771 	if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
772 		struct blk_desc *desc = dev_get_uclass_plat(dev);
773 
774 		part_init(desc);
775 
776 		if (desc->part_type != PART_TYPE_UNKNOWN &&
777 		    part_create_block_devices(dev))
778 			debug("*** creating partitions failed\n");
779 	}
780 
781 	return 0;
782 }
783 
784 UCLASS_DRIVER(blk) = {
785 	.id		= UCLASS_BLK,
786 	.name		= "blk",
787 	.post_probe	= blk_post_probe,
788 	.per_device_plat_auto	= sizeof(struct blk_desc),
789 };
790