1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <common.h>
8 #include <blk.h>
9 #include <part.h>
10 #include <linux/err.h>
11 
blk_driver_lookup_type(int if_type)12 struct blk_driver *blk_driver_lookup_type(int if_type)
13 {
14 	struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
15 	const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
16 	struct blk_driver *entry;
17 
18 	for (entry = drv; entry != drv + n_ents; entry++) {
19 		if (if_type == entry->if_type)
20 			return entry;
21 	}
22 
23 	/* Not found */
24 	return NULL;
25 }
26 
blk_driver_lookup_typename(const char * if_typename)27 static struct blk_driver *blk_driver_lookup_typename(const char *if_typename)
28 {
29 	struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
30 	const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
31 	struct blk_driver *entry;
32 
33 	for (entry = drv; entry != drv + n_ents; entry++) {
34 		if (!strcmp(if_typename, entry->if_typename))
35 			return entry;
36 	}
37 
38 	/* Not found */
39 	return NULL;
40 }
41 
blk_get_if_type_name(enum if_type if_type)42 const char *blk_get_if_type_name(enum if_type if_type)
43 {
44 	struct blk_driver *drv = blk_driver_lookup_type(if_type);
45 
46 	return drv ? drv->if_typename : NULL;
47 }
48 
49 /**
50  * get_desc() - Get the block device descriptor for the given device number
51  *
52  * @drv:	Legacy block driver
53  * @devnum:	Device number (0 = first)
54  * @descp:	Returns block device descriptor on success
55  * @return 0 on success, -ENODEV if there is no such device, -ENOSYS if the
56  * driver does not provide a way to find a device, or other -ve on other
57  * error.
58  */
get_desc(struct blk_driver * drv,int devnum,struct blk_desc ** descp)59 static int get_desc(struct blk_driver *drv, int devnum, struct blk_desc **descp)
60 {
61 	if (drv->desc) {
62 		if (devnum < 0 || devnum >= drv->max_devs)
63 			return -ENODEV;
64 		*descp = &drv->desc[devnum];
65 		return 0;
66 	}
67 	if (!drv->get_dev)
68 		return -ENOSYS;
69 
70 	return drv->get_dev(devnum, descp);
71 }
72 
73 #ifdef CONFIG_HAVE_BLOCK_DEVICE
blk_list_part(enum if_type if_type)74 int blk_list_part(enum if_type if_type)
75 {
76 	struct blk_driver *drv;
77 	struct blk_desc *desc;
78 	int devnum, ok;
79 	bool first = true;
80 
81 	drv = blk_driver_lookup_type(if_type);
82 	if (!drv)
83 		return -ENOSYS;
84 	for (ok = 0, devnum = 0; devnum < drv->max_devs; ++devnum) {
85 		if (get_desc(drv, devnum, &desc))
86 			continue;
87 		if (desc->part_type != PART_TYPE_UNKNOWN) {
88 			++ok;
89 			if (!first)
90 				putc('\n');
91 			part_print(desc);
92 			first = false;
93 		}
94 	}
95 	if (!ok)
96 		return -ENODEV;
97 
98 	return 0;
99 }
100 
blk_print_part_devnum(enum if_type if_type,int devnum)101 int blk_print_part_devnum(enum if_type if_type, int devnum)
102 {
103 	struct blk_driver *drv = blk_driver_lookup_type(if_type);
104 	struct blk_desc *desc;
105 	int ret;
106 
107 	if (!drv)
108 		return -ENOSYS;
109 	ret = get_desc(drv, devnum, &desc);
110 	if (ret)
111 		return ret;
112 	if (desc->type == DEV_TYPE_UNKNOWN)
113 		return -ENOENT;
114 	part_print(desc);
115 
116 	return 0;
117 }
118 
blk_list_devices(enum if_type if_type)119 void blk_list_devices(enum if_type if_type)
120 {
121 	struct blk_driver *drv = blk_driver_lookup_type(if_type);
122 	struct blk_desc *desc;
123 	int i;
124 
125 	if (!drv)
126 		return;
127 	for (i = 0; i < drv->max_devs; ++i) {
128 		if (get_desc(drv, i, &desc))
129 			continue;
130 		if (desc->type == DEV_TYPE_UNKNOWN)
131 			continue;  /* list only known devices */
132 		printf("Device %d: ", i);
133 		dev_print(desc);
134 	}
135 }
136 
blk_print_device_num(enum if_type if_type,int devnum)137 int blk_print_device_num(enum if_type if_type, int devnum)
138 {
139 	struct blk_driver *drv = blk_driver_lookup_type(if_type);
140 	struct blk_desc *desc;
141 	int ret;
142 
143 	if (!drv)
144 		return -ENOSYS;
145 	ret = get_desc(drv, devnum, &desc);
146 	if (ret)
147 		return ret;
148 	printf("\n%s device %d: ", drv->if_typename, devnum);
149 	dev_print(desc);
150 
151 	return 0;
152 }
153 
blk_show_device(enum if_type if_type,int devnum)154 int blk_show_device(enum if_type if_type, int devnum)
155 {
156 	struct blk_driver *drv = blk_driver_lookup_type(if_type);
157 	struct blk_desc *desc;
158 	int ret;
159 
160 	if (!drv)
161 		return -ENOSYS;
162 	printf("\nDevice %d: ", devnum);
163 	if (devnum >= drv->max_devs) {
164 		puts("unknown device\n");
165 		return -ENODEV;
166 	}
167 	ret = get_desc(drv, devnum, &desc);
168 	if (ret)
169 		return ret;
170 	dev_print(desc);
171 
172 	if (desc->type == DEV_TYPE_UNKNOWN)
173 		return -ENOENT;
174 
175 	return 0;
176 }
177 #endif /* CONFIG_HAVE_BLOCK_DEVICE */
178 
blk_get_devnum_by_type(enum if_type if_type,int devnum)179 struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
180 {
181 	struct blk_driver *drv = blk_driver_lookup_type(if_type);
182 	struct blk_desc *desc;
183 
184 	if (!drv)
185 		return NULL;
186 
187 	if (get_desc(drv, devnum, &desc))
188 		return NULL;
189 
190 	return desc;
191 }
192 
blk_dselect_hwpart(struct blk_desc * desc,int hwpart)193 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
194 {
195 	struct blk_driver *drv = blk_driver_lookup_type(desc->if_type);
196 
197 	if (!drv)
198 		return -ENOSYS;
199 	if (drv->select_hwpart)
200 		return drv->select_hwpart(desc, hwpart);
201 
202 	return 0;
203 }
204 
blk_get_devnum_by_typename(const char * if_typename,int devnum)205 struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
206 {
207 	struct blk_driver *drv = blk_driver_lookup_typename(if_typename);
208 	struct blk_desc *desc;
209 
210 	if (!drv)
211 		return NULL;
212 
213 	if (get_desc(drv, devnum, &desc))
214 		return NULL;
215 
216 	return desc;
217 }
218 
blk_read_devnum(enum if_type if_type,int devnum,lbaint_t start,lbaint_t blkcnt,void * buffer)219 ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
220 		      lbaint_t blkcnt, void *buffer)
221 {
222 	struct blk_driver *drv = blk_driver_lookup_type(if_type);
223 	struct blk_desc *desc;
224 	ulong n;
225 	int ret;
226 
227 	if (!drv)
228 		return -ENOSYS;
229 	ret = get_desc(drv, devnum, &desc);
230 	if (ret)
231 		return ret;
232 	n = desc->block_read(desc, start, blkcnt, buffer);
233 	if (IS_ERR_VALUE(n))
234 		return n;
235 
236 	return n;
237 }
238 
blk_write_devnum(enum if_type if_type,int devnum,lbaint_t start,lbaint_t blkcnt,const void * buffer)239 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
240 		       lbaint_t blkcnt, const void *buffer)
241 {
242 	struct blk_driver *drv = blk_driver_lookup_type(if_type);
243 	struct blk_desc *desc;
244 	int ret;
245 
246 	if (!drv)
247 		return -ENOSYS;
248 	ret = get_desc(drv, devnum, &desc);
249 	if (ret)
250 		return ret;
251 	return desc->block_write(desc, start, blkcnt, buffer);
252 }
253 
blk_select_hwpart_devnum(enum if_type if_type,int devnum,int hwpart)254 int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
255 {
256 	struct blk_driver *drv = blk_driver_lookup_type(if_type);
257 	struct blk_desc *desc;
258 	int ret;
259 
260 	if (!drv)
261 		return -ENOSYS;
262 	ret = get_desc(drv, devnum, &desc);
263 	if (ret)
264 		return ret;
265 	return drv->select_hwpart(desc, hwpart);
266 }
267