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