xref: /openbmc/u-boot/drivers/block/blk-uclass.c (revision fb53e7eb)
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_INVALID,
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 	/* flush cache after read */
298 	flush_cache((ulong)buffer, blkcnt * desc->blksz);
299 
300 	return n;
301 }
302 
303 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
304 		       lbaint_t blkcnt, const void *buffer)
305 {
306 	struct blk_desc *desc;
307 	int ret;
308 
309 	ret = get_desc(if_type, devnum, &desc);
310 	if (ret)
311 		return ret;
312 	return blk_dwrite(desc, start, blkcnt, buffer);
313 }
314 
315 int blk_select_hwpart(struct udevice *dev, int hwpart)
316 {
317 	const struct blk_ops *ops = blk_get_ops(dev);
318 
319 	if (!ops)
320 		return -ENOSYS;
321 	if (!ops->select_hwpart)
322 		return 0;
323 
324 	return ops->select_hwpart(dev, hwpart);
325 }
326 
327 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
328 {
329 	return blk_select_hwpart(desc->bdev, hwpart);
330 }
331 
332 int blk_first_device(int if_type, struct udevice **devp)
333 {
334 	struct blk_desc *desc;
335 	int ret;
336 
337 	ret = uclass_first_device(UCLASS_BLK, devp);
338 	if (ret)
339 		return ret;
340 	if (!*devp)
341 		return -ENODEV;
342 	do {
343 		desc = dev_get_uclass_platdata(*devp);
344 		if (desc->if_type == if_type)
345 			return 0;
346 		ret = uclass_next_device(devp);
347 		if (ret)
348 			return ret;
349 	} while (*devp);
350 
351 	return -ENODEV;
352 }
353 
354 int blk_next_device(struct udevice **devp)
355 {
356 	struct blk_desc *desc;
357 	int ret, if_type;
358 
359 	desc = dev_get_uclass_platdata(*devp);
360 	if_type = desc->if_type;
361 	do {
362 		ret = uclass_next_device(devp);
363 		if (ret)
364 			return ret;
365 		if (!*devp)
366 			return -ENODEV;
367 		desc = dev_get_uclass_platdata(*devp);
368 		if (desc->if_type == if_type)
369 			return 0;
370 	} while (1);
371 }
372 
373 int blk_find_device(int if_type, int devnum, struct udevice **devp)
374 {
375 	struct uclass *uc;
376 	struct udevice *dev;
377 	int ret;
378 
379 	ret = uclass_get(UCLASS_BLK, &uc);
380 	if (ret)
381 		return ret;
382 	uclass_foreach_dev(dev, uc) {
383 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
384 
385 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
386 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
387 		if (desc->if_type == if_type && desc->devnum == devnum) {
388 			*devp = dev;
389 			return 0;
390 		}
391 	}
392 
393 	return -ENODEV;
394 }
395 
396 int blk_get_device(int if_type, int devnum, struct udevice **devp)
397 {
398 	int ret;
399 
400 	ret = blk_find_device(if_type, devnum, devp);
401 	if (ret)
402 		return ret;
403 
404 	return device_probe(*devp);
405 }
406 
407 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
408 			lbaint_t blkcnt, void *buffer)
409 {
410 	struct udevice *dev = block_dev->bdev;
411 	const struct blk_ops *ops = blk_get_ops(dev);
412 	ulong blks_read;
413 
414 	if (!ops->read)
415 		return -ENOSYS;
416 
417 	if (blkcache_read(block_dev->if_type, block_dev->devnum,
418 			  start, blkcnt, block_dev->blksz, buffer))
419 		return blkcnt;
420 	blks_read = ops->read(dev, start, blkcnt, buffer);
421 	if (blks_read == blkcnt)
422 		blkcache_fill(block_dev->if_type, block_dev->devnum,
423 			      start, blkcnt, block_dev->blksz, buffer);
424 
425 	return blks_read;
426 }
427 
428 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
429 			 lbaint_t blkcnt, const void *buffer)
430 {
431 	struct udevice *dev = block_dev->bdev;
432 	const struct blk_ops *ops = blk_get_ops(dev);
433 
434 	if (!ops->write)
435 		return -ENOSYS;
436 
437 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
438 	return ops->write(dev, start, blkcnt, buffer);
439 }
440 
441 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
442 			 lbaint_t blkcnt)
443 {
444 	struct udevice *dev = block_dev->bdev;
445 	const struct blk_ops *ops = blk_get_ops(dev);
446 
447 	if (!ops->erase)
448 		return -ENOSYS;
449 
450 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
451 	return ops->erase(dev, start, blkcnt);
452 }
453 
454 int blk_prepare_device(struct udevice *dev)
455 {
456 	struct blk_desc *desc = dev_get_uclass_platdata(dev);
457 
458 	part_init(desc);
459 
460 	return 0;
461 }
462 
463 int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
464 {
465 	struct udevice *dev;
466 	enum uclass_id id;
467 	int ret;
468 
469 	device_find_first_child(parent, &dev);
470 	if (!dev) {
471 		debug("%s: No block device found for parent '%s'\n", __func__,
472 		      parent->name);
473 		return -ENODEV;
474 	}
475 	id = device_get_uclass_id(dev);
476 	if (id != UCLASS_BLK) {
477 		debug("%s: Incorrect uclass %s for block device '%s'\n",
478 		      __func__, uclass_get_name(id), dev->name);
479 		return -ENOTBLK;
480 	}
481 	ret = device_probe(dev);
482 	if (ret)
483 		return ret;
484 	*devp = dev;
485 
486 	return 0;
487 }
488 
489 int blk_find_max_devnum(enum if_type if_type)
490 {
491 	struct udevice *dev;
492 	int max_devnum = -ENODEV;
493 	struct uclass *uc;
494 	int ret;
495 
496 	ret = uclass_get(UCLASS_BLK, &uc);
497 	if (ret)
498 		return ret;
499 	uclass_foreach_dev(dev, uc) {
500 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
501 
502 		if (desc->if_type == if_type && desc->devnum > max_devnum)
503 			max_devnum = desc->devnum;
504 	}
505 
506 	return max_devnum;
507 }
508 
509 static int blk_next_free_devnum(enum if_type if_type)
510 {
511 	int ret;
512 
513 	ret = blk_find_max_devnum(if_type);
514 	if (ret == -ENODEV)
515 		return 0;
516 	if (ret < 0)
517 		return ret;
518 
519 	return ret + 1;
520 }
521 
522 static int blk_claim_devnum(enum if_type if_type, int devnum)
523 {
524 	struct udevice *dev;
525 	struct uclass *uc;
526 	int ret;
527 
528 	ret = uclass_get(UCLASS_BLK, &uc);
529 	if (ret)
530 		return ret;
531 	uclass_foreach_dev(dev, uc) {
532 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
533 
534 		if (desc->if_type == if_type && desc->devnum == devnum) {
535 			int next = blk_next_free_devnum(if_type);
536 
537 			if (next < 0)
538 				return next;
539 			desc->devnum = next;
540 			return 0;
541 		}
542 	}
543 
544 	return -ENOENT;
545 }
546 
547 int blk_create_device(struct udevice *parent, const char *drv_name,
548 		      const char *name, int if_type, int devnum, int blksz,
549 		      lbaint_t size, struct udevice **devp)
550 {
551 	struct blk_desc *desc;
552 	struct udevice *dev;
553 	int ret;
554 
555 	if (devnum == -1) {
556 		devnum = blk_next_free_devnum(if_type);
557 	} else {
558 		ret = blk_claim_devnum(if_type, devnum);
559 		if (ret < 0 && ret != -ENOENT)
560 			return ret;
561 	}
562 	if (devnum < 0)
563 		return devnum;
564 	ret = device_bind_driver(parent, drv_name, name, &dev);
565 	if (ret)
566 		return ret;
567 	desc = dev_get_uclass_platdata(dev);
568 	desc->if_type = if_type;
569 	desc->blksz = blksz;
570 	desc->lba = size / blksz;
571 	desc->part_type = PART_TYPE_UNKNOWN;
572 	desc->bdev = dev;
573 	desc->devnum = devnum;
574 	*devp = dev;
575 
576 	return 0;
577 }
578 
579 int blk_create_devicef(struct udevice *parent, const char *drv_name,
580 		       const char *name, int if_type, int devnum, int blksz,
581 		       lbaint_t size, struct udevice **devp)
582 {
583 	char dev_name[30], *str;
584 	int ret;
585 
586 	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
587 	str = strdup(dev_name);
588 	if (!str)
589 		return -ENOMEM;
590 
591 	ret = blk_create_device(parent, drv_name, str, if_type, devnum,
592 				blksz, size, devp);
593 	if (ret) {
594 		free(str);
595 		return ret;
596 	}
597 	device_set_name_alloced(*devp);
598 
599 	return 0;
600 }
601 
602 int blk_unbind_all(int if_type)
603 {
604 	struct uclass *uc;
605 	struct udevice *dev, *next;
606 	int ret;
607 
608 	ret = uclass_get(UCLASS_BLK, &uc);
609 	if (ret)
610 		return ret;
611 	uclass_foreach_dev_safe(dev, next, uc) {
612 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
613 
614 		if (desc->if_type == if_type) {
615 			ret = device_remove(dev, DM_REMOVE_NORMAL);
616 			if (ret)
617 				return ret;
618 			ret = device_unbind(dev);
619 			if (ret)
620 				return ret;
621 		}
622 	}
623 
624 	return 0;
625 }
626 
627 UCLASS_DRIVER(blk) = {
628 	.id		= UCLASS_BLK,
629 	.name		= "blk",
630 	.per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
631 };
632