]>
Commit | Line | Data |
---|---|---|
f739fcd8 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2a22d05d AG |
2 | /* |
3 | * EFI application disk support | |
4 | * | |
5 | * Copyright (c) 2016 Alexander Graf | |
2a22d05d AG |
6 | */ |
7 | ||
8 | #include <common.h> | |
6dd9faf8 | 9 | #include <blk.h> |
487d756f | 10 | #include <dm.h> |
2a22d05d | 11 | #include <efi_loader.h> |
86740067 | 12 | #include <fs.h> |
2a22d05d AG |
13 | #include <part.h> |
14 | #include <malloc.h> | |
15 | ||
dec88e41 | 16 | const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID; |
2a22d05d | 17 | |
d39646a3 HS |
18 | /** |
19 | * struct efi_disk_obj - EFI disk object | |
20 | * | |
21 | * @header: EFI object header | |
22 | * @ops: EFI disk I/O protocol interface | |
23 | * @ifname: interface name for block device | |
24 | * @dev_index: device index of block device | |
25 | * @media: block I/O media information | |
26 | * @dp: device path to the block device | |
27 | * @part: partition | |
28 | * @volume: simple file system protocol of the partition | |
29 | * @offset: offset into disk for simple partition | |
30 | * @desc: internal block device descriptor | |
31 | */ | |
2a22d05d | 32 | struct efi_disk_obj { |
d39646a3 | 33 | struct efi_object header; |
2a22d05d | 34 | struct efi_block_io ops; |
2a22d05d | 35 | const char *ifname; |
2a22d05d | 36 | int dev_index; |
2a22d05d | 37 | struct efi_block_io_media media; |
884bcf6f | 38 | struct efi_device_path *dp; |
884bcf6f | 39 | unsigned int part; |
2a92080d | 40 | struct efi_simple_file_system_protocol *volume; |
8c3df0bf | 41 | lbaint_t offset; |
884bcf6f | 42 | struct blk_desc *desc; |
2a22d05d AG |
43 | }; |
44 | ||
cda9b352 HS |
45 | /** |
46 | * efi_disk_reset() - reset block device | |
47 | * | |
48 | * This function implements the Reset service of the EFI_BLOCK_IO_PROTOCOL. | |
49 | * | |
50 | * As U-Boot's block devices do not have a reset function simply return | |
51 | * EFI_SUCCESS. | |
52 | * | |
53 | * See the Unified Extensible Firmware Interface (UEFI) specification for | |
54 | * details. | |
55 | * | |
56 | * @this: pointer to the BLOCK_IO_PROTOCOL | |
57 | * @extended_verification: extended verification | |
58 | * Return: status code | |
59 | */ | |
2a22d05d AG |
60 | static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, |
61 | char extended_verification) | |
62 | { | |
63 | EFI_ENTRY("%p, %x", this, extended_verification); | |
cda9b352 | 64 | return EFI_EXIT(EFI_SUCCESS); |
2a22d05d AG |
65 | } |
66 | ||
67 | enum efi_disk_direction { | |
68 | EFI_DISK_READ, | |
69 | EFI_DISK_WRITE, | |
70 | }; | |
71 | ||
a80a232e | 72 | static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this, |
2a22d05d AG |
73 | u32 media_id, u64 lba, unsigned long buffer_size, |
74 | void *buffer, enum efi_disk_direction direction) | |
75 | { | |
76 | struct efi_disk_obj *diskobj; | |
77 | struct blk_desc *desc; | |
78 | int blksz; | |
79 | int blocks; | |
80 | unsigned long n; | |
81 | ||
2a22d05d | 82 | diskobj = container_of(this, struct efi_disk_obj, ops); |
f9d334bd | 83 | desc = (struct blk_desc *) diskobj->desc; |
2a22d05d AG |
84 | blksz = desc->blksz; |
85 | blocks = buffer_size / blksz; | |
8c3df0bf | 86 | lba += diskobj->offset; |
2a22d05d | 87 | |
9d3f3398 HS |
88 | EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n", |
89 | blocks, lba, blksz, direction); | |
2a22d05d AG |
90 | |
91 | /* We only support full block access */ | |
92 | if (buffer_size & (blksz - 1)) | |
f59f0825 | 93 | return EFI_BAD_BUFFER_SIZE; |
2a22d05d AG |
94 | |
95 | if (direction == EFI_DISK_READ) | |
487d756f | 96 | n = blk_dread(desc, lba, blocks, buffer); |
2a22d05d | 97 | else |
487d756f | 98 | n = blk_dwrite(desc, lba, blocks, buffer); |
2a22d05d AG |
99 | |
100 | /* We don't do interrupts, so check for timers cooperatively */ | |
101 | efi_timer_check(); | |
102 | ||
9d3f3398 | 103 | EFI_PRINT("n=%lx blocks=%x\n", n, blocks); |
edcef3ba | 104 | |
2a22d05d | 105 | if (n != blocks) |
3304990b | 106 | return EFI_DEVICE_ERROR; |
2a22d05d | 107 | |
3304990b | 108 | return EFI_SUCCESS; |
2a22d05d AG |
109 | } |
110 | ||
e275458c | 111 | static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this, |
4f94865b | 112 | u32 media_id, u64 lba, efi_uintn_t buffer_size, |
2a22d05d AG |
113 | void *buffer) |
114 | { | |
51735ae0 AG |
115 | void *real_buffer = buffer; |
116 | efi_status_t r; | |
117 | ||
f59f0825 HS |
118 | if (!this) |
119 | return EFI_INVALID_PARAMETER; | |
120 | /* TODO: check for media changes */ | |
121 | if (media_id != this->media->media_id) | |
122 | return EFI_MEDIA_CHANGED; | |
123 | if (!this->media->media_present) | |
124 | return EFI_NO_MEDIA; | |
125 | /* media->io_align is a power of 2 */ | |
126 | if ((uintptr_t)buffer & (this->media->io_align - 1)) | |
127 | return EFI_INVALID_PARAMETER; | |
128 | if (lba * this->media->block_size + buffer_size > | |
129 | this->media->last_block * this->media->block_size) | |
130 | return EFI_INVALID_PARAMETER; | |
131 | ||
51735ae0 AG |
132 | #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER |
133 | if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) { | |
134 | r = efi_disk_read_blocks(this, media_id, lba, | |
135 | EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer); | |
136 | if (r != EFI_SUCCESS) | |
137 | return r; | |
138 | return efi_disk_read_blocks(this, media_id, lba + | |
139 | EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size, | |
140 | buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE, | |
141 | buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE); | |
142 | } | |
143 | ||
144 | real_buffer = efi_bounce_buffer; | |
145 | #endif | |
146 | ||
dee37fc9 | 147 | EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba, |
51735ae0 AG |
148 | buffer_size, buffer); |
149 | ||
150 | r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer, | |
151 | EFI_DISK_READ); | |
152 | ||
153 | /* Copy from bounce buffer to real buffer if necessary */ | |
154 | if ((r == EFI_SUCCESS) && (real_buffer != buffer)) | |
155 | memcpy(buffer, real_buffer, buffer_size); | |
156 | ||
157 | return EFI_EXIT(r); | |
2a22d05d AG |
158 | } |
159 | ||
e275458c | 160 | static efi_status_t EFIAPI efi_disk_write_blocks(struct efi_block_io *this, |
4f94865b | 161 | u32 media_id, u64 lba, efi_uintn_t buffer_size, |
2a22d05d AG |
162 | void *buffer) |
163 | { | |
51735ae0 AG |
164 | void *real_buffer = buffer; |
165 | efi_status_t r; | |
166 | ||
f59f0825 HS |
167 | if (!this) |
168 | return EFI_INVALID_PARAMETER; | |
169 | if (this->media->read_only) | |
170 | return EFI_WRITE_PROTECTED; | |
171 | /* TODO: check for media changes */ | |
172 | if (media_id != this->media->media_id) | |
173 | return EFI_MEDIA_CHANGED; | |
174 | if (!this->media->media_present) | |
175 | return EFI_NO_MEDIA; | |
176 | /* media->io_align is a power of 2 */ | |
177 | if ((uintptr_t)buffer & (this->media->io_align - 1)) | |
178 | return EFI_INVALID_PARAMETER; | |
179 | if (lba * this->media->block_size + buffer_size > | |
180 | this->media->last_block * this->media->block_size) | |
181 | return EFI_INVALID_PARAMETER; | |
182 | ||
51735ae0 AG |
183 | #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER |
184 | if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) { | |
185 | r = efi_disk_write_blocks(this, media_id, lba, | |
186 | EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer); | |
187 | if (r != EFI_SUCCESS) | |
188 | return r; | |
189 | return efi_disk_write_blocks(this, media_id, lba + | |
190 | EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size, | |
191 | buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE, | |
192 | buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE); | |
193 | } | |
194 | ||
195 | real_buffer = efi_bounce_buffer; | |
196 | #endif | |
197 | ||
dee37fc9 | 198 | EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba, |
51735ae0 AG |
199 | buffer_size, buffer); |
200 | ||
201 | /* Populate bounce buffer if necessary */ | |
202 | if (real_buffer != buffer) | |
203 | memcpy(real_buffer, buffer, buffer_size); | |
204 | ||
205 | r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer, | |
206 | EFI_DISK_WRITE); | |
207 | ||
208 | return EFI_EXIT(r); | |
2a22d05d AG |
209 | } |
210 | ||
211 | static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this) | |
212 | { | |
213 | /* We always write synchronously */ | |
214 | EFI_ENTRY("%p", this); | |
215 | return EFI_EXIT(EFI_SUCCESS); | |
216 | } | |
217 | ||
218 | static const struct efi_block_io block_io_disk_template = { | |
219 | .reset = &efi_disk_reset, | |
220 | .read_blocks = &efi_disk_read_blocks, | |
221 | .write_blocks = &efi_disk_write_blocks, | |
222 | .flush_blocks = &efi_disk_flush_blocks, | |
223 | }; | |
224 | ||
2a92080d | 225 | /* |
110d80a1 HS |
226 | * Get the simple file system protocol for a file device path. |
227 | * | |
228 | * The full path provided is split into device part and into a file | |
229 | * part. The device part is used to find the handle on which the | |
230 | * simple file system protocol is installed. | |
231 | * | |
232 | * @full_path device path including device and file | |
233 | * @return simple file system protocol | |
2a92080d RC |
234 | */ |
235 | struct efi_simple_file_system_protocol * | |
110d80a1 | 236 | efi_fs_from_path(struct efi_device_path *full_path) |
2a92080d RC |
237 | { |
238 | struct efi_object *efiobj; | |
110d80a1 HS |
239 | struct efi_handler *handler; |
240 | struct efi_device_path *device_path; | |
241 | struct efi_device_path *file_path; | |
242 | efi_status_t ret; | |
2a92080d | 243 | |
110d80a1 HS |
244 | /* Split the path into a device part and a file part */ |
245 | ret = efi_dp_split_file_path(full_path, &device_path, &file_path); | |
246 | if (ret != EFI_SUCCESS) | |
247 | return NULL; | |
248 | efi_free_pool(file_path); | |
249 | ||
250 | /* Get the EFI object for the partition */ | |
251 | efiobj = efi_dp_find_obj(device_path, NULL); | |
252 | efi_free_pool(device_path); | |
2a92080d RC |
253 | if (!efiobj) |
254 | return NULL; | |
255 | ||
110d80a1 HS |
256 | /* Find the simple file system protocol */ |
257 | ret = efi_search_protocol(efiobj, &efi_simple_file_system_protocol_guid, | |
258 | &handler); | |
259 | if (ret != EFI_SUCCESS) | |
260 | return NULL; | |
2a92080d | 261 | |
110d80a1 HS |
262 | /* Return the simple file system protocol for the partition */ |
263 | return handler->protocol_interface; | |
2a92080d RC |
264 | } |
265 | ||
86740067 AT |
266 | /** |
267 | * efi_fs_exists() - check if a partition bears a file system | |
268 | * | |
269 | * @desc: block device descriptor | |
270 | * @part: partition number | |
271 | * Return: 1 if a file system exists on the partition | |
272 | * 0 otherwise | |
273 | */ | |
274 | static int efi_fs_exists(struct blk_desc *desc, int part) | |
275 | { | |
276 | if (fs_set_blk_dev_with_part(desc, part)) | |
277 | return 0; | |
278 | ||
279 | if (fs_get_type() == FS_TYPE_ANY) | |
280 | return 0; | |
281 | ||
282 | fs_close(); | |
283 | ||
284 | return 1; | |
285 | } | |
286 | ||
93945f2c | 287 | /* |
64e4db0f | 288 | * Create a handle for a partition or disk |
93945f2c | 289 | * |
64e4db0f HS |
290 | * @parent parent handle |
291 | * @dp_parent parent device path | |
93945f2c HS |
292 | * @if_typename interface name for block device |
293 | * @desc internal block device | |
294 | * @dev_index device index for block device | |
295 | * @offset offset into disk for simple partitions | |
64e4db0f | 296 | * @return disk object |
93945f2c | 297 | */ |
df9cf561 | 298 | static efi_status_t efi_disk_add_dev( |
64e4db0f HS |
299 | efi_handle_t parent, |
300 | struct efi_device_path *dp_parent, | |
301 | const char *if_typename, | |
302 | struct blk_desc *desc, | |
303 | int dev_index, | |
304 | lbaint_t offset, | |
df9cf561 HS |
305 | unsigned int part, |
306 | struct efi_disk_obj **disk) | |
4a12a97c AG |
307 | { |
308 | struct efi_disk_obj *diskobj; | |
4b9f7aaf | 309 | efi_status_t ret; |
4a12a97c | 310 | |
0812d1a0 AG |
311 | /* Don't add empty devices */ |
312 | if (!desc->lba) | |
df9cf561 | 313 | return EFI_NOT_READY; |
0812d1a0 | 314 | |
884bcf6f | 315 | diskobj = calloc(1, sizeof(*diskobj)); |
4b9f7aaf | 316 | if (!diskobj) |
df9cf561 | 317 | return EFI_OUT_OF_RESOURCES; |
4b9f7aaf HS |
318 | |
319 | /* Hook up to the device list */ | |
d39646a3 | 320 | efi_add_handle(&diskobj->header); |
4a12a97c AG |
321 | |
322 | /* Fill in object data */ | |
64e4db0f HS |
323 | if (part) { |
324 | struct efi_device_path *node = efi_dp_part_node(desc, part); | |
325 | ||
326 | diskobj->dp = efi_dp_append_node(dp_parent, node); | |
327 | efi_free_pool(node); | |
328 | } else { | |
329 | diskobj->dp = efi_dp_from_part(desc, part); | |
330 | } | |
884bcf6f | 331 | diskobj->part = part; |
d39646a3 | 332 | ret = efi_add_protocol(&diskobj->header, &efi_block_io_guid, |
4b9f7aaf HS |
333 | &diskobj->ops); |
334 | if (ret != EFI_SUCCESS) | |
df9cf561 | 335 | return ret; |
d39646a3 | 336 | ret = efi_add_protocol(&diskobj->header, &efi_guid_device_path, |
4b9f7aaf HS |
337 | diskobj->dp); |
338 | if (ret != EFI_SUCCESS) | |
df9cf561 | 339 | return ret; |
89cb6a5d AT |
340 | /* partitions or whole disk without partitions */ |
341 | if ((part || desc->part_type == PART_TYPE_UNKNOWN) && | |
342 | efi_fs_exists(desc, part)) { | |
2a92080d RC |
343 | diskobj->volume = efi_simple_file_system(desc, part, |
344 | diskobj->dp); | |
d39646a3 | 345 | ret = efi_add_protocol(&diskobj->header, |
4b9f7aaf | 346 | &efi_simple_file_system_protocol_guid, |
22de1de9 | 347 | diskobj->volume); |
4b9f7aaf | 348 | if (ret != EFI_SUCCESS) |
df9cf561 | 349 | return ret; |
2a92080d | 350 | } |
4a12a97c | 351 | diskobj->ops = block_io_disk_template; |
487d756f | 352 | diskobj->ifname = if_typename; |
4a12a97c | 353 | diskobj->dev_index = dev_index; |
8c3df0bf | 354 | diskobj->offset = offset; |
f9d334bd | 355 | diskobj->desc = desc; |
4a12a97c AG |
356 | |
357 | /* Fill in EFI IO Media info (for read/write callbacks) */ | |
358 | diskobj->media.removable_media = desc->removable; | |
359 | diskobj->media.media_present = 1; | |
f59f0825 HS |
360 | /* |
361 | * MediaID is just an arbitrary counter. | |
362 | * We have to change it if the medium is removed or changed. | |
363 | */ | |
364 | diskobj->media.media_id = 1; | |
4a12a97c AG |
365 | diskobj->media.block_size = desc->blksz; |
366 | diskobj->media.io_align = desc->blksz; | |
0812d1a0 | 367 | diskobj->media.last_block = desc->lba - offset; |
5f770836 EV |
368 | if (part != 0) |
369 | diskobj->media.logical_partition = 1; | |
4a12a97c | 370 | diskobj->ops.media = &diskobj->media; |
df9cf561 HS |
371 | if (disk) |
372 | *disk = diskobj; | |
373 | return EFI_SUCCESS; | |
4a12a97c AG |
374 | } |
375 | ||
64e4db0f HS |
376 | /* |
377 | * Create handles and protocols for the partitions of a block device | |
378 | * | |
379 | * @parent handle of the parent disk | |
380 | * @blk_desc block device | |
381 | * @if_typename interface type | |
382 | * @diskid device number | |
383 | * @pdevname device name | |
384 | * @return number of partitions created | |
385 | */ | |
386 | int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc, | |
387 | const char *if_typename, int diskid, | |
388 | const char *pdevname) | |
8c3df0bf AG |
389 | { |
390 | int disks = 0; | |
ecbe1a07 | 391 | char devname[32] = { 0 }; /* dp->str is u16[32] long */ |
8c3df0bf | 392 | disk_partition_t info; |
16a73b24 | 393 | int part; |
64e4db0f HS |
394 | struct efi_device_path *dp = NULL; |
395 | efi_status_t ret; | |
396 | struct efi_handler *handler; | |
397 | ||
398 | /* Get the device path of the parent */ | |
399 | ret = efi_search_protocol(parent, &efi_guid_device_path, &handler); | |
400 | if (ret == EFI_SUCCESS) | |
401 | dp = handler->protocol_interface; | |
8c3df0bf | 402 | |
c034b7fd | 403 | /* Add devices for each partition */ |
16a73b24 JG |
404 | for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) { |
405 | if (part_get_info(desc, part, &info)) | |
406 | continue; | |
f9d334bd AG |
407 | snprintf(devname, sizeof(devname), "%s:%d", pdevname, |
408 | part); | |
df9cf561 HS |
409 | ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid, |
410 | info.start, part, NULL); | |
411 | if (ret != EFI_SUCCESS) { | |
412 | printf("Adding partition %s failed\n", pdevname); | |
413 | continue; | |
414 | } | |
8c3df0bf AG |
415 | disks++; |
416 | } | |
884bcf6f | 417 | |
8c3df0bf AG |
418 | return disks; |
419 | } | |
420 | ||
2a22d05d AG |
421 | /* |
422 | * U-Boot doesn't have a list of all online disk devices. So when running our | |
423 | * EFI payload, we scan through all of the potentially available ones and | |
424 | * store them in our object pool. | |
425 | * | |
487d756f SG |
426 | * TODO([email protected]): Actually with CONFIG_BLK, U-Boot does have this. |
427 | * Consider converting the code to look up devices as needed. The EFI device | |
428 | * could be a child of the UCLASS_BLK block device, perhaps. | |
429 | * | |
2a22d05d AG |
430 | * This gets called from do_bootefi_exec(). |
431 | */ | |
df9cf561 | 432 | efi_status_t efi_disk_register(void) |
2a22d05d | 433 | { |
64e4db0f | 434 | struct efi_disk_obj *disk; |
2a22d05d | 435 | int disks = 0; |
df9cf561 | 436 | efi_status_t ret; |
487d756f SG |
437 | #ifdef CONFIG_BLK |
438 | struct udevice *dev; | |
439 | ||
df9cf561 | 440 | for (uclass_first_device_check(UCLASS_BLK, &dev); dev; |
70bfcdc6 | 441 | uclass_next_device_check(&dev)) { |
487d756f | 442 | struct blk_desc *desc = dev_get_uclass_platdata(dev); |
9bfca9f9 | 443 | const char *if_typename = blk_get_if_type_name(desc->if_type); |
487d756f | 444 | |
c034b7fd | 445 | /* Add block device for the full device */ |
df9cf561 HS |
446 | printf("Scanning disk %s...\n", dev->name); |
447 | ret = efi_disk_add_dev(NULL, NULL, if_typename, | |
448 | desc, desc->devnum, 0, 0, &disk); | |
449 | if (ret == EFI_NOT_READY) { | |
450 | printf("Disk %s not ready\n", dev->name); | |
451 | continue; | |
452 | } | |
453 | if (ret) { | |
454 | printf("ERROR: failure to add disk device %s, r = %lu\n", | |
455 | dev->name, ret & ~EFI_ERROR_MASK); | |
456 | return ret; | |
457 | } | |
487d756f SG |
458 | disks++; |
459 | ||
c034b7fd | 460 | /* Partitions show up as block devices in EFI */ |
64e4db0f | 461 | disks += efi_disk_create_partitions( |
d39646a3 | 462 | &disk->header, desc, if_typename, |
64e4db0f | 463 | desc->devnum, dev->name); |
487d756f SG |
464 | } |
465 | #else | |
466 | int i, if_type; | |
2a22d05d AG |
467 | |
468 | /* Search for all available disk devices */ | |
6dd9faf8 | 469 | for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) { |
487d756f SG |
470 | const struct blk_driver *cur_drvr; |
471 | const char *if_typename; | |
472 | ||
6dd9faf8 SG |
473 | cur_drvr = blk_driver_lookup_type(if_type); |
474 | if (!cur_drvr) | |
475 | continue; | |
476 | ||
487d756f SG |
477 | if_typename = cur_drvr->if_typename; |
478 | printf("Scanning disks on %s...\n", if_typename); | |
2a22d05d AG |
479 | for (i = 0; i < 4; i++) { |
480 | struct blk_desc *desc; | |
ecbe1a07 | 481 | char devname[32] = { 0 }; /* dp->str is u16[32] long */ |
2a22d05d | 482 | |
6dd9faf8 | 483 | desc = blk_get_devnum_by_type(if_type, i); |
2a22d05d AG |
484 | if (!desc) |
485 | continue; | |
486 | if (desc->type == DEV_TYPE_UNKNOWN) | |
487 | continue; | |
488 | ||
2a22d05d | 489 | snprintf(devname, sizeof(devname), "%s%d", |
487d756f | 490 | if_typename, i); |
77511b3b | 491 | |
c034b7fd | 492 | /* Add block device for the full device */ |
df9cf561 HS |
493 | ret = efi_disk_add_dev(NULL, NULL, if_typename, desc, |
494 | i, 0, 0, &disk); | |
495 | if (ret == EFI_NOT_READY) { | |
496 | printf("Disk %s not ready\n", devname); | |
497 | continue; | |
498 | } | |
499 | if (ret) { | |
500 | printf("ERROR: failure to add disk device %s, r = %lu\n", | |
501 | devname, ret & ~EFI_ERROR_MASK); | |
502 | return ret; | |
503 | } | |
2a22d05d | 504 | disks++; |
8c3df0bf | 505 | |
c034b7fd | 506 | /* Partitions show up as block devices in EFI */ |
fae0118e | 507 | disks += efi_disk_create_partitions |
d39646a3 | 508 | (&disk->header, desc, |
fae0118e | 509 | if_typename, i, devname); |
2a22d05d AG |
510 | } |
511 | } | |
487d756f | 512 | #endif |
2a22d05d AG |
513 | printf("Found %d disks\n", disks); |
514 | ||
df9cf561 | 515 | return EFI_SUCCESS; |
2a22d05d | 516 | } |