xref: /openbmc/u-boot/drivers/block/blk-uclass.c (revision 0f347a00)
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 #include <common.h>
8 #include <blk.h>
9 #include <dm.h>
10 #include <dm/device-internal.h>
11 #include <dm/lists.h>
12 #include <dm/uclass-internal.h>
13 
14 static const char *if_typename_str[IF_TYPE_COUNT] = {
15 	[IF_TYPE_IDE]		= "ide",
16 	[IF_TYPE_SCSI]		= "scsi",
17 	[IF_TYPE_ATAPI]		= "atapi",
18 	[IF_TYPE_USB]		= "usb",
19 	[IF_TYPE_DOC]		= "doc",
20 	[IF_TYPE_MMC]		= "mmc",
21 	[IF_TYPE_SD]		= "sd",
22 	[IF_TYPE_SATA]		= "sata",
23 	[IF_TYPE_HOST]		= "host",
24 	[IF_TYPE_NVME]		= "nvme",
25 	[IF_TYPE_EFI]		= "efi",
26 };
27 
28 static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
29 	[IF_TYPE_IDE]		= UCLASS_IDE,
30 	[IF_TYPE_SCSI]		= UCLASS_SCSI,
31 	[IF_TYPE_ATAPI]		= UCLASS_INVALID,
32 	[IF_TYPE_USB]		= UCLASS_MASS_STORAGE,
33 	[IF_TYPE_DOC]		= UCLASS_INVALID,
34 	[IF_TYPE_MMC]		= UCLASS_MMC,
35 	[IF_TYPE_SD]		= UCLASS_INVALID,
36 	[IF_TYPE_SATA]		= UCLASS_AHCI,
37 	[IF_TYPE_HOST]		= UCLASS_ROOT,
38 	[IF_TYPE_NVME]		= UCLASS_NVME,
39 	[IF_TYPE_EFI]		= UCLASS_EFI,
40 };
41 
42 static enum if_type if_typename_to_iftype(const char *if_typename)
43 {
44 	int i;
45 
46 	for (i = 0; i < IF_TYPE_COUNT; i++) {
47 		if (if_typename_str[i] &&
48 		    !strcmp(if_typename, if_typename_str[i]))
49 			return i;
50 	}
51 
52 	return IF_TYPE_UNKNOWN;
53 }
54 
55 static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
56 {
57 	return if_type_uclass_id[if_type];
58 }
59 
60 const char *blk_get_if_type_name(enum if_type if_type)
61 {
62 	return if_typename_str[if_type];
63 }
64 
65 struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
66 {
67 	struct blk_desc *desc;
68 	struct udevice *dev;
69 	int ret;
70 
71 	ret = blk_get_device(if_type, devnum, &dev);
72 	if (ret)
73 		return NULL;
74 	desc = dev_get_uclass_platdata(dev);
75 
76 	return desc;
77 }
78 
79 /*
80  * This function is complicated with driver model. We look up the interface
81  * name in a local table. This gives us an interface type which we can match
82  * against the uclass of the block device's parent.
83  */
84 struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
85 {
86 	enum uclass_id uclass_id;
87 	enum if_type if_type;
88 	struct udevice *dev;
89 	struct uclass *uc;
90 	int ret;
91 
92 	if_type = if_typename_to_iftype(if_typename);
93 	if (if_type == IF_TYPE_UNKNOWN) {
94 		debug("%s: Unknown interface type '%s'\n", __func__,
95 		      if_typename);
96 		return NULL;
97 	}
98 	uclass_id = if_type_to_uclass_id(if_type);
99 	if (uclass_id == UCLASS_INVALID) {
100 		debug("%s: Unknown uclass for interface type'\n",
101 		      if_typename_str[if_type]);
102 		return NULL;
103 	}
104 
105 	ret = uclass_get(UCLASS_BLK, &uc);
106 	if (ret)
107 		return NULL;
108 	uclass_foreach_dev(dev, uc) {
109 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
110 
111 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
112 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
113 		if (desc->devnum != devnum)
114 			continue;
115 
116 		/* Find out the parent device uclass */
117 		if (device_get_uclass_id(dev->parent) != uclass_id) {
118 			debug("%s: parent uclass %d, this dev %d\n", __func__,
119 			      device_get_uclass_id(dev->parent), uclass_id);
120 			continue;
121 		}
122 
123 		if (device_probe(dev))
124 			return NULL;
125 
126 		debug("%s: Device desc %p\n", __func__, desc);
127 		return desc;
128 	}
129 	debug("%s: No device found\n", __func__);
130 
131 	return NULL;
132 }
133 
134 /**
135  * blk_get_by_device() - Get the block device descriptor for the given device
136  * @dev:	Instance of a storage device
137  *
138  * Return: With block device descriptor on success , NULL if there is no such
139  *	   block device.
140  */
141 struct blk_desc *blk_get_by_device(struct udevice *dev)
142 {
143 	struct udevice *child_dev, *next;
144 
145 	device_foreach_child_safe(child_dev, next, dev) {
146 		if (device_get_uclass_id(child_dev) != UCLASS_BLK)
147 			continue;
148 
149 		return dev_get_uclass_platdata(child_dev);
150 	}
151 
152 	debug("%s: No block device found\n", __func__);
153 
154 	return NULL;
155 }
156 
157 /**
158  * get_desc() - Get the block device descriptor for the given device number
159  *
160  * @if_type:	Interface type
161  * @devnum:	Device number (0 = first)
162  * @descp:	Returns block device descriptor on success
163  * @return 0 on success, -ENODEV if there is no such device and no device
164  * with a higher device number, -ENOENT if there is no such device but there
165  * is one with a higher number, or other -ve on other error.
166  */
167 static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
168 {
169 	bool found_more = false;
170 	struct udevice *dev;
171 	struct uclass *uc;
172 	int ret;
173 
174 	*descp = NULL;
175 	ret = uclass_get(UCLASS_BLK, &uc);
176 	if (ret)
177 		return ret;
178 	uclass_foreach_dev(dev, uc) {
179 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
180 
181 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
182 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
183 		if (desc->if_type == if_type) {
184 			if (desc->devnum == devnum) {
185 				ret = device_probe(dev);
186 				if (ret)
187 					return ret;
188 
189 				*descp = desc;
190 				return 0;
191 			} else if (desc->devnum > devnum) {
192 				found_more = true;
193 			}
194 		}
195 	}
196 
197 	return found_more ? -ENOENT : -ENODEV;
198 }
199 
200 int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
201 {
202 	struct udevice *dev;
203 	int ret;
204 
205 	ret = blk_get_device(if_type, devnum, &dev);
206 	if (ret)
207 		return ret;
208 
209 	return blk_select_hwpart(dev, hwpart);
210 }
211 
212 int blk_list_part(enum if_type if_type)
213 {
214 	struct blk_desc *desc;
215 	int devnum, ok;
216 	int ret;
217 
218 	for (ok = 0, devnum = 0;; ++devnum) {
219 		ret = get_desc(if_type, devnum, &desc);
220 		if (ret == -ENODEV)
221 			break;
222 		else if (ret)
223 			continue;
224 		if (desc->part_type != PART_TYPE_UNKNOWN) {
225 			++ok;
226 			if (devnum)
227 				putc('\n');
228 			part_print(desc);
229 		}
230 	}
231 	if (!ok)
232 		return -ENODEV;
233 
234 	return 0;
235 }
236 
237 int blk_print_part_devnum(enum if_type if_type, int devnum)
238 {
239 	struct blk_desc *desc;
240 	int ret;
241 
242 	ret = get_desc(if_type, devnum, &desc);
243 	if (ret)
244 		return ret;
245 	if (desc->type == DEV_TYPE_UNKNOWN)
246 		return -ENOENT;
247 	part_print(desc);
248 
249 	return 0;
250 }
251 
252 void blk_list_devices(enum if_type if_type)
253 {
254 	struct blk_desc *desc;
255 	int ret;
256 	int i;
257 
258 	for (i = 0;; ++i) {
259 		ret = get_desc(if_type, i, &desc);
260 		if (ret == -ENODEV)
261 			break;
262 		else if (ret)
263 			continue;
264 		if (desc->type == DEV_TYPE_UNKNOWN)
265 			continue;  /* list only known devices */
266 		printf("Device %d: ", i);
267 		dev_print(desc);
268 	}
269 }
270 
271 int blk_print_device_num(enum if_type if_type, int devnum)
272 {
273 	struct blk_desc *desc;
274 	int ret;
275 
276 	ret = get_desc(if_type, devnum, &desc);
277 	if (ret)
278 		return ret;
279 	printf("\nIDE device %d: ", devnum);
280 	dev_print(desc);
281 
282 	return 0;
283 }
284 
285 int blk_show_device(enum if_type if_type, int devnum)
286 {
287 	struct blk_desc *desc;
288 	int ret;
289 
290 	printf("\nDevice %d: ", devnum);
291 	ret = get_desc(if_type, devnum, &desc);
292 	if (ret == -ENODEV || ret == -ENOENT) {
293 		printf("unknown device\n");
294 		return -ENODEV;
295 	}
296 	if (ret)
297 		return ret;
298 	dev_print(desc);
299 
300 	if (desc->type == DEV_TYPE_UNKNOWN)
301 		return -ENOENT;
302 
303 	return 0;
304 }
305 
306 ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
307 		      lbaint_t blkcnt, void *buffer)
308 {
309 	struct blk_desc *desc;
310 	ulong n;
311 	int ret;
312 
313 	ret = get_desc(if_type, devnum, &desc);
314 	if (ret)
315 		return ret;
316 	n = blk_dread(desc, start, blkcnt, buffer);
317 	if (IS_ERR_VALUE(n))
318 		return n;
319 
320 	return n;
321 }
322 
323 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
324 		       lbaint_t blkcnt, const void *buffer)
325 {
326 	struct blk_desc *desc;
327 	int ret;
328 
329 	ret = get_desc(if_type, devnum, &desc);
330 	if (ret)
331 		return ret;
332 	return blk_dwrite(desc, start, blkcnt, buffer);
333 }
334 
335 int blk_select_hwpart(struct udevice *dev, int hwpart)
336 {
337 	const struct blk_ops *ops = blk_get_ops(dev);
338 
339 	if (!ops)
340 		return -ENOSYS;
341 	if (!ops->select_hwpart)
342 		return 0;
343 
344 	return ops->select_hwpart(dev, hwpart);
345 }
346 
347 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
348 {
349 	return blk_select_hwpart(desc->bdev, hwpart);
350 }
351 
352 int blk_first_device(int if_type, struct udevice **devp)
353 {
354 	struct blk_desc *desc;
355 	int ret;
356 
357 	ret = uclass_find_first_device(UCLASS_BLK, devp);
358 	if (ret)
359 		return ret;
360 	if (!*devp)
361 		return -ENODEV;
362 	do {
363 		desc = dev_get_uclass_platdata(*devp);
364 		if (desc->if_type == if_type)
365 			return 0;
366 		ret = uclass_find_next_device(devp);
367 		if (ret)
368 			return ret;
369 	} while (*devp);
370 
371 	return -ENODEV;
372 }
373 
374 int blk_next_device(struct udevice **devp)
375 {
376 	struct blk_desc *desc;
377 	int ret, if_type;
378 
379 	desc = dev_get_uclass_platdata(*devp);
380 	if_type = desc->if_type;
381 	do {
382 		ret = uclass_find_next_device(devp);
383 		if (ret)
384 			return ret;
385 		if (!*devp)
386 			return -ENODEV;
387 		desc = dev_get_uclass_platdata(*devp);
388 		if (desc->if_type == if_type)
389 			return 0;
390 	} while (1);
391 }
392 
393 int blk_find_device(int if_type, int devnum, struct udevice **devp)
394 {
395 	struct uclass *uc;
396 	struct udevice *dev;
397 	int ret;
398 
399 	ret = uclass_get(UCLASS_BLK, &uc);
400 	if (ret)
401 		return ret;
402 	uclass_foreach_dev(dev, uc) {
403 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
404 
405 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
406 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
407 		if (desc->if_type == if_type && desc->devnum == devnum) {
408 			*devp = dev;
409 			return 0;
410 		}
411 	}
412 
413 	return -ENODEV;
414 }
415 
416 int blk_get_device(int if_type, int devnum, struct udevice **devp)
417 {
418 	int ret;
419 
420 	ret = blk_find_device(if_type, devnum, devp);
421 	if (ret)
422 		return ret;
423 
424 	return device_probe(*devp);
425 }
426 
427 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
428 			lbaint_t blkcnt, void *buffer)
429 {
430 	struct udevice *dev = block_dev->bdev;
431 	const struct blk_ops *ops = blk_get_ops(dev);
432 	ulong blks_read;
433 
434 	if (!ops->read)
435 		return -ENOSYS;
436 
437 	if (blkcache_read(block_dev->if_type, block_dev->devnum,
438 			  start, blkcnt, block_dev->blksz, buffer))
439 		return blkcnt;
440 	blks_read = ops->read(dev, start, blkcnt, buffer);
441 	if (blks_read == blkcnt)
442 		blkcache_fill(block_dev->if_type, block_dev->devnum,
443 			      start, blkcnt, block_dev->blksz, buffer);
444 
445 	return blks_read;
446 }
447 
448 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
449 			 lbaint_t blkcnt, const void *buffer)
450 {
451 	struct udevice *dev = block_dev->bdev;
452 	const struct blk_ops *ops = blk_get_ops(dev);
453 
454 	if (!ops->write)
455 		return -ENOSYS;
456 
457 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
458 	return ops->write(dev, start, blkcnt, buffer);
459 }
460 
461 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
462 			 lbaint_t blkcnt)
463 {
464 	struct udevice *dev = block_dev->bdev;
465 	const struct blk_ops *ops = blk_get_ops(dev);
466 
467 	if (!ops->erase)
468 		return -ENOSYS;
469 
470 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
471 	return ops->erase(dev, start, blkcnt);
472 }
473 
474 int blk_prepare_device(struct udevice *dev)
475 {
476 	struct blk_desc *desc = dev_get_uclass_platdata(dev);
477 
478 	part_init(desc);
479 
480 	return 0;
481 }
482 
483 int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
484 {
485 	struct udevice *dev;
486 	enum uclass_id id;
487 	int ret;
488 
489 	device_find_first_child(parent, &dev);
490 	if (!dev) {
491 		debug("%s: No block device found for parent '%s'\n", __func__,
492 		      parent->name);
493 		return -ENODEV;
494 	}
495 	id = device_get_uclass_id(dev);
496 	if (id != UCLASS_BLK) {
497 		debug("%s: Incorrect uclass %s for block device '%s'\n",
498 		      __func__, uclass_get_name(id), dev->name);
499 		return -ENOTBLK;
500 	}
501 	ret = device_probe(dev);
502 	if (ret)
503 		return ret;
504 	*devp = dev;
505 
506 	return 0;
507 }
508 
509 int blk_find_max_devnum(enum if_type if_type)
510 {
511 	struct udevice *dev;
512 	int max_devnum = -ENODEV;
513 	struct uclass *uc;
514 	int ret;
515 
516 	ret = uclass_get(UCLASS_BLK, &uc);
517 	if (ret)
518 		return ret;
519 	uclass_foreach_dev(dev, uc) {
520 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
521 
522 		if (desc->if_type == if_type && desc->devnum > max_devnum)
523 			max_devnum = desc->devnum;
524 	}
525 
526 	return max_devnum;
527 }
528 
529 static int blk_next_free_devnum(enum if_type if_type)
530 {
531 	int ret;
532 
533 	ret = blk_find_max_devnum(if_type);
534 	if (ret == -ENODEV)
535 		return 0;
536 	if (ret < 0)
537 		return ret;
538 
539 	return ret + 1;
540 }
541 
542 static int blk_claim_devnum(enum if_type if_type, int devnum)
543 {
544 	struct udevice *dev;
545 	struct uclass *uc;
546 	int ret;
547 
548 	ret = uclass_get(UCLASS_BLK, &uc);
549 	if (ret)
550 		return ret;
551 	uclass_foreach_dev(dev, uc) {
552 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
553 
554 		if (desc->if_type == if_type && desc->devnum == devnum) {
555 			int next = blk_next_free_devnum(if_type);
556 
557 			if (next < 0)
558 				return next;
559 			desc->devnum = next;
560 			return 0;
561 		}
562 	}
563 
564 	return -ENOENT;
565 }
566 
567 int blk_create_device(struct udevice *parent, const char *drv_name,
568 		      const char *name, int if_type, int devnum, int blksz,
569 		      lbaint_t lba, struct udevice **devp)
570 {
571 	struct blk_desc *desc;
572 	struct udevice *dev;
573 	int ret;
574 
575 	if (devnum == -1) {
576 		devnum = blk_next_free_devnum(if_type);
577 	} else {
578 		ret = blk_claim_devnum(if_type, devnum);
579 		if (ret < 0 && ret != -ENOENT)
580 			return ret;
581 	}
582 	if (devnum < 0)
583 		return devnum;
584 	ret = device_bind_driver(parent, drv_name, name, &dev);
585 	if (ret)
586 		return ret;
587 	desc = dev_get_uclass_platdata(dev);
588 	desc->if_type = if_type;
589 	desc->blksz = blksz;
590 	desc->lba = lba;
591 	desc->part_type = PART_TYPE_UNKNOWN;
592 	desc->bdev = dev;
593 	desc->devnum = devnum;
594 	*devp = dev;
595 
596 	return 0;
597 }
598 
599 int blk_create_devicef(struct udevice *parent, const char *drv_name,
600 		       const char *name, int if_type, int devnum, int blksz,
601 		       lbaint_t lba, struct udevice **devp)
602 {
603 	char dev_name[30], *str;
604 	int ret;
605 
606 	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
607 	str = strdup(dev_name);
608 	if (!str)
609 		return -ENOMEM;
610 
611 	ret = blk_create_device(parent, drv_name, str, if_type, devnum,
612 				blksz, lba, devp);
613 	if (ret) {
614 		free(str);
615 		return ret;
616 	}
617 	device_set_name_alloced(*devp);
618 
619 	return 0;
620 }
621 
622 int blk_unbind_all(int if_type)
623 {
624 	struct uclass *uc;
625 	struct udevice *dev, *next;
626 	int ret;
627 
628 	ret = uclass_get(UCLASS_BLK, &uc);
629 	if (ret)
630 		return ret;
631 	uclass_foreach_dev_safe(dev, next, uc) {
632 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
633 
634 		if (desc->if_type == if_type) {
635 			ret = device_remove(dev, DM_REMOVE_NORMAL);
636 			if (ret)
637 				return ret;
638 			ret = device_unbind(dev);
639 			if (ret)
640 				return ret;
641 		}
642 	}
643 
644 	return 0;
645 }
646 
647 UCLASS_DRIVER(blk) = {
648 	.id		= UCLASS_BLK,
649 	.name		= "blk",
650 	.per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
651 };
652