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