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