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