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 <linux/err.h> 9 10 struct blk_driver *blk_driver_lookup_type(int if_type) 11 { 12 struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver); 13 const int n_ents = ll_entry_count(struct blk_driver, blk_driver); 14 struct blk_driver *entry; 15 16 for (entry = drv; entry != drv + n_ents; entry++) { 17 if (if_type == entry->if_type) 18 return entry; 19 } 20 21 /* Not found */ 22 return NULL; 23 } 24 25 static struct blk_driver *blk_driver_lookup_typename(const char *if_typename) 26 { 27 struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver); 28 const int n_ents = ll_entry_count(struct blk_driver, blk_driver); 29 struct blk_driver *entry; 30 31 for (entry = drv; entry != drv + n_ents; entry++) { 32 if (!strcmp(if_typename, entry->if_typename)) 33 return entry; 34 } 35 36 /* Not found */ 37 return NULL; 38 } 39 40 const char *blk_get_if_type_name(enum if_type if_type) 41 { 42 struct blk_driver *drv = blk_driver_lookup_type(if_type); 43 44 return drv ? drv->if_typename : NULL; 45 } 46 47 /** 48 * get_desc() - Get the block device descriptor for the given device number 49 * 50 * @drv: Legacy block driver 51 * @devnum: Device number (0 = first) 52 * @descp: Returns block device descriptor on success 53 * @return 0 on success, -ENODEV if there is no such device, -ENOSYS if the 54 * driver does not provide a way to find a device, or other -ve on other 55 * error. 56 */ 57 static int get_desc(struct blk_driver *drv, int devnum, struct blk_desc **descp) 58 { 59 if (drv->desc) { 60 if (devnum < 0 || devnum >= drv->max_devs) 61 return -ENODEV; 62 *descp = &drv->desc[devnum]; 63 return 0; 64 } 65 if (!drv->get_dev) 66 return -ENOSYS; 67 68 return drv->get_dev(devnum, descp); 69 } 70 71 #ifdef CONFIG_HAVE_BLOCK_DEVICE 72 int blk_list_part(enum if_type if_type) 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(if_type); 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 99 int blk_print_part_devnum(enum if_type if_type, int devnum) 100 { 101 struct blk_driver *drv = blk_driver_lookup_type(if_type); 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 117 void blk_list_devices(enum if_type if_type) 118 { 119 struct blk_driver *drv = blk_driver_lookup_type(if_type); 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 135 int blk_print_device_num(enum if_type if_type, int devnum) 136 { 137 struct blk_driver *drv = blk_driver_lookup_type(if_type); 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->if_typename, devnum); 147 dev_print(desc); 148 149 return 0; 150 } 151 152 int blk_show_device(enum if_type if_type, int devnum) 153 { 154 struct blk_driver *drv = blk_driver_lookup_type(if_type); 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 #endif /* CONFIG_HAVE_BLOCK_DEVICE */ 176 177 struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum) 178 { 179 struct blk_driver *drv = blk_driver_lookup_type(if_type); 180 struct blk_desc *desc; 181 182 if (!drv) 183 return NULL; 184 185 if (get_desc(drv, devnum, &desc)) 186 return NULL; 187 188 return desc; 189 } 190 191 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart) 192 { 193 struct blk_driver *drv = blk_driver_lookup_type(desc->if_type); 194 195 if (!drv) 196 return -ENOSYS; 197 if (drv->select_hwpart) 198 return drv->select_hwpart(desc, hwpart); 199 200 return 0; 201 } 202 203 struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum) 204 { 205 struct blk_driver *drv = blk_driver_lookup_typename(if_typename); 206 struct blk_desc *desc; 207 208 if (!drv) 209 return NULL; 210 211 if (get_desc(drv, devnum, &desc)) 212 return NULL; 213 214 return desc; 215 } 216 217 ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start, 218 lbaint_t blkcnt, void *buffer) 219 { 220 struct blk_driver *drv = blk_driver_lookup_type(if_type); 221 struct blk_desc *desc; 222 ulong n; 223 int ret; 224 225 if (!drv) 226 return -ENOSYS; 227 ret = get_desc(drv, devnum, &desc); 228 if (ret) 229 return ret; 230 n = desc->block_read(desc, start, blkcnt, buffer); 231 if (IS_ERR_VALUE(n)) 232 return n; 233 234 return n; 235 } 236 237 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start, 238 lbaint_t blkcnt, const void *buffer) 239 { 240 struct blk_driver *drv = blk_driver_lookup_type(if_type); 241 struct blk_desc *desc; 242 int ret; 243 244 if (!drv) 245 return -ENOSYS; 246 ret = get_desc(drv, devnum, &desc); 247 if (ret) 248 return ret; 249 return desc->block_write(desc, start, blkcnt, buffer); 250 } 251 252 int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart) 253 { 254 struct blk_driver *drv = blk_driver_lookup_type(if_type); 255 struct blk_desc *desc; 256 int ret; 257 258 if (!drv) 259 return -ENOSYS; 260 ret = get_desc(drv, devnum, &desc); 261 if (ret) 262 return ret; 263 return drv->select_hwpart(desc, hwpart); 264 } 265