xref: /openbmc/u-boot/drivers/block/blk-uclass.c (revision 014a953c)
1 /*
2  * Copyright (C) 2016 Google, Inc
3  * Written by Simon Glass <sjg@chromium.org>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <blk.h>
10 #include <dm.h>
11 #include <dm/device-internal.h>
12 #include <dm/lists.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_SYSTEMACE]	= "ace",
25 	[IF_TYPE_NVME]		= "nvme",
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_SYSTEMACE]	= UCLASS_INVALID,
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  * get_desc() - Get the block device descriptor for the given device number
136  *
137  * @if_type:	Interface type
138  * @devnum:	Device number (0 = first)
139  * @descp:	Returns block device descriptor on success
140  * @return 0 on success, -ENODEV if there is no such device and no device
141  * with a higher device number, -ENOENT if there is no such device but there
142  * is one with a higher number, or other -ve on other error.
143  */
144 static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
145 {
146 	bool found_more = false;
147 	struct udevice *dev;
148 	struct uclass *uc;
149 	int ret;
150 
151 	*descp = NULL;
152 	ret = uclass_get(UCLASS_BLK, &uc);
153 	if (ret)
154 		return ret;
155 	uclass_foreach_dev(dev, uc) {
156 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
157 
158 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
159 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
160 		if (desc->if_type == if_type) {
161 			if (desc->devnum == devnum) {
162 				ret = device_probe(dev);
163 				if (ret)
164 					return ret;
165 
166 				*descp = desc;
167 				return 0;
168 			} else if (desc->devnum > devnum) {
169 				found_more = true;
170 			}
171 		}
172 	}
173 
174 	return found_more ? -ENOENT : -ENODEV;
175 }
176 
177 int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
178 {
179 	struct udevice *dev;
180 	int ret;
181 
182 	ret = blk_get_device(if_type, devnum, &dev);
183 	if (ret)
184 		return ret;
185 
186 	return blk_select_hwpart(dev, hwpart);
187 }
188 
189 int blk_list_part(enum if_type if_type)
190 {
191 	struct blk_desc *desc;
192 	int devnum, ok;
193 	int ret;
194 
195 	for (ok = 0, devnum = 0;; ++devnum) {
196 		ret = get_desc(if_type, devnum, &desc);
197 		if (ret == -ENODEV)
198 			break;
199 		else if (ret)
200 			continue;
201 		if (desc->part_type != PART_TYPE_UNKNOWN) {
202 			++ok;
203 			if (devnum)
204 				putc('\n');
205 			part_print(desc);
206 		}
207 	}
208 	if (!ok)
209 		return -ENODEV;
210 
211 	return 0;
212 }
213 
214 int blk_print_part_devnum(enum if_type if_type, int devnum)
215 {
216 	struct blk_desc *desc;
217 	int ret;
218 
219 	ret = get_desc(if_type, devnum, &desc);
220 	if (ret)
221 		return ret;
222 	if (desc->type == DEV_TYPE_UNKNOWN)
223 		return -ENOENT;
224 	part_print(desc);
225 
226 	return 0;
227 }
228 
229 void blk_list_devices(enum if_type if_type)
230 {
231 	struct blk_desc *desc;
232 	int ret;
233 	int i;
234 
235 	for (i = 0;; ++i) {
236 		ret = get_desc(if_type, i, &desc);
237 		if (ret == -ENODEV)
238 			break;
239 		else if (ret)
240 			continue;
241 		if (desc->type == DEV_TYPE_UNKNOWN)
242 			continue;  /* list only known devices */
243 		printf("Device %d: ", i);
244 		dev_print(desc);
245 	}
246 }
247 
248 int blk_print_device_num(enum if_type if_type, int devnum)
249 {
250 	struct blk_desc *desc;
251 	int ret;
252 
253 	ret = get_desc(if_type, devnum, &desc);
254 	if (ret)
255 		return ret;
256 	printf("\nIDE device %d: ", devnum);
257 	dev_print(desc);
258 
259 	return 0;
260 }
261 
262 int blk_show_device(enum if_type if_type, int devnum)
263 {
264 	struct blk_desc *desc;
265 	int ret;
266 
267 	printf("\nDevice %d: ", devnum);
268 	ret = get_desc(if_type, devnum, &desc);
269 	if (ret == -ENODEV || ret == -ENOENT) {
270 		printf("unknown device\n");
271 		return -ENODEV;
272 	}
273 	if (ret)
274 		return ret;
275 	dev_print(desc);
276 
277 	if (desc->type == DEV_TYPE_UNKNOWN)
278 		return -ENOENT;
279 
280 	return 0;
281 }
282 
283 ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
284 		      lbaint_t blkcnt, void *buffer)
285 {
286 	struct blk_desc *desc;
287 	ulong n;
288 	int ret;
289 
290 	ret = get_desc(if_type, devnum, &desc);
291 	if (ret)
292 		return ret;
293 	n = blk_dread(desc, start, blkcnt, buffer);
294 	if (IS_ERR_VALUE(n))
295 		return n;
296 
297 	return n;
298 }
299 
300 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
301 		       lbaint_t blkcnt, const void *buffer)
302 {
303 	struct blk_desc *desc;
304 	int ret;
305 
306 	ret = get_desc(if_type, devnum, &desc);
307 	if (ret)
308 		return ret;
309 	return blk_dwrite(desc, start, blkcnt, buffer);
310 }
311 
312 int blk_select_hwpart(struct udevice *dev, int hwpart)
313 {
314 	const struct blk_ops *ops = blk_get_ops(dev);
315 
316 	if (!ops)
317 		return -ENOSYS;
318 	if (!ops->select_hwpart)
319 		return 0;
320 
321 	return ops->select_hwpart(dev, hwpart);
322 }
323 
324 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
325 {
326 	return blk_select_hwpart(desc->bdev, hwpart);
327 }
328 
329 int blk_first_device(int if_type, struct udevice **devp)
330 {
331 	struct blk_desc *desc;
332 	int ret;
333 
334 	ret = uclass_first_device(UCLASS_BLK, devp);
335 	if (ret)
336 		return ret;
337 	if (!*devp)
338 		return -ENODEV;
339 	do {
340 		desc = dev_get_uclass_platdata(*devp);
341 		if (desc->if_type == if_type)
342 			return 0;
343 		ret = uclass_next_device(devp);
344 		if (ret)
345 			return ret;
346 	} while (*devp);
347 
348 	return -ENODEV;
349 }
350 
351 int blk_next_device(struct udevice **devp)
352 {
353 	struct blk_desc *desc;
354 	int ret, if_type;
355 
356 	desc = dev_get_uclass_platdata(*devp);
357 	if_type = desc->if_type;
358 	do {
359 		ret = uclass_next_device(devp);
360 		if (ret)
361 			return ret;
362 		if (!*devp)
363 			return -ENODEV;
364 		desc = dev_get_uclass_platdata(*devp);
365 		if (desc->if_type == if_type)
366 			return 0;
367 	} while (1);
368 }
369 
370 int blk_find_device(int if_type, int devnum, struct udevice **devp)
371 {
372 	struct uclass *uc;
373 	struct udevice *dev;
374 	int ret;
375 
376 	ret = uclass_get(UCLASS_BLK, &uc);
377 	if (ret)
378 		return ret;
379 	uclass_foreach_dev(dev, uc) {
380 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
381 
382 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
383 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
384 		if (desc->if_type == if_type && desc->devnum == devnum) {
385 			*devp = dev;
386 			return 0;
387 		}
388 	}
389 
390 	return -ENODEV;
391 }
392 
393 int blk_get_device(int if_type, int devnum, struct udevice **devp)
394 {
395 	int ret;
396 
397 	ret = blk_find_device(if_type, devnum, devp);
398 	if (ret)
399 		return ret;
400 
401 	return device_probe(*devp);
402 }
403 
404 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
405 			lbaint_t blkcnt, void *buffer)
406 {
407 	struct udevice *dev = block_dev->bdev;
408 	const struct blk_ops *ops = blk_get_ops(dev);
409 	ulong blks_read;
410 
411 	if (!ops->read)
412 		return -ENOSYS;
413 
414 	if (blkcache_read(block_dev->if_type, block_dev->devnum,
415 			  start, blkcnt, block_dev->blksz, buffer))
416 		return blkcnt;
417 	blks_read = ops->read(dev, start, blkcnt, buffer);
418 	if (blks_read == blkcnt)
419 		blkcache_fill(block_dev->if_type, block_dev->devnum,
420 			      start, blkcnt, block_dev->blksz, buffer);
421 
422 	return blks_read;
423 }
424 
425 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
426 			 lbaint_t blkcnt, const void *buffer)
427 {
428 	struct udevice *dev = block_dev->bdev;
429 	const struct blk_ops *ops = blk_get_ops(dev);
430 
431 	if (!ops->write)
432 		return -ENOSYS;
433 
434 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
435 	return ops->write(dev, start, blkcnt, buffer);
436 }
437 
438 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
439 			 lbaint_t blkcnt)
440 {
441 	struct udevice *dev = block_dev->bdev;
442 	const struct blk_ops *ops = blk_get_ops(dev);
443 
444 	if (!ops->erase)
445 		return -ENOSYS;
446 
447 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
448 	return ops->erase(dev, start, blkcnt);
449 }
450 
451 int blk_prepare_device(struct udevice *dev)
452 {
453 	struct blk_desc *desc = dev_get_uclass_platdata(dev);
454 
455 	part_init(desc);
456 
457 	return 0;
458 }
459 
460 int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
461 {
462 	struct udevice *dev;
463 	enum uclass_id id;
464 	int ret;
465 
466 	device_find_first_child(parent, &dev);
467 	if (!dev) {
468 		debug("%s: No block device found for parent '%s'\n", __func__,
469 		      parent->name);
470 		return -ENODEV;
471 	}
472 	id = device_get_uclass_id(dev);
473 	if (id != UCLASS_BLK) {
474 		debug("%s: Incorrect uclass %s for block device '%s'\n",
475 		      __func__, uclass_get_name(id), dev->name);
476 		return -ENOTBLK;
477 	}
478 	ret = device_probe(dev);
479 	if (ret)
480 		return ret;
481 	*devp = dev;
482 
483 	return 0;
484 }
485 
486 int blk_find_max_devnum(enum if_type if_type)
487 {
488 	struct udevice *dev;
489 	int max_devnum = -ENODEV;
490 	struct uclass *uc;
491 	int ret;
492 
493 	ret = uclass_get(UCLASS_BLK, &uc);
494 	if (ret)
495 		return ret;
496 	uclass_foreach_dev(dev, uc) {
497 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
498 
499 		if (desc->if_type == if_type && desc->devnum > max_devnum)
500 			max_devnum = desc->devnum;
501 	}
502 
503 	return max_devnum;
504 }
505 
506 static int blk_next_free_devnum(enum if_type if_type)
507 {
508 	int ret;
509 
510 	ret = blk_find_max_devnum(if_type);
511 	if (ret == -ENODEV)
512 		return 0;
513 	if (ret < 0)
514 		return ret;
515 
516 	return ret + 1;
517 }
518 
519 static int blk_claim_devnum(enum if_type if_type, int devnum)
520 {
521 	struct udevice *dev;
522 	struct uclass *uc;
523 	int ret;
524 
525 	ret = uclass_get(UCLASS_BLK, &uc);
526 	if (ret)
527 		return ret;
528 	uclass_foreach_dev(dev, uc) {
529 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
530 
531 		if (desc->if_type == if_type && desc->devnum == devnum) {
532 			int next = blk_next_free_devnum(if_type);
533 
534 			if (next < 0)
535 				return next;
536 			desc->devnum = next;
537 			return 0;
538 		}
539 	}
540 
541 	return -ENOENT;
542 }
543 
544 int blk_create_device(struct udevice *parent, const char *drv_name,
545 		      const char *name, int if_type, int devnum, int blksz,
546 		      lbaint_t lba, struct udevice **devp)
547 {
548 	struct blk_desc *desc;
549 	struct udevice *dev;
550 	int ret;
551 
552 	if (devnum == -1) {
553 		devnum = blk_next_free_devnum(if_type);
554 	} else {
555 		ret = blk_claim_devnum(if_type, devnum);
556 		if (ret < 0 && ret != -ENOENT)
557 			return ret;
558 	}
559 	if (devnum < 0)
560 		return devnum;
561 	ret = device_bind_driver(parent, drv_name, name, &dev);
562 	if (ret)
563 		return ret;
564 	desc = dev_get_uclass_platdata(dev);
565 	desc->if_type = if_type;
566 	desc->blksz = blksz;
567 	desc->lba = lba;
568 	desc->part_type = PART_TYPE_UNKNOWN;
569 	desc->bdev = dev;
570 	desc->devnum = devnum;
571 	*devp = dev;
572 
573 	return 0;
574 }
575 
576 int blk_create_devicef(struct udevice *parent, const char *drv_name,
577 		       const char *name, int if_type, int devnum, int blksz,
578 		       lbaint_t lba, struct udevice **devp)
579 {
580 	char dev_name[30], *str;
581 	int ret;
582 
583 	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
584 	str = strdup(dev_name);
585 	if (!str)
586 		return -ENOMEM;
587 
588 	ret = blk_create_device(parent, drv_name, str, if_type, devnum,
589 				blksz, lba, devp);
590 	if (ret) {
591 		free(str);
592 		return ret;
593 	}
594 	device_set_name_alloced(*devp);
595 
596 	return 0;
597 }
598 
599 int blk_unbind_all(int if_type)
600 {
601 	struct uclass *uc;
602 	struct udevice *dev, *next;
603 	int ret;
604 
605 	ret = uclass_get(UCLASS_BLK, &uc);
606 	if (ret)
607 		return ret;
608 	uclass_foreach_dev_safe(dev, next, uc) {
609 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
610 
611 		if (desc->if_type == if_type) {
612 			ret = device_remove(dev, DM_REMOVE_NORMAL);
613 			if (ret)
614 				return ret;
615 			ret = device_unbind(dev);
616 			if (ret)
617 				return ret;
618 		}
619 	}
620 
621 	return 0;
622 }
623 
624 UCLASS_DRIVER(blk) = {
625 	.id		= UCLASS_BLK,
626 	.name		= "blk",
627 	.per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
628 };
629