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