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