Merge branch 'master' of git://git.denx.de/u-boot-fsl-qoriq
[oweals/u-boot.git] / drivers / block / blk_legacy.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 <linux/err.h>
10
11 struct blk_driver *blk_driver_lookup_type(int if_type)
12 {
13         struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
14         const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
15         struct blk_driver *entry;
16
17         for (entry = drv; entry != drv + n_ents; entry++) {
18                 if (if_type == entry->if_type)
19                         return entry;
20         }
21
22         /* Not found */
23         return NULL;
24 }
25
26 static struct blk_driver *blk_driver_lookup_typename(const char *if_typename)
27 {
28         struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
29         const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
30         struct blk_driver *entry;
31
32         for (entry = drv; entry != drv + n_ents; entry++) {
33                 if (!strcmp(if_typename, entry->if_typename))
34                         return entry;
35         }
36
37         /* Not found */
38         return NULL;
39 }
40
41 /**
42  * get_desc() - Get the block device descriptor for the given device number
43  *
44  * @drv:        Legacy block driver
45  * @devnum:     Device number (0 = first)
46  * @descp:      Returns block device descriptor on success
47  * @return 0 on success, -ENODEV if there is no such device, -ENOSYS if the
48  * driver does not provide a way to find a device, or other -ve on other
49  * error.
50  */
51 static int get_desc(struct blk_driver *drv, int devnum, struct blk_desc **descp)
52 {
53         if (drv->desc) {
54                 if (devnum < 0 || devnum >= drv->max_devs)
55                         return -ENODEV;
56                 *descp = &drv->desc[devnum];
57                 return 0;
58         }
59         if (!drv->get_dev)
60                 return -ENOSYS;
61
62         return drv->get_dev(devnum, descp);
63 }
64
65 #ifdef HAVE_BLOCK_DEVICE
66 int blk_list_part(enum if_type if_type)
67 {
68         struct blk_driver *drv;
69         struct blk_desc *desc;
70         int devnum, ok;
71         bool first = true;
72
73         drv = blk_driver_lookup_type(if_type);
74         if (!drv)
75                 return -ENOSYS;
76         for (ok = 0, devnum = 0; devnum < drv->max_devs; ++devnum) {
77                 if (get_desc(drv, devnum, &desc))
78                         continue;
79                 if (desc->part_type != PART_TYPE_UNKNOWN) {
80                         ++ok;
81                         if (!first)
82                                 putc('\n');
83                         part_print(desc);
84                         first = false;
85                 }
86         }
87         if (!ok)
88                 return -ENODEV;
89
90         return 0;
91 }
92
93 int blk_print_part_devnum(enum if_type if_type, int devnum)
94 {
95         struct blk_driver *drv = blk_driver_lookup_type(if_type);
96         struct blk_desc *desc;
97         int ret;
98
99         if (!drv)
100                 return -ENOSYS;
101         ret = get_desc(drv, devnum, &desc);
102         if (ret)
103                 return ret;
104         if (desc->type == DEV_TYPE_UNKNOWN)
105                 return -ENOENT;
106         part_print(desc);
107
108         return 0;
109 }
110
111 void blk_list_devices(enum if_type if_type)
112 {
113         struct blk_driver *drv = blk_driver_lookup_type(if_type);
114         struct blk_desc *desc;
115         int i;
116
117         if (!drv)
118                 return;
119         for (i = 0; i < drv->max_devs; ++i) {
120                 if (get_desc(drv, i, &desc))
121                         continue;
122                 if (desc->type == DEV_TYPE_UNKNOWN)
123                         continue;  /* list only known devices */
124                 printf("Device %d: ", i);
125                 dev_print(desc);
126         }
127 }
128
129 int blk_print_device_num(enum if_type if_type, int devnum)
130 {
131         struct blk_driver *drv = blk_driver_lookup_type(if_type);
132         struct blk_desc *desc;
133         int ret;
134
135         if (!drv)
136                 return -ENOSYS;
137         ret = get_desc(drv, devnum, &desc);
138         if (ret)
139                 return ret;
140         printf("\n%s device %d: ", drv->if_typename, devnum);
141         dev_print(desc);
142
143         return 0;
144 }
145
146 int blk_show_device(enum if_type if_type, int devnum)
147 {
148         struct blk_driver *drv = blk_driver_lookup_type(if_type);
149         struct blk_desc *desc;
150         int ret;
151
152         if (!drv)
153                 return -ENOSYS;
154         printf("\nDevice %d: ", devnum);
155         if (devnum >= drv->max_devs) {
156                 puts("unknown device\n");
157                 return -ENODEV;
158         }
159         ret = get_desc(drv, devnum, &desc);
160         if (ret)
161                 return ret;
162         dev_print(desc);
163
164         if (desc->type == DEV_TYPE_UNKNOWN)
165                 return -ENOENT;
166
167         return 0;
168 }
169 #endif /* HAVE_BLOCK_DEVICE */
170
171 struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
172 {
173         struct blk_driver *drv = blk_driver_lookup_type(if_type);
174         struct blk_desc *desc;
175
176         if (!drv)
177                 return NULL;
178
179         if (get_desc(drv, devnum, &desc))
180                 return NULL;
181
182         return desc;
183 }
184
185 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
186 {
187         struct blk_driver *drv = blk_driver_lookup_type(desc->if_type);
188
189         if (!drv)
190                 return -ENOSYS;
191         if (drv->select_hwpart)
192                 return drv->select_hwpart(desc, hwpart);
193
194         return 0;
195 }
196
197 struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
198 {
199         struct blk_driver *drv = blk_driver_lookup_typename(if_typename);
200         struct blk_desc *desc;
201
202         if (!drv)
203                 return NULL;
204
205         if (get_desc(drv, devnum, &desc))
206                 return NULL;
207
208         return desc;
209 }
210
211 ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
212                       lbaint_t blkcnt, void *buffer)
213 {
214         struct blk_driver *drv = blk_driver_lookup_type(if_type);
215         struct blk_desc *desc;
216         ulong n;
217         int ret;
218
219         if (!drv)
220                 return -ENOSYS;
221         ret = get_desc(drv, devnum, &desc);
222         if (ret)
223                 return ret;
224         n = desc->block_read(desc, start, blkcnt, buffer);
225         if (IS_ERR_VALUE(n))
226                 return n;
227
228         /* flush cache after read */
229         flush_cache((ulong)buffer, blkcnt * desc->blksz);
230
231         return n;
232 }
233
234 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
235                        lbaint_t blkcnt, const void *buffer)
236 {
237         struct blk_driver *drv = blk_driver_lookup_type(if_type);
238         struct blk_desc *desc;
239         int ret;
240
241         if (!drv)
242                 return -ENOSYS;
243         ret = get_desc(drv, devnum, &desc);
244         if (ret)
245                 return ret;
246         return desc->block_write(desc, start, blkcnt, buffer);
247 }
248
249 int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
250 {
251         struct blk_driver *drv = blk_driver_lookup_type(if_type);
252         struct blk_desc *desc;
253         int ret;
254
255         if (!drv)
256                 return -ENOSYS;
257         ret = get_desc(drv, devnum, &desc);
258         if (ret)
259                 return ret;
260         return drv->select_hwpart(desc, hwpart);
261 }