xref: /openbmc/u-boot/api/api_storage.c (revision 6d0f6bcf)
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 #if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
34 #include <usb.h>
35 #endif
36 
37 #define DEBUG
38 #undef DEBUG
39 
40 #ifdef DEBUG
41 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
42 #else
43 #define debugf(fmt, args...)
44 #endif
45 
46 #define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
47 
48 
49 #define ENUM_IDE	0
50 #define ENUM_USB	1
51 #define ENUM_SCSI	2
52 #define ENUM_MMC	3
53 #define ENUM_SATA	4
54 #define ENUM_MAX	5
55 
56 struct stor_spec {
57 	int		max_dev;
58 	int		enum_started;
59 	int		enum_ended;
60 	int		type;		/* "external" type: DT_STOR_{IDE,USB,etc} */
61 	char		*name;
62 };
63 
64 static struct stor_spec specs[ENUM_MAX] = { { 0, 0, 0, 0, "" }, };
65 
66 
67 void dev_stor_init(void)
68 {
69 #if defined(CONFIG_CMD_IDE)
70 	specs[ENUM_IDE].max_dev = CONFIG_SYS_IDE_MAXDEVICE;
71 	specs[ENUM_IDE].enum_started = 0;
72 	specs[ENUM_IDE].enum_ended = 0;
73 	specs[ENUM_IDE].type = DEV_TYP_STOR | DT_STOR_IDE;
74 	specs[ENUM_IDE].name = "ide";
75 #endif
76 #if defined(CONFIG_CMD_MMC)
77 	specs[ENUM_MMC].max_dev = CONFIG_SYS_MMC_MAX_DEVICE;
78 	specs[ENUM_MMC].enum_started = 0;
79 	specs[ENUM_MMC].enum_ended = 0;
80 	specs[ENUM_MMC].type = DEV_TYP_STOR | DT_STOR_MMC;
81 	specs[ENUM_MMC].name = "mmc";
82 #endif
83 #if defined(CONFIG_CMD_SATA)
84 	specs[ENUM_SATA].max_dev = CONFIG_SYS_SATA_MAX_DEVICE;
85 	specs[ENUM_SATA].enum_started = 0;
86 	specs[ENUM_SATA].enum_ended = 0;
87 	specs[ENUM_SATA].type = DEV_TYP_STOR | DT_STOR_SATA;
88 	specs[ENUM_SATA].name = "sata";
89 #endif
90 #if defined(CONFIG_CMD_SCSI)
91 	specs[ENUM_SCSI].max_dev = CONFIG_SYS_SCSI_MAX_DEVICE;
92 	specs[ENUM_SCSI].enum_started = 0;
93 	specs[ENUM_SCSI].enum_ended = 0;
94 	specs[ENUM_SCSI].type = DEV_TYP_STOR | DT_STOR_SCSI;
95 	specs[ENUM_SCSI].name = "scsi";
96 #endif
97 #if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
98 	specs[ENUM_USB].max_dev = USB_MAX_STOR_DEV;
99 	specs[ENUM_USB].enum_started = 0;
100 	specs[ENUM_USB].enum_ended = 0;
101 	specs[ENUM_USB].type = DEV_TYP_STOR | DT_STOR_USB;
102 	specs[ENUM_USB].name = "usb";
103 #endif
104 }
105 
106 /*
107  * Finds next available device in the storage group
108  *
109  * type:	storage group type - ENUM_IDE, ENUM_SCSI etc.
110  *
111  * first:	if 1 the first device in the storage group is returned (if
112  *              exists), if 0 the next available device is searched
113  *
114  * more:	returns 0/1 depending if there are more devices in this group
115  *		available (for future iterations)
116  *
117  * returns:	0/1 depending if device found in this iteration
118  */
119 static int dev_stor_get(int type, int first, int *more, struct device_info *di)
120 {
121 	int found = 0;
122 	*more = 0;
123 
124 	int i;
125 
126 	block_dev_desc_t *dd;
127 
128 	if (first) {
129 		di->cookie = (void *)get_dev(specs[type].name, 0);
130 		if (di->cookie == NULL)
131 			return 0;
132 		else
133 			found = 1;
134 
135 	} else {
136 		for (i = 0; i < specs[type].max_dev; i++)
137 			if (di->cookie == (void *)get_dev(specs[type].name, i)) {
138 				/* previous cookie found -- advance to the
139 				 * next device, if possible */
140 
141 				if (++i >= specs[type].max_dev) {
142 					/* out of range, no more to enum */
143 					di->cookie = NULL;
144 					break;
145 				}
146 
147 				di->cookie = (void *)get_dev(specs[type].name, i);
148 				if (di->cookie == NULL)
149 					return 0;
150 				else
151 					found = 1;
152 
153 				/* provide hint if there are more devices in
154 				 * this group to enumerate */
155 				if ((i + 1) < specs[type].max_dev)
156 					*more = 1;
157 
158 				break;
159 			}
160 	}
161 
162 	if (found) {
163 		di->type = specs[type].type;
164 
165 		if (di->cookie != NULL) {
166 			dd = (block_dev_desc_t *)di->cookie;
167 			if (dd->type == DEV_TYPE_UNKNOWN) {
168 				debugf("device instance exists, but is not active..");
169 				found = 0;
170 			} else {
171 				di->di_stor.block_count = dd->lba;
172 				di->di_stor.block_size = dd->blksz;
173 			}
174 		}
175 
176 	} else
177 		di->cookie = NULL;
178 
179 	return found;
180 }
181 
182 
183 /*
184  * returns:	ENUM_IDE, ENUM_USB etc. based on block_dev_desc_t
185  */
186 static int dev_stor_type(block_dev_desc_t *dd)
187 {
188 	int i, j;
189 
190 	for (i = ENUM_IDE; i < ENUM_MAX; i++)
191 		for (j = 0; j < specs[i].max_dev; j++)
192 			if (dd == get_dev(specs[i].name, j))
193 				return i;
194 
195 	return ENUM_MAX;
196 }
197 
198 
199 /*
200  * returns:	0/1 whether cookie points to some device in this group
201  */
202 static int dev_is_stor(int type, struct device_info *di)
203 {
204 	return (dev_stor_type(di->cookie) == type) ? 1 : 0;
205 }
206 
207 
208 static int dev_enum_stor(int type, struct device_info *di)
209 {
210 	int found = 0, more = 0;
211 
212 	debugf("called, type %d\n", type);
213 
214 	/*
215 	 * Formulae for enumerating storage devices:
216 	 * 1. if cookie (hint from previous enum call) is NULL we start again
217 	 *    with enumeration, so return the first available device, done.
218 	 *
219 	 * 2. if cookie is not NULL, check if it identifies some device in
220 	 *    this group:
221 	 *
222 	 * 2a. if cookie is a storage device from our group (IDE, USB etc.),
223 	 *     return next available (if exists) in this group
224 	 *
225 	 * 2b. if it isn't device from our group, check if such devices were
226 	 *     ever enumerated before:
227 	 *     - if not, return the first available device from this group
228 	 *     - else return 0
229 	 */
230 
231 	if (di->cookie == NULL) {
232 
233 		debugf("group%d - enum restart\n", type);
234 
235 		/*
236 		 * 1. Enumeration (re-)started: take the first available
237 		 * device, if exists
238 		 */
239 		found = dev_stor_get(type, 1, &more, di);
240 		specs[type].enum_started = 1;
241 
242 	} else if (dev_is_stor(type, di)) {
243 
244 		debugf("group%d - enum continued for the next device\n", type);
245 
246 		if (specs[type].enum_ended) {
247 			debugf("group%d - nothing more to enum!\n", type);
248 			return 0;
249 		}
250 
251 		/* 2a. Attempt to take a next available device in the group */
252 		found = dev_stor_get(type, 0, &more, di);
253 
254 	} else {
255 
256 		if (specs[type].enum_ended) {
257 			debugf("group %d - already enumerated, skipping\n", type);
258 			return 0;
259 		}
260 
261 		debugf("group%d - first time enum\n", type);
262 
263 		if (specs[type].enum_started == 0) {
264 			/*
265 			 * 2b.  If enumerating devices in this group did not
266 			 * happen before, it means the cookie pointed to a
267 			 * device frome some other group (another storage
268 			 * group, or network); in this case try to take the
269 			 * first available device from our group
270 			 */
271 			specs[type].enum_started = 1;
272 
273 			/*
274 			 * Attempt to take the first device in this group:
275 			 *'first element' flag is set
276 			 */
277 			found = dev_stor_get(type, 1, &more, di);
278 
279 		} else {
280 			errf("group%d - out of order iteration\n", type);
281 			found = 0;
282 			more = 0;
283 		}
284 	}
285 
286 	/*
287 	 * If there are no more devices in this group, consider its
288 	 * enumeration finished
289 	 */
290 	specs[type].enum_ended = (!more) ? 1 : 0;
291 
292 	if (found)
293 		debugf("device found, returning cookie 0x%08x\n",
294 			(u_int32_t)di->cookie);
295 	else
296 		debugf("no device found\n");
297 
298 	return found;
299 }
300 
301 void dev_enum_reset(void)
302 {
303 	int i;
304 
305 	for (i = 0; i < ENUM_MAX; i ++) {
306 		specs[i].enum_started = 0;
307 		specs[i].enum_ended = 0;
308 	}
309 }
310 
311 int dev_enum_storage(struct device_info *di)
312 {
313 	int i;
314 
315 	/*
316 	 * check: ide, usb, scsi, mmc
317 	 */
318 	for (i = ENUM_IDE; i < ENUM_MAX; i ++) {
319 		if (dev_enum_stor(i, di))
320 			return 1;
321 	}
322 
323 	return 0;
324 }
325 
326 static int dev_stor_is_valid(int type, block_dev_desc_t *dd)
327 {
328 	int i;
329 
330 	for (i = 0; i < specs[type].max_dev; i++)
331 		if (dd == get_dev(specs[type].name, i))
332 			if (dd->type != DEV_TYPE_UNKNOWN)
333 				return 1;
334 
335 	return 0;
336 }
337 
338 
339 int dev_open_stor(void *cookie)
340 {
341 	int type = dev_stor_type(cookie);
342 
343 	if (type == ENUM_MAX)
344 		return API_ENODEV;
345 
346 	if (dev_stor_is_valid(type, (block_dev_desc_t *)cookie))
347 		return 0;
348 
349 	return API_ENODEV;
350 }
351 
352 
353 int dev_close_stor(void *cookie)
354 {
355 	/*
356 	 * Not much to do as we actually do not alter storage devices upon
357 	 * close
358 	 */
359 	return 0;
360 }
361 
362 
363 static int dev_stor_index(block_dev_desc_t *dd)
364 {
365 	int i, type;
366 
367 	type = dev_stor_type(dd);
368 	for (i = 0; i < specs[type].max_dev; i++)
369 		if (dd == get_dev(specs[type].name, i))
370 			return i;
371 
372 	return (specs[type].max_dev);
373 }
374 
375 
376 lbasize_t dev_read_stor(void *cookie, void *buf, lbasize_t len, lbastart_t start)
377 {
378 	int type;
379 	block_dev_desc_t *dd = (block_dev_desc_t *)cookie;
380 
381 	if ((type = dev_stor_type(dd)) == ENUM_MAX)
382 		return 0;
383 
384 	if (!dev_stor_is_valid(type, dd))
385 		return 0;
386 
387 	if ((dd->block_read) == NULL) {
388 		debugf("no block_read() for device 0x%08x\n", cookie);
389 		return 0;
390 	}
391 
392 	return (dd->block_read(dev_stor_index(dd), start, len, buf));
393 }
394 
395 #endif /* CONFIG_API */
396