Home | History | Annotate | Download | only in block
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2016 Google, Inc
      4  * Written by Simon Glass <sjg (at) 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