]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - api/api_storage.c
API: Correct storage enumeration routine, other minor fixes in API storage area.
[karo-tx-uboot.git] / api / api_storage.c
1 /*
2  * (C) Copyright 2007-2008 Semihalf
3  *
4  * Written by: Rafal Jaworowski <raj@semihalf.com>
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  *
24  */
25
26 #include <config.h>
27
28 #if defined(CONFIG_API)
29
30 #include <common.h>
31 #include <api_public.h>
32
33 #define DEBUG
34 #undef DEBUG
35
36 #ifdef DEBUG
37 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
38 #else
39 #define debugf(fmt, args...)
40 #endif
41
42 #define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
43
44
45 #define ENUM_IDE        0
46 #define ENUM_USB        1
47 #define ENUM_SCSI       2
48 #define ENUM_MMC        3
49 #define ENUM_MAX        4
50
51 struct stor_spec {
52         int             max_dev;
53         int             enum_started;
54         int             enum_ended;
55         int             type;           /* "external" type: DT_STOR_{IDE,USB,etc} */
56         char            *name;
57 };
58
59 static struct stor_spec specs[ENUM_MAX] = { { 0, 0, 0, 0, "" }, };
60
61
62 void dev_stor_init(void)
63 {
64 #if defined(CONFIG_CMD_IDE)
65         specs[ENUM_IDE].max_dev = CFG_IDE_MAXDEVICE;
66         specs[ENUM_IDE].enum_started = 0;
67         specs[ENUM_IDE].enum_ended = 0;
68         specs[ENUM_IDE].type = DEV_TYP_STOR | DT_STOR_IDE;
69         specs[ENUM_IDE].name = "ide";
70 #endif
71 #if defined(CONFIG_CMD_USB)
72         specs[ENUM_USB].max_dev = USB_MAX_STOR_DEV;
73         specs[ENUM_USB].enum_started = 0;
74         specs[ENUM_USB].enum_ended = 0;
75         specs[ENUM_USB].type = DEV_TYP_STOR | DT_STOR_USB;
76         specs[ENUM_USB].name = "usb";
77 #endif
78 #if defined(CONFIG_CMD_SCSI)
79         specs[ENUM_SCSI].max_dev = CFG_SCSI_MAX_DEVICE;
80         specs[ENUM_SCSI].enum_started = 0;
81         specs[ENUM_SCSI].enum_ended = 0;
82         specs[ENUM_SCSI].type = DEV_TYP_STOR | DT_STOR_SCSI;
83         specs[ENUM_SCSI].name = "scsi";
84 #endif
85 }
86
87 /*
88  * Finds next available device in the storage group
89  *
90  * type:        storage group type - ENUM_IDE, ENUM_SCSI etc.
91  *
92  * first:       if 1 the first device in the storage group is returned (if
93  *              exists), if 0 the next available device is searched
94  *
95  * more:        returns 0/1 depending if there are more devices in this group
96  *              available (for future iterations)
97  *
98  * returns:     0/1 depending if device found in this iteration
99  */
100 static int dev_stor_get(int type, int first, int *more, struct device_info *di)
101 {
102         int found = 0;
103         *more = 0;
104
105         int i;
106
107         block_dev_desc_t *dd;
108
109         if (first) {
110                 di->cookie = (void *)get_dev(specs[type].name, 0);
111                 if (di->cookie == NULL)
112                         return 0;
113                 else
114                         found = 1;
115
116         } else {
117                 for (i = 0; i < specs[type].max_dev; i++)
118                         if (di->cookie == (void *)get_dev(specs[type].name, i)) {
119                                 /* previous cookie found -- advance to the
120                                  * next device, if possible */
121
122                                 if (++i >= specs[type].max_dev) {
123                                         /* out of range, no more to enum */
124                                         di->cookie = NULL;
125                                         break;
126                                 }
127
128                                 di->cookie = (void *)get_dev(specs[type].name, i);
129                                 if (di->cookie == NULL)
130                                         return 0;
131                                 else
132                                         found = 1;
133
134                                 /* provide hint if there are more devices in
135                                  * this group to enumerate */
136                                 if ((i + 1) < specs[type].max_dev)
137                                         *more = 1;
138
139                                 break;
140                         }
141         }
142
143         if (found) {
144                 di->type = specs[type].type;
145
146                 if (di->cookie != NULL) {
147                         dd = (block_dev_desc_t *)di->cookie;
148                         if (dd->type == DEV_TYPE_UNKNOWN) {
149                                 debugf("device instance exists, but is not active..");
150                                 found = 0;
151                         } else {
152                                 di->di_stor.block_count = dd->lba;
153                                 di->di_stor.block_size = dd->blksz;
154                         }
155                 }
156
157         } else
158                 di->cookie = NULL;
159
160         return found;
161 }
162
163
164 /*
165  * returns:     ENUM_IDE, ENUM_USB etc. based on block_dev_desc_t
166  */
167 static int dev_stor_type(block_dev_desc_t *dd)
168 {
169         int i, j;
170
171         for (i = ENUM_IDE; i < ENUM_MAX; i++)
172                 for (j = 0; j < specs[i].max_dev; j++)
173                         if (dd == get_dev(specs[i].name, j))
174                                 return i;
175
176         return ENUM_MAX;
177 }
178
179
180 /*
181  * returns:     0/1 whether cookie points to some device in this group
182  */
183 static int dev_is_stor(int type, struct device_info *di)
184 {
185         return (dev_stor_type(di->cookie) == type) ? 1 : 0;
186 }
187
188
189 static int dev_enum_stor(int type, struct device_info *di)
190 {
191         int found = 0, more = 0;
192
193         debugf("called, type %d\n", type);
194
195         /*
196          * Formulae for enumerating storage devices:
197          * 1. if cookie (hint from previous enum call) is NULL we start again
198          *    with enumeration, so return the first available device, done.
199          *
200          * 2. if cookie is not NULL, check if it identifies some device in
201          *    this group:
202          *
203          * 2a. if cookie is a storage device from our group (IDE, USB etc.),
204          *     return next available (if exists) in this group
205          *
206          * 2b. if it isn't device from our group, check if such devices were
207          *     ever enumerated before:
208          *     - if not, return the first available device from this group
209          *     - else return 0
210          */
211
212         if (di->cookie == NULL) {
213
214                 debugf("group%d - enum restart\n", type);
215
216                 /*
217                  * 1. Enumeration (re-)started: take the first available
218                  * device, if exists
219                  */
220                 found = dev_stor_get(type, 1, &more, di);
221                 specs[type].enum_started = 1;
222
223         } else if (dev_is_stor(type, di)) {
224
225                 debugf("group%d - enum continued for the next device\n", type);
226
227                 if (specs[type].enum_ended) {
228                         debugf("group%d - nothing more to enum!\n", type);
229                         return 0;
230                 }
231
232                 /* 2a. Attempt to take a next available device in the group */
233                 found = dev_stor_get(type, 0, &more, di);
234
235         } else {
236
237                 if (specs[type].enum_ended) {
238                         debugf("group %d - already enumerated, skipping\n", type);
239                         return 0;
240                 }
241
242                 debugf("group%d - first time enum\n", type);
243
244                 if (specs[type].enum_started == 0) {
245                         /*
246                          * 2b.  If enumerating devices in this group did not
247                          * happen before, it means the cookie pointed to a
248                          * device frome some other group (another storage
249                          * group, or network); in this case try to take the
250                          * first available device from our group
251                          */
252                         specs[type].enum_started = 1;
253
254                         /*
255                          * Attempt to take the first device in this group:
256                          *'first element' flag is set
257                          */
258                         found = dev_stor_get(type, 1, &more, di);
259
260                 } else {
261                         errf("group%d - out of order iteration\n", type);
262                         found = 0;
263                         more = 0;
264                 }
265         }
266
267         /*
268          * If there are no more devices in this group, consider its
269          * enumeration finished
270          */
271         specs[type].enum_ended = (!more) ? 1 : 0;
272
273         if (found)
274                 debugf("device found, returning cookie 0x%08x\n",
275                         (u_int32_t)di->cookie);
276         else
277                 debugf("no device found\n");
278
279         return found;
280 }
281
282 void dev_enum_reset(void)
283 {
284         int i;
285
286         for (i = 0; i < ENUM_MAX; i ++) {
287                 specs[i].enum_started = 0;
288                 specs[i].enum_ended = 0;
289         }
290 }
291
292 int dev_enum_storage(struct device_info *di)
293 {
294         int i;
295
296         /*
297          * check: ide, usb, scsi, mmc
298          */
299         for (i = ENUM_IDE; i < ENUM_MAX; i ++) {
300                 if (dev_enum_stor(i, di))
301                         return 1;
302         }
303
304         return 0;
305 }
306
307 static int dev_stor_is_valid(int type, block_dev_desc_t *dd)
308 {
309         int i;
310
311         for (i = 0; i < specs[type].max_dev; i++)
312                 if (dd == get_dev(specs[type].name, i))
313                         if (dd->type != DEV_TYPE_UNKNOWN)
314                                 return 1;
315
316         return 0;
317 }
318
319
320 int dev_open_stor(void *cookie)
321 {
322         int type = dev_stor_type(cookie);
323
324         if (type == ENUM_MAX)
325                 return API_ENODEV;
326
327         if (dev_stor_is_valid(type, (block_dev_desc_t *)cookie))
328                 return 0;
329
330         return API_ENODEV;
331 }
332
333
334 int dev_close_stor(void *cookie)
335 {
336         /*
337          * Not much to do as we actually do not alter storage devices upon
338          * close
339          */
340         return 0;
341 }
342
343
344 static int dev_stor_index(block_dev_desc_t *dd)
345 {
346         int i, type;
347
348         type = dev_stor_type(dd);
349         for (i = 0; i < specs[type].max_dev; i++)
350                 if (dd == get_dev(specs[type].name, i))
351                         return i;
352
353         return (specs[type].max_dev);
354 }
355
356
357 lbasize_t dev_read_stor(void *cookie, void *buf, lbasize_t len, lbastart_t start)
358 {
359         int type;
360         block_dev_desc_t *dd = (block_dev_desc_t *)cookie;
361
362         if ((type = dev_stor_type(dd)) == ENUM_MAX)
363                 return 0;
364
365         if (!dev_stor_is_valid(type, dd))
366                 return 0;
367
368         if ((dd->block_read) == NULL) {
369                 debugf("no block_read() for device 0x%08x\n", cookie);
370                 return 0;
371         }
372
373         return (dd->block_read(dev_stor_index(dd), start, len, buf));
374 }
375
376 #endif /* CONFIG_API */