xref: /openbmc/u-boot/lib/efi_loader/efi_disk.c (revision 9450ab2b)
1f739fcd8STom Rini // SPDX-License-Identifier: GPL-2.0+
22a22d05dSAlexander Graf /*
32a22d05dSAlexander Graf  *  EFI application disk support
42a22d05dSAlexander Graf  *
52a22d05dSAlexander Graf  *  Copyright (c) 2016 Alexander Graf
62a22d05dSAlexander Graf  */
72a22d05dSAlexander Graf 
82a22d05dSAlexander Graf #include <common.h>
96dd9faf8SSimon Glass #include <blk.h>
10487d756fSSimon Glass #include <dm.h>
112a22d05dSAlexander Graf #include <efi_loader.h>
122a22d05dSAlexander Graf #include <part.h>
132a22d05dSAlexander Graf #include <malloc.h>
142a22d05dSAlexander Graf 
15b3dd14b6SHeinrich Schuchardt const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID;
162a22d05dSAlexander Graf 
17*d39646a3SHeinrich Schuchardt /**
18*d39646a3SHeinrich Schuchardt  * struct efi_disk_obj - EFI disk object
19*d39646a3SHeinrich Schuchardt  *
20*d39646a3SHeinrich Schuchardt  * @header:	EFI object header
21*d39646a3SHeinrich Schuchardt  * @ops:	EFI disk I/O protocol interface
22*d39646a3SHeinrich Schuchardt  * @ifname:	interface name for block device
23*d39646a3SHeinrich Schuchardt  * @dev_index:	device index of block device
24*d39646a3SHeinrich Schuchardt  * @media:	block I/O media information
25*d39646a3SHeinrich Schuchardt  * @dp:		device path to the block device
26*d39646a3SHeinrich Schuchardt  * @part:	partition
27*d39646a3SHeinrich Schuchardt  * @volume:	simple file system protocol of the partition
28*d39646a3SHeinrich Schuchardt  * @offset:	offset into disk for simple partition
29*d39646a3SHeinrich Schuchardt  * @desc:	internal block device descriptor
30*d39646a3SHeinrich Schuchardt  */
312a22d05dSAlexander Graf struct efi_disk_obj {
32*d39646a3SHeinrich Schuchardt 	struct efi_object header;
332a22d05dSAlexander Graf 	struct efi_block_io ops;
342a22d05dSAlexander Graf 	const char *ifname;
352a22d05dSAlexander Graf 	int dev_index;
362a22d05dSAlexander Graf 	struct efi_block_io_media media;
37884bcf6fSRob Clark 	struct efi_device_path *dp;
38884bcf6fSRob Clark 	unsigned int part;
392a92080dSRob Clark 	struct efi_simple_file_system_protocol *volume;
408c3df0bfSAlexander Graf 	lbaint_t offset;
41884bcf6fSRob Clark 	struct blk_desc *desc;
422a22d05dSAlexander Graf };
432a22d05dSAlexander Graf 
efi_disk_reset(struct efi_block_io * this,char extended_verification)442a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
452a22d05dSAlexander Graf 			char extended_verification)
462a22d05dSAlexander Graf {
472a22d05dSAlexander Graf 	EFI_ENTRY("%p, %x", this, extended_verification);
482a22d05dSAlexander Graf 	return EFI_EXIT(EFI_DEVICE_ERROR);
492a22d05dSAlexander Graf }
502a22d05dSAlexander Graf 
512a22d05dSAlexander Graf enum efi_disk_direction {
522a22d05dSAlexander Graf 	EFI_DISK_READ,
532a22d05dSAlexander Graf 	EFI_DISK_WRITE,
542a22d05dSAlexander Graf };
552a22d05dSAlexander Graf 
efi_disk_rw_blocks(struct efi_block_io * this,u32 media_id,u64 lba,unsigned long buffer_size,void * buffer,enum efi_disk_direction direction)56a80a232eSHeinrich Schuchardt static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
572a22d05dSAlexander Graf 			u32 media_id, u64 lba, unsigned long buffer_size,
582a22d05dSAlexander Graf 			void *buffer, enum efi_disk_direction direction)
592a22d05dSAlexander Graf {
602a22d05dSAlexander Graf 	struct efi_disk_obj *diskobj;
612a22d05dSAlexander Graf 	struct blk_desc *desc;
622a22d05dSAlexander Graf 	int blksz;
632a22d05dSAlexander Graf 	int blocks;
642a22d05dSAlexander Graf 	unsigned long n;
652a22d05dSAlexander Graf 
662a22d05dSAlexander Graf 	diskobj = container_of(this, struct efi_disk_obj, ops);
67f9d334bdSAlexander Graf 	desc = (struct blk_desc *) diskobj->desc;
682a22d05dSAlexander Graf 	blksz = desc->blksz;
692a22d05dSAlexander Graf 	blocks = buffer_size / blksz;
708c3df0bfSAlexander Graf 	lba += diskobj->offset;
712a22d05dSAlexander Graf 
72dee37fc9SMasahiro Yamada 	debug("EFI: %s:%d blocks=%x lba=%llx blksz=%x dir=%d\n", __func__,
732a22d05dSAlexander Graf 	      __LINE__, blocks, lba, blksz, direction);
742a22d05dSAlexander Graf 
752a22d05dSAlexander Graf 	/* We only support full block access */
762a22d05dSAlexander Graf 	if (buffer_size & (blksz - 1))
773304990bSRob Clark 		return EFI_DEVICE_ERROR;
782a22d05dSAlexander Graf 
792a22d05dSAlexander Graf 	if (direction == EFI_DISK_READ)
80487d756fSSimon Glass 		n = blk_dread(desc, lba, blocks, buffer);
812a22d05dSAlexander Graf 	else
82487d756fSSimon Glass 		n = blk_dwrite(desc, lba, blocks, buffer);
832a22d05dSAlexander Graf 
842a22d05dSAlexander Graf 	/* We don't do interrupts, so check for timers cooperatively */
852a22d05dSAlexander Graf 	efi_timer_check();
862a22d05dSAlexander Graf 
87edcef3baSAlexander Graf 	debug("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks);
88edcef3baSAlexander Graf 
892a22d05dSAlexander Graf 	if (n != blocks)
903304990bSRob Clark 		return EFI_DEVICE_ERROR;
912a22d05dSAlexander Graf 
923304990bSRob Clark 	return EFI_SUCCESS;
932a22d05dSAlexander Graf }
942a22d05dSAlexander Graf 
efi_disk_read_blocks(struct efi_block_io * this,u32 media_id,u64 lba,efi_uintn_t buffer_size,void * buffer)95e275458cSSimon Glass static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this,
964f94865bSHeinrich Schuchardt 			u32 media_id, u64 lba, efi_uintn_t buffer_size,
972a22d05dSAlexander Graf 			void *buffer)
982a22d05dSAlexander Graf {
9951735ae0SAlexander Graf 	void *real_buffer = buffer;
10051735ae0SAlexander Graf 	efi_status_t r;
10151735ae0SAlexander Graf 
10251735ae0SAlexander Graf #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
10351735ae0SAlexander Graf 	if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
10451735ae0SAlexander Graf 		r = efi_disk_read_blocks(this, media_id, lba,
10551735ae0SAlexander Graf 			EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer);
10651735ae0SAlexander Graf 		if (r != EFI_SUCCESS)
10751735ae0SAlexander Graf 			return r;
10851735ae0SAlexander Graf 		return efi_disk_read_blocks(this, media_id, lba +
10951735ae0SAlexander Graf 			EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size,
11051735ae0SAlexander Graf 			buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE,
11151735ae0SAlexander Graf 			buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE);
11251735ae0SAlexander Graf 	}
11351735ae0SAlexander Graf 
11451735ae0SAlexander Graf 	real_buffer = efi_bounce_buffer;
11551735ae0SAlexander Graf #endif
11651735ae0SAlexander Graf 
117dee37fc9SMasahiro Yamada 	EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba,
11851735ae0SAlexander Graf 		  buffer_size, buffer);
11951735ae0SAlexander Graf 
12051735ae0SAlexander Graf 	r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer,
1212a22d05dSAlexander Graf 			       EFI_DISK_READ);
12251735ae0SAlexander Graf 
12351735ae0SAlexander Graf 	/* Copy from bounce buffer to real buffer if necessary */
12451735ae0SAlexander Graf 	if ((r == EFI_SUCCESS) && (real_buffer != buffer))
12551735ae0SAlexander Graf 		memcpy(buffer, real_buffer, buffer_size);
12651735ae0SAlexander Graf 
12751735ae0SAlexander Graf 	return EFI_EXIT(r);
1282a22d05dSAlexander Graf }
1292a22d05dSAlexander Graf 
efi_disk_write_blocks(struct efi_block_io * this,u32 media_id,u64 lba,efi_uintn_t buffer_size,void * buffer)130e275458cSSimon Glass static efi_status_t EFIAPI efi_disk_write_blocks(struct efi_block_io *this,
1314f94865bSHeinrich Schuchardt 			u32 media_id, u64 lba, efi_uintn_t buffer_size,
1322a22d05dSAlexander Graf 			void *buffer)
1332a22d05dSAlexander Graf {
13451735ae0SAlexander Graf 	void *real_buffer = buffer;
13551735ae0SAlexander Graf 	efi_status_t r;
13651735ae0SAlexander Graf 
13751735ae0SAlexander Graf #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
13851735ae0SAlexander Graf 	if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
13951735ae0SAlexander Graf 		r = efi_disk_write_blocks(this, media_id, lba,
14051735ae0SAlexander Graf 			EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer);
14151735ae0SAlexander Graf 		if (r != EFI_SUCCESS)
14251735ae0SAlexander Graf 			return r;
14351735ae0SAlexander Graf 		return efi_disk_write_blocks(this, media_id, lba +
14451735ae0SAlexander Graf 			EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size,
14551735ae0SAlexander Graf 			buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE,
14651735ae0SAlexander Graf 			buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE);
14751735ae0SAlexander Graf 	}
14851735ae0SAlexander Graf 
14951735ae0SAlexander Graf 	real_buffer = efi_bounce_buffer;
15051735ae0SAlexander Graf #endif
15151735ae0SAlexander Graf 
152dee37fc9SMasahiro Yamada 	EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba,
15351735ae0SAlexander Graf 		  buffer_size, buffer);
15451735ae0SAlexander Graf 
15551735ae0SAlexander Graf 	/* Populate bounce buffer if necessary */
15651735ae0SAlexander Graf 	if (real_buffer != buffer)
15751735ae0SAlexander Graf 		memcpy(real_buffer, buffer, buffer_size);
15851735ae0SAlexander Graf 
15951735ae0SAlexander Graf 	r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer,
1602a22d05dSAlexander Graf 			       EFI_DISK_WRITE);
16151735ae0SAlexander Graf 
16251735ae0SAlexander Graf 	return EFI_EXIT(r);
1632a22d05dSAlexander Graf }
1642a22d05dSAlexander Graf 
efi_disk_flush_blocks(struct efi_block_io * this)1652a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this)
1662a22d05dSAlexander Graf {
1672a22d05dSAlexander Graf 	/* We always write synchronously */
1682a22d05dSAlexander Graf 	EFI_ENTRY("%p", this);
1692a22d05dSAlexander Graf 	return EFI_EXIT(EFI_SUCCESS);
1702a22d05dSAlexander Graf }
1712a22d05dSAlexander Graf 
1722a22d05dSAlexander Graf static const struct efi_block_io block_io_disk_template = {
1732a22d05dSAlexander Graf 	.reset = &efi_disk_reset,
1742a22d05dSAlexander Graf 	.read_blocks = &efi_disk_read_blocks,
1752a22d05dSAlexander Graf 	.write_blocks = &efi_disk_write_blocks,
1762a22d05dSAlexander Graf 	.flush_blocks = &efi_disk_flush_blocks,
1772a22d05dSAlexander Graf };
1782a22d05dSAlexander Graf 
1792a92080dSRob Clark /*
180110d80a1SHeinrich Schuchardt  * Get the simple file system protocol for a file device path.
181110d80a1SHeinrich Schuchardt  *
182110d80a1SHeinrich Schuchardt  * The full path provided is split into device part and into a file
183110d80a1SHeinrich Schuchardt  * part. The device part is used to find the handle on which the
184110d80a1SHeinrich Schuchardt  * simple file system protocol is installed.
185110d80a1SHeinrich Schuchardt  *
186110d80a1SHeinrich Schuchardt  * @full_path	device path including device and file
187110d80a1SHeinrich Schuchardt  * @return	simple file system protocol
1882a92080dSRob Clark  */
1892a92080dSRob Clark struct efi_simple_file_system_protocol *
efi_fs_from_path(struct efi_device_path * full_path)190110d80a1SHeinrich Schuchardt efi_fs_from_path(struct efi_device_path *full_path)
1912a92080dSRob Clark {
1922a92080dSRob Clark 	struct efi_object *efiobj;
193110d80a1SHeinrich Schuchardt 	struct efi_handler *handler;
194110d80a1SHeinrich Schuchardt 	struct efi_device_path *device_path;
195110d80a1SHeinrich Schuchardt 	struct efi_device_path *file_path;
196110d80a1SHeinrich Schuchardt 	efi_status_t ret;
1972a92080dSRob Clark 
198110d80a1SHeinrich Schuchardt 	/* Split the path into a device part and a file part */
199110d80a1SHeinrich Schuchardt 	ret = efi_dp_split_file_path(full_path, &device_path, &file_path);
200110d80a1SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
201110d80a1SHeinrich Schuchardt 		return NULL;
202110d80a1SHeinrich Schuchardt 	efi_free_pool(file_path);
203110d80a1SHeinrich Schuchardt 
204110d80a1SHeinrich Schuchardt 	/* Get the EFI object for the partition */
205110d80a1SHeinrich Schuchardt 	efiobj = efi_dp_find_obj(device_path, NULL);
206110d80a1SHeinrich Schuchardt 	efi_free_pool(device_path);
2072a92080dSRob Clark 	if (!efiobj)
2082a92080dSRob Clark 		return NULL;
2092a92080dSRob Clark 
210110d80a1SHeinrich Schuchardt 	/* Find the simple file system protocol */
211110d80a1SHeinrich Schuchardt 	ret = efi_search_protocol(efiobj, &efi_simple_file_system_protocol_guid,
212110d80a1SHeinrich Schuchardt 				  &handler);
213110d80a1SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
214110d80a1SHeinrich Schuchardt 		return NULL;
2152a92080dSRob Clark 
216110d80a1SHeinrich Schuchardt 	/* Return the simple file system protocol for the partition */
217110d80a1SHeinrich Schuchardt 	return handler->protocol_interface;
2182a92080dSRob Clark }
2192a92080dSRob Clark 
22093945f2cSHeinrich Schuchardt /*
22164e4db0fSHeinrich Schuchardt  * Create a handle for a partition or disk
22293945f2cSHeinrich Schuchardt  *
22364e4db0fSHeinrich Schuchardt  * @parent	parent handle
22464e4db0fSHeinrich Schuchardt  * @dp_parent	parent device path
22593945f2cSHeinrich Schuchardt  * @if_typename interface name for block device
22693945f2cSHeinrich Schuchardt  * @desc	internal block device
22793945f2cSHeinrich Schuchardt  * @dev_index   device index for block device
22893945f2cSHeinrich Schuchardt  * @offset	offset into disk for simple partitions
22964e4db0fSHeinrich Schuchardt  * @return	disk object
23093945f2cSHeinrich Schuchardt  */
efi_disk_add_dev(efi_handle_t parent,struct efi_device_path * dp_parent,const char * if_typename,struct blk_desc * desc,int dev_index,lbaint_t offset,unsigned int part,struct efi_disk_obj ** disk)231df9cf561SHeinrich Schuchardt static efi_status_t efi_disk_add_dev(
23264e4db0fSHeinrich Schuchardt 				efi_handle_t parent,
23364e4db0fSHeinrich Schuchardt 				struct efi_device_path *dp_parent,
234487d756fSSimon Glass 				const char *if_typename,
235884bcf6fSRob Clark 				struct blk_desc *desc,
2364a12a97cSAlexander Graf 				int dev_index,
237884bcf6fSRob Clark 				lbaint_t offset,
238df9cf561SHeinrich Schuchardt 				unsigned int part,
239df9cf561SHeinrich Schuchardt 				struct efi_disk_obj **disk)
2404a12a97cSAlexander Graf {
2414a12a97cSAlexander Graf 	struct efi_disk_obj *diskobj;
2424b9f7aafSHeinrich Schuchardt 	efi_status_t ret;
2434a12a97cSAlexander Graf 
2440812d1a0SAlexander Graf 	/* Don't add empty devices */
2450812d1a0SAlexander Graf 	if (!desc->lba)
246df9cf561SHeinrich Schuchardt 		return EFI_NOT_READY;
2470812d1a0SAlexander Graf 
248884bcf6fSRob Clark 	diskobj = calloc(1, sizeof(*diskobj));
2494b9f7aafSHeinrich Schuchardt 	if (!diskobj)
250df9cf561SHeinrich Schuchardt 		return EFI_OUT_OF_RESOURCES;
2514b9f7aafSHeinrich Schuchardt 
2524b9f7aafSHeinrich Schuchardt 	/* Hook up to the device list */
253*d39646a3SHeinrich Schuchardt 	efi_add_handle(&diskobj->header);
2544a12a97cSAlexander Graf 
2554a12a97cSAlexander Graf 	/* Fill in object data */
25664e4db0fSHeinrich Schuchardt 	if (part) {
25764e4db0fSHeinrich Schuchardt 		struct efi_device_path *node = efi_dp_part_node(desc, part);
25864e4db0fSHeinrich Schuchardt 
25964e4db0fSHeinrich Schuchardt 		diskobj->dp = efi_dp_append_node(dp_parent, node);
26064e4db0fSHeinrich Schuchardt 		efi_free_pool(node);
26164e4db0fSHeinrich Schuchardt 	} else {
262884bcf6fSRob Clark 		diskobj->dp = efi_dp_from_part(desc, part);
26364e4db0fSHeinrich Schuchardt 	}
264884bcf6fSRob Clark 	diskobj->part = part;
265*d39646a3SHeinrich Schuchardt 	ret = efi_add_protocol(&diskobj->header, &efi_block_io_guid,
2664b9f7aafSHeinrich Schuchardt 			       &diskobj->ops);
2674b9f7aafSHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
268df9cf561SHeinrich Schuchardt 		return ret;
269*d39646a3SHeinrich Schuchardt 	ret = efi_add_protocol(&diskobj->header, &efi_guid_device_path,
2704b9f7aafSHeinrich Schuchardt 			       diskobj->dp);
2714b9f7aafSHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
272df9cf561SHeinrich Schuchardt 		return ret;
2732a92080dSRob Clark 	if (part >= 1) {
2742a92080dSRob Clark 		diskobj->volume = efi_simple_file_system(desc, part,
2752a92080dSRob Clark 							 diskobj->dp);
276*d39646a3SHeinrich Schuchardt 		ret = efi_add_protocol(&diskobj->header,
2774b9f7aafSHeinrich Schuchardt 				       &efi_simple_file_system_protocol_guid,
27822de1de9SHeinrich Schuchardt 				       diskobj->volume);
2794b9f7aafSHeinrich Schuchardt 		if (ret != EFI_SUCCESS)
280df9cf561SHeinrich Schuchardt 			return ret;
2812a92080dSRob Clark 	}
2824a12a97cSAlexander Graf 	diskobj->ops = block_io_disk_template;
283487d756fSSimon Glass 	diskobj->ifname = if_typename;
2844a12a97cSAlexander Graf 	diskobj->dev_index = dev_index;
2858c3df0bfSAlexander Graf 	diskobj->offset = offset;
286f9d334bdSAlexander Graf 	diskobj->desc = desc;
2874a12a97cSAlexander Graf 
2884a12a97cSAlexander Graf 	/* Fill in EFI IO Media info (for read/write callbacks) */
2894a12a97cSAlexander Graf 	diskobj->media.removable_media = desc->removable;
2904a12a97cSAlexander Graf 	diskobj->media.media_present = 1;
2914a12a97cSAlexander Graf 	diskobj->media.block_size = desc->blksz;
2924a12a97cSAlexander Graf 	diskobj->media.io_align = desc->blksz;
2930812d1a0SAlexander Graf 	diskobj->media.last_block = desc->lba - offset;
2945f770836SEmmanuel Vadot 	if (part != 0)
2955f770836SEmmanuel Vadot 		diskobj->media.logical_partition = 1;
2964a12a97cSAlexander Graf 	diskobj->ops.media = &diskobj->media;
297df9cf561SHeinrich Schuchardt 	if (disk)
298df9cf561SHeinrich Schuchardt 		*disk = diskobj;
299df9cf561SHeinrich Schuchardt 	return EFI_SUCCESS;
3004a12a97cSAlexander Graf }
3014a12a97cSAlexander Graf 
30264e4db0fSHeinrich Schuchardt /*
30364e4db0fSHeinrich Schuchardt  * Create handles and protocols for the partitions of a block device
30464e4db0fSHeinrich Schuchardt  *
30564e4db0fSHeinrich Schuchardt  * @parent		handle of the parent disk
30664e4db0fSHeinrich Schuchardt  * @blk_desc		block device
30764e4db0fSHeinrich Schuchardt  * @if_typename		interface type
30864e4db0fSHeinrich Schuchardt  * @diskid		device number
30964e4db0fSHeinrich Schuchardt  * @pdevname		device name
31064e4db0fSHeinrich Schuchardt  * @return		number of partitions created
31164e4db0fSHeinrich Schuchardt  */
efi_disk_create_partitions(efi_handle_t parent,struct blk_desc * desc,const char * if_typename,int diskid,const char * pdevname)31264e4db0fSHeinrich Schuchardt int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
31364e4db0fSHeinrich Schuchardt 			       const char *if_typename, int diskid,
314f9d334bdSAlexander Graf 			       const char *pdevname)
3158c3df0bfSAlexander Graf {
3168c3df0bfSAlexander Graf 	int disks = 0;
317ecbe1a07SAlexander Graf 	char devname[32] = { 0 }; /* dp->str is u16[32] long */
3188c3df0bfSAlexander Graf 	disk_partition_t info;
31916a73b24SJonathan Gray 	int part;
32064e4db0fSHeinrich Schuchardt 	struct efi_device_path *dp = NULL;
32164e4db0fSHeinrich Schuchardt 	efi_status_t ret;
32264e4db0fSHeinrich Schuchardt 	struct efi_handler *handler;
32364e4db0fSHeinrich Schuchardt 
32464e4db0fSHeinrich Schuchardt 	/* Get the device path of the parent */
32564e4db0fSHeinrich Schuchardt 	ret = efi_search_protocol(parent, &efi_guid_device_path, &handler);
32664e4db0fSHeinrich Schuchardt 	if (ret == EFI_SUCCESS)
32764e4db0fSHeinrich Schuchardt 		dp = handler->protocol_interface;
3288c3df0bfSAlexander Graf 
329c034b7fdSAlexander Graf 	/* Add devices for each partition */
33016a73b24SJonathan Gray 	for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
33116a73b24SJonathan Gray 		if (part_get_info(desc, part, &info))
33216a73b24SJonathan Gray 			continue;
333f9d334bdSAlexander Graf 		snprintf(devname, sizeof(devname), "%s:%d", pdevname,
334f9d334bdSAlexander Graf 			 part);
335df9cf561SHeinrich Schuchardt 		ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid,
336df9cf561SHeinrich Schuchardt 				       info.start, part, NULL);
337df9cf561SHeinrich Schuchardt 		if (ret != EFI_SUCCESS) {
338df9cf561SHeinrich Schuchardt 			printf("Adding partition %s failed\n", pdevname);
339df9cf561SHeinrich Schuchardt 			continue;
340df9cf561SHeinrich Schuchardt 		}
3418c3df0bfSAlexander Graf 		disks++;
3428c3df0bfSAlexander Graf 	}
343884bcf6fSRob Clark 
3448c3df0bfSAlexander Graf 	return disks;
3458c3df0bfSAlexander Graf }
3468c3df0bfSAlexander Graf 
3472a22d05dSAlexander Graf /*
3482a22d05dSAlexander Graf  * U-Boot doesn't have a list of all online disk devices. So when running our
3492a22d05dSAlexander Graf  * EFI payload, we scan through all of the potentially available ones and
3502a22d05dSAlexander Graf  * store them in our object pool.
3512a22d05dSAlexander Graf  *
352487d756fSSimon Glass  * TODO(sjg@chromium.org): Actually with CONFIG_BLK, U-Boot does have this.
353487d756fSSimon Glass  * Consider converting the code to look up devices as needed. The EFI device
354487d756fSSimon Glass  * could be a child of the UCLASS_BLK block device, perhaps.
355487d756fSSimon Glass  *
3562a22d05dSAlexander Graf  * This gets called from do_bootefi_exec().
3572a22d05dSAlexander Graf  */
efi_disk_register(void)358df9cf561SHeinrich Schuchardt efi_status_t efi_disk_register(void)
3592a22d05dSAlexander Graf {
36064e4db0fSHeinrich Schuchardt 	struct efi_disk_obj *disk;
3612a22d05dSAlexander Graf 	int disks = 0;
362df9cf561SHeinrich Schuchardt 	efi_status_t ret;
363487d756fSSimon Glass #ifdef CONFIG_BLK
364487d756fSSimon Glass 	struct udevice *dev;
365487d756fSSimon Glass 
366df9cf561SHeinrich Schuchardt 	for (uclass_first_device_check(UCLASS_BLK, &dev); dev;
36770bfcdc6Sxypron.glpk@gmx.de 	     uclass_next_device_check(&dev)) {
368487d756fSSimon Glass 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
3699bfca9f9SHeinrich Schuchardt 		const char *if_typename = blk_get_if_type_name(desc->if_type);
370487d756fSSimon Glass 
371c034b7fdSAlexander Graf 		/* Add block device for the full device */
372df9cf561SHeinrich Schuchardt 		printf("Scanning disk %s...\n", dev->name);
373df9cf561SHeinrich Schuchardt 		ret = efi_disk_add_dev(NULL, NULL, if_typename,
374df9cf561SHeinrich Schuchardt 					desc, desc->devnum, 0, 0, &disk);
375df9cf561SHeinrich Schuchardt 		if (ret == EFI_NOT_READY) {
376df9cf561SHeinrich Schuchardt 			printf("Disk %s not ready\n", dev->name);
377df9cf561SHeinrich Schuchardt 			continue;
378df9cf561SHeinrich Schuchardt 		}
379df9cf561SHeinrich Schuchardt 		if (ret) {
380df9cf561SHeinrich Schuchardt 			printf("ERROR: failure to add disk device %s, r = %lu\n",
381df9cf561SHeinrich Schuchardt 			       dev->name, ret & ~EFI_ERROR_MASK);
382df9cf561SHeinrich Schuchardt 			return ret;
383df9cf561SHeinrich Schuchardt 		}
384487d756fSSimon Glass 		disks++;
385487d756fSSimon Glass 
386c034b7fdSAlexander Graf 		/* Partitions show up as block devices in EFI */
38764e4db0fSHeinrich Schuchardt 		disks += efi_disk_create_partitions(
388*d39646a3SHeinrich Schuchardt 					&disk->header, desc, if_typename,
389f9d334bdSAlexander Graf 					desc->devnum, dev->name);
390487d756fSSimon Glass 	}
391487d756fSSimon Glass #else
392487d756fSSimon Glass 	int i, if_type;
3932a22d05dSAlexander Graf 
3942a22d05dSAlexander Graf 	/* Search for all available disk devices */
3956dd9faf8SSimon Glass 	for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) {
396487d756fSSimon Glass 		const struct blk_driver *cur_drvr;
397487d756fSSimon Glass 		const char *if_typename;
398487d756fSSimon Glass 
3996dd9faf8SSimon Glass 		cur_drvr = blk_driver_lookup_type(if_type);
4006dd9faf8SSimon Glass 		if (!cur_drvr)
4016dd9faf8SSimon Glass 			continue;
4026dd9faf8SSimon Glass 
403487d756fSSimon Glass 		if_typename = cur_drvr->if_typename;
404487d756fSSimon Glass 		printf("Scanning disks on %s...\n", if_typename);
4052a22d05dSAlexander Graf 		for (i = 0; i < 4; i++) {
4062a22d05dSAlexander Graf 			struct blk_desc *desc;
407ecbe1a07SAlexander Graf 			char devname[32] = { 0 }; /* dp->str is u16[32] long */
4082a22d05dSAlexander Graf 
4096dd9faf8SSimon Glass 			desc = blk_get_devnum_by_type(if_type, i);
4102a22d05dSAlexander Graf 			if (!desc)
4112a22d05dSAlexander Graf 				continue;
4122a22d05dSAlexander Graf 			if (desc->type == DEV_TYPE_UNKNOWN)
4132a22d05dSAlexander Graf 				continue;
4142a22d05dSAlexander Graf 
4152a22d05dSAlexander Graf 			snprintf(devname, sizeof(devname), "%s%d",
416487d756fSSimon Glass 				 if_typename, i);
41777511b3bSRob Clark 
418c034b7fdSAlexander Graf 			/* Add block device for the full device */
419df9cf561SHeinrich Schuchardt 			ret = efi_disk_add_dev(NULL, NULL, if_typename, desc,
420df9cf561SHeinrich Schuchardt 					       i, 0, 0, &disk);
421df9cf561SHeinrich Schuchardt 			if (ret == EFI_NOT_READY) {
422df9cf561SHeinrich Schuchardt 				printf("Disk %s not ready\n", devname);
423df9cf561SHeinrich Schuchardt 				continue;
424df9cf561SHeinrich Schuchardt 			}
425df9cf561SHeinrich Schuchardt 			if (ret) {
426df9cf561SHeinrich Schuchardt 				printf("ERROR: failure to add disk device %s, r = %lu\n",
427df9cf561SHeinrich Schuchardt 				       devname, ret & ~EFI_ERROR_MASK);
428df9cf561SHeinrich Schuchardt 				return ret;
429df9cf561SHeinrich Schuchardt 			}
4302a22d05dSAlexander Graf 			disks++;
4318c3df0bfSAlexander Graf 
432c034b7fdSAlexander Graf 			/* Partitions show up as block devices in EFI */
433fae0118eSHeinrich Schuchardt 			disks += efi_disk_create_partitions
434*d39646a3SHeinrich Schuchardt 						(&disk->header, desc,
43564e4db0fSHeinrich Schuchardt 						 if_typename, i, devname);
4362a22d05dSAlexander Graf 		}
4372a22d05dSAlexander Graf 	}
438487d756fSSimon Glass #endif
4392a22d05dSAlexander Graf 	printf("Found %d disks\n", disks);
4402a22d05dSAlexander Graf 
441df9cf561SHeinrich Schuchardt 	return EFI_SUCCESS;
4422a22d05dSAlexander Graf }
443