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