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 <blk.h>
8 #include <part.h>
9 #include <linux/err.h>
10 
blk_driver_lookup_type(int uclass_id)11 struct blk_driver *blk_driver_lookup_type(int uclass_id)
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 (uclass_id == entry->uclass_id)
19 			return entry;
20 	}
21 
22 	/* Not found */
23 	return NULL;
24 }
25 
blk_driver_lookup_typename(const char * uclass_idname)26 static struct blk_driver *blk_driver_lookup_typename(const char *uclass_idname)
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(uclass_idname, entry->uclass_idname))
34 			return entry;
35 	}
36 
37 	/* Not found */
38 	return NULL;
39 }
40 
blk_get_uclass_name(enum uclass_id uclass_id)41 const char *blk_get_uclass_name(enum uclass_id uclass_id)
42 {
43 	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
44 
45 	return drv ? drv->uclass_idname : 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  */
get_desc(struct blk_driver * drv,int devnum,struct blk_desc ** descp)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 
blk_list_part(enum uclass_id uclass_id)72 int blk_list_part(enum uclass_id uclass_id)
73 {
74 	struct blk_driver *drv;
75 	struct blk_desc *desc;
76 	int devnum, ok;
77 	bool first = true;
78 
79 	drv = blk_driver_lookup_type(uclass_id);
80 	if (!drv)
81 		return -ENOSYS;
82 	for (ok = 0, devnum = 0; devnum < drv->max_devs; ++devnum) {
83 		if (get_desc(drv, devnum, &desc))
84 			continue;
85 		if (desc->part_type != PART_TYPE_UNKNOWN) {
86 			++ok;
87 			if (!first)
88 				putc('\n');
89 			part_print(desc);
90 			first = false;
91 		}
92 	}
93 	if (!ok)
94 		return -ENODEV;
95 
96 	return 0;
97 }
98 
blk_print_part_devnum(enum uclass_id uclass_id,int devnum)99 int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
100 {
101 	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
102 	struct blk_desc *desc;
103 	int ret;
104 
105 	if (!drv)
106 		return -ENOSYS;
107 	ret = get_desc(drv, devnum, &desc);
108 	if (ret)
109 		return ret;
110 	if (desc->type == DEV_TYPE_UNKNOWN)
111 		return -ENOENT;
112 	part_print(desc);
113 
114 	return 0;
115 }
116 
blk_list_devices(enum uclass_id uclass_id)117 void blk_list_devices(enum uclass_id uclass_id)
118 {
119 	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
120 	struct blk_desc *desc;
121 	int i;
122 
123 	if (!drv)
124 		return;
125 	for (i = 0; i < drv->max_devs; ++i) {
126 		if (get_desc(drv, i, &desc))
127 			continue;
128 		if (desc->type == DEV_TYPE_UNKNOWN)
129 			continue;  /* list only known devices */
130 		printf("Device %d: ", i);
131 		dev_print(desc);
132 	}
133 }
134 
blk_print_device_num(enum uclass_id uclass_id,int devnum)135 int blk_print_device_num(enum uclass_id uclass_id, int devnum)
136 {
137 	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
138 	struct blk_desc *desc;
139 	int ret;
140 
141 	if (!drv)
142 		return -ENOSYS;
143 	ret = get_desc(drv, devnum, &desc);
144 	if (ret)
145 		return ret;
146 	printf("\n%s device %d: ", drv->uclass_idname, devnum);
147 	dev_print(desc);
148 
149 	return 0;
150 }
151 
blk_show_device(enum uclass_id uclass_id,int devnum)152 int blk_show_device(enum uclass_id uclass_id, int devnum)
153 {
154 	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
155 	struct blk_desc *desc;
156 	int ret;
157 
158 	if (!drv)
159 		return -ENOSYS;
160 	printf("\nDevice %d: ", devnum);
161 	if (devnum >= drv->max_devs) {
162 		puts("unknown device\n");
163 		return -ENODEV;
164 	}
165 	ret = get_desc(drv, devnum, &desc);
166 	if (ret)
167 		return ret;
168 	dev_print(desc);
169 
170 	if (desc->type == DEV_TYPE_UNKNOWN)
171 		return -ENOENT;
172 
173 	return 0;
174 }
175 
blk_get_devnum_by_uclass_id(enum uclass_id uclass_id,int devnum)176 struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
177 {
178 	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
179 	struct blk_desc *desc;
180 
181 	if (!drv)
182 		return NULL;
183 
184 	if (get_desc(drv, devnum, &desc))
185 		return NULL;
186 
187 	return desc;
188 }
189 
blk_dselect_hwpart(struct blk_desc * desc,int hwpart)190 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
191 {
192 	struct blk_driver *drv = blk_driver_lookup_type(desc->uclass_id);
193 
194 	if (!drv)
195 		return -ENOSYS;
196 	if (drv->select_hwpart)
197 		return drv->select_hwpart(desc, hwpart);
198 
199 	return 0;
200 }
201 
blk_get_devnum_by_uclass_idname(const char * uclass_idname,int devnum)202 struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
203 {
204 	struct blk_driver *drv = blk_driver_lookup_typename(uclass_idname);
205 	struct blk_desc *desc;
206 
207 	if (!drv)
208 		return NULL;
209 
210 	if (get_desc(drv, devnum, &desc))
211 		return NULL;
212 
213 	return desc;
214 }
215 
blk_read_devnum(enum uclass_id uclass_id,int devnum,lbaint_t start,lbaint_t blkcnt,void * buffer)216 ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
217 		      lbaint_t blkcnt, void *buffer)
218 {
219 	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
220 	struct blk_desc *desc;
221 	ulong n;
222 	int ret;
223 
224 	if (!drv)
225 		return -ENOSYS;
226 	ret = get_desc(drv, devnum, &desc);
227 	if (ret)
228 		return ret;
229 	n = desc->block_read(desc, start, blkcnt, buffer);
230 	if (IS_ERR_VALUE(n))
231 		return n;
232 
233 	return n;
234 }
235 
blk_write_devnum(enum uclass_id uclass_id,int devnum,lbaint_t start,lbaint_t blkcnt,const void * buffer)236 ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
237 		       lbaint_t blkcnt, const void *buffer)
238 {
239 	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
240 	struct blk_desc *desc;
241 	int ret;
242 
243 	if (!drv)
244 		return -ENOSYS;
245 	ret = get_desc(drv, devnum, &desc);
246 	if (ret)
247 		return ret;
248 	return desc->block_write(desc, start, blkcnt, buffer);
249 }
250 
blk_select_hwpart_devnum(enum uclass_id uclass_id,int devnum,int hwpart)251 int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
252 {
253 	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
254 	struct blk_desc *desc;
255 	int ret;
256 
257 	if (!drv)
258 		return -ENOSYS;
259 	ret = get_desc(drv, devnum, &desc);
260 	if (ret)
261 		return ret;
262 	return drv->select_hwpart(desc, hwpart);
263 }
264