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