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