xref: /openbmc/u-boot/api/api_storage.c (revision 24e02d0f)
1 /*
2  * (C) Copyright 2007 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[4];
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 (CONFIG_COMMANDS & CFG_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 (CONFIG_COMMANDS & CFG_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 (CONFIG_COMMANDS & CFG_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 		found = 1;
112 
113 	} else {
114 		for (i = 0; i < specs[type].max_dev; i++)
115 			if (di->cookie == (void *)get_dev(specs[type].name, i)) {
116 				/* previous cookie found -- advance to the
117 				 * next device, if possible */
118 
119 				if (++i >= specs[type].max_dev) {
120 					/* out of range, no more to enum */
121 					di->cookie = NULL;
122 					break;
123 				}
124 
125 				di->cookie = (void *)get_dev(specs[type].name, i);
126 				found = 1;
127 
128 				/* provide hint if there are more devices in
129 				 * this group to enumerate */
130 				if ((i + 1) < specs[type].max_dev)
131 					*more = 1;
132 
133 				break;
134 			}
135 	}
136 
137 	if (found) {
138 		di->type = specs[type].type;
139 
140 		if (di->cookie != NULL) {
141 			dd = (block_dev_desc_t *)di->cookie;
142 			if (dd->type == DEV_TYPE_UNKNOWN) {
143 				debugf("device instance exists, but is not active..");
144 				found = 0;
145 			} else {
146 				di->di_stor.block_count = dd->lba;
147 				di->di_stor.block_size = dd->blksz;
148 			}
149 		}
150 
151 	} else
152 		di->cookie = NULL;
153 
154 	return found;
155 }
156 
157 
158 /*
159  * returns:	ENUM_IDE, ENUM_USB etc. based on block_dev_desc_t
160  */
161 static int dev_stor_type(block_dev_desc_t *dd)
162 {
163 	int i, j;
164 
165 	for (i = ENUM_IDE; i < ENUM_MAX; i++)
166 		for (j = 0; j < specs[i].max_dev; j++)
167 			if (dd == get_dev(specs[i].name, j))
168 				return i;
169 
170 	return ENUM_MAX;
171 }
172 
173 
174 /*
175  * returns:	0/1 whether cookie points to some device in this group
176  */
177 static int dev_is_stor(int type, struct device_info *di)
178 {
179 	return (dev_stor_type(di->cookie) == type) ? 1 : 0;
180 }
181 
182 
183 static int dev_enum_stor(int type, struct device_info *di)
184 {
185 	int found = 0, more = 0;
186 
187 	debugf("called, type %d\n", type);
188 
189 	/*
190 	 * Formulae for enumerating storage devices:
191 	 * 1. if cookie (hint from previous enum call) is NULL we start again
192 	 *    with enumeration, so return the first available device, done.
193 	 *
194 	 * 2. if cookie is not NULL, check if it identifies some device in
195 	 *    this group:
196 	 *
197 	 * 2a. if cookie is a storage device from our group (IDE, USB etc.),
198 	 *     return next available (if exists) in this group
199 	 *
200 	 * 2b. if it isn't device from our group, check if such devices were
201 	 *     ever enumerated before:
202 	 *     - if not, return the first available device from this group
203 	 *     - else return 0
204 	 */
205 
206 	if (di->cookie == NULL) {
207 
208 		debugf("group%d - enum restart\n", type);
209 
210 		/*
211 		 * 1. Enumeration (re-)started: take the first available
212 		 * device, if exists
213 		 */
214 		found = dev_stor_get(type, 1, &more, di);
215 		specs[type].enum_started = 1;
216 
217 	} else if (dev_is_stor(type, di)) {
218 
219 		debugf("group%d - enum continued for the next device\n", type);
220 
221 		if (specs[type].enum_ended) {
222 			debugf("group%d - nothing more to enum!\n", type);
223 			return 0;
224 		}
225 
226 		/* 2a. Attempt to take a next available device in the group */
227 		found = dev_stor_get(type, 0, &more, di);
228 
229 	} else {
230 
231 		if (specs[type].enum_ended) {
232 			debugf("group %d - already enumerated, skipping\n", type);
233 			return 0;
234 		}
235 
236 		debugf("group%d - first time enum\n", type);
237 
238 		if (specs[type].enum_started == 0) {
239 			/*
240 			 * 2b.  If enumerating devices in this group did not
241 			 * happen before, it means the cookie pointed to a
242 			 * device frome some other group (another storage
243 			 * group, or network); in this case try to take the
244 			 * first available device from our group
245 			 */
246 			specs[type].enum_started = 1;
247 
248 			/*
249 			 * Attempt to take the first device in this group:
250 			 *'first element' flag is set
251 			 */
252 			found = dev_stor_get(type, 1, &more, di);
253 
254 		} else {
255 			errf("group%d - out of order iteration\n", type);
256 			found = 0;
257 			more = 0;
258 		}
259 	}
260 
261 	/*
262 	 * If there are no more devices in this group, consider its
263 	 * enumeration finished
264 	 */
265 	specs[type].enum_ended = (!more) ? 1 : 0;
266 
267 	if (found)
268 		debugf("device found, returning cookie 0x%08x\n",
269 			(u_int32_t)di->cookie);
270 	else
271 		debugf("no device found\n");
272 
273 	return found;
274 }
275 
276 void dev_enum_reset(void)
277 {
278 	int i;
279 
280 	for (i = 0; i < ENUM_MAX; i ++) {
281 		specs[i].enum_started = 0;
282 		specs[i].enum_ended = 0;
283 	}
284 }
285 
286 int dev_enum_storage(struct device_info *di)
287 {
288 	int i;
289 
290 	/*
291 	 * check: ide, usb, scsi, mmc
292 	 */
293 	for (i = ENUM_IDE; i < ENUM_MAX; i ++) {
294 		if (dev_enum_stor(i, di))
295 			return 1;
296 	}
297 
298 	return 0;
299 }
300 
301 static int dev_stor_is_valid(int type, block_dev_desc_t *dd)
302 {
303 	int i;
304 
305 	for (i = 0; i < specs[type].max_dev; i++)
306 		if (dd == get_dev(specs[type].name, i))
307 			if (dd->type != DEV_TYPE_UNKNOWN)
308 				return 1;
309 
310 	return 0;
311 }
312 
313 
314 int dev_open_stor(void *cookie)
315 {
316 	int type = dev_stor_type(cookie);
317 
318 	if (type == ENUM_MAX)
319 		return API_ENODEV;
320 
321 	if (dev_stor_is_valid(type, (block_dev_desc_t *)cookie))
322 		return 0;
323 
324 	return API_ENODEV;
325 }
326 
327 
328 int dev_close_stor(void *cookie)
329 {
330 	/*
331 	 * Not much to do as we actually do not alter storage devices upon
332 	 * close
333 	 */
334 	return 0;
335 }
336 
337 
338 static int dev_stor_index(block_dev_desc_t *dd)
339 {
340 	int i, type;
341 
342 	type = dev_stor_type(dd);
343 	for (i = 0; i < specs[type].max_dev; i++)
344 		if (dd == get_dev(specs[type].name, i))
345 			return i;
346 
347 	return (specs[type].max_dev);
348 }
349 
350 
351 lbasize_t dev_read_stor(void *cookie, void *buf, lbasize_t len, lbastart_t start)
352 {
353 	int type;
354 	block_dev_desc_t *dd = (block_dev_desc_t *)cookie;
355 
356 	if ((type = dev_stor_type(dd)) == ENUM_MAX)
357 		return 0;
358 
359 	if (!dev_stor_is_valid(type, dd))
360 		return 0;
361 
362 	if ((dd->block_read) == NULL) {
363 		debugf("no block_read() for device 0x%08x\n");
364 		return 0;
365 	}
366 
367 	return (dd->block_read(dev_stor_index(dd), start, len, buf));
368 }
369 
370 #endif /* CONFIG_API */
371