]> git.sur5r.net Git - u-boot/blob - drivers/block/blk-uclass.c
Merge git://www.denx.de/git/u-boot-imx
[u-boot] / drivers / block / blk-uclass.c
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 };