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