]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
MdeModulePkg/PartitionDxe: Add already start check for child hanldes
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Partition.c
CommitLineData
adbcbf8f 1/** @file\r
2 Partition driver that produces logical BlockIo devices from a physical\r
3 BlockIo device. The logical BlockIo devices are based on the format\r
8aafec2c 4 of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy\r
adbcbf8f 5 MBR, and GPT partition schemes are supported.\r
6\r
709c9fd5 7Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.\r
68599525 8Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 9SPDX-License-Identifier: BSD-2-Clause-Patent\r
adbcbf8f 10\r
11**/\r
12\r
13\r
14#include "Partition.h"\r
15\r
16//\r
ff61847d 17// Partition Driver Global Variables.\r
adbcbf8f 18//\r
19EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {\r
20 PartitionDriverBindingSupported,\r
21 PartitionDriverBindingStart,\r
22 PartitionDriverBindingStop,\r
c86b273d 23 //\r
d1102dba
LG
24 // Grub4Dos copies the BPB of the first partition to the MBR. If the\r
25 // DriverBindingStart() of the Fat driver gets run before that of Partition\r
c86b273d
RN
26 // driver only the first partition can be recognized.\r
27 // Let the driver binding version of Partition driver be higher than that of\r
28 // Fat driver to make sure the DriverBindingStart() of the Partition driver\r
29 // gets run before that of Fat driver so that all the partitions can be recognized.\r
30 //\r
31 0xb,\r
adbcbf8f 32 NULL,\r
33 NULL\r
34};\r
35\r
ff61847d 36//\r
d1102dba 37// Prioritized function list to detect partition table.\r
ff61847d 38//\r
adbcbf8f 39PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {\r
40 PartitionInstallGptChildHandles,\r
adbcbf8f 41 PartitionInstallMbrChildHandles,\r
8aafec2c 42 PartitionInstallUdfChildHandles,\r
adbcbf8f 43 NULL\r
44};\r
45\r
adbcbf8f 46/**\r
47 Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
490b5ea1 48 than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be\r
49 supported.\r
adbcbf8f 50\r
490b5ea1 51 @param[in] This Protocol instance pointer.\r
52 @param[in] ControllerHandle Handle of device to test.\r
53 @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
54 device to start.\r
adbcbf8f 55\r
56 @retval EFI_SUCCESS This driver supports this device\r
57 @retval EFI_ALREADY_STARTED This driver is already running on this device\r
58 @retval other This driver does not support this device\r
59\r
60**/\r
61EFI_STATUS\r
62EFIAPI\r
63PartitionDriverBindingSupported (\r
64 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
65 IN EFI_HANDLE ControllerHandle,\r
66 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
67 )\r
68{\r
69 EFI_STATUS Status;\r
70 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
71 EFI_DISK_IO_PROTOCOL *DiskIo;\r
72 EFI_DEV_PATH *Node;\r
73\r
9be29006 74 //\r
75 // Check RemainingDevicePath validation\r
76 //\r
adbcbf8f 77 if (RemainingDevicePath != NULL) {\r
9be29006 78 //\r
d1102dba 79 // Check if RemainingDevicePath is the End of Device Path Node,\r
9be29006 80 // if yes, go on checking other conditions\r
81 //\r
82 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
83 //\r
84 // If RemainingDevicePath isn't the End of Device Path Node,\r
85 // check its validation\r
86 //\r
87 Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
88 if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||\r
adbcbf8f 89 Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||\r
9be29006 90 DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {\r
490b5ea1 91 return EFI_UNSUPPORTED;\r
9be29006 92 }\r
adbcbf8f 93 }\r
94 }\r
9be29006 95\r
adbcbf8f 96 //\r
97 // Open the IO Abstraction(s) needed to perform the supported test\r
98 //\r
99 Status = gBS->OpenProtocol (\r
100 ControllerHandle,\r
9be29006 101 &gEfiDiskIoProtocolGuid,\r
102 (VOID **) &DiskIo,\r
adbcbf8f 103 This->DriverBindingHandle,\r
104 ControllerHandle,\r
105 EFI_OPEN_PROTOCOL_BY_DRIVER\r
106 );\r
107 if (Status == EFI_ALREADY_STARTED) {\r
108 return EFI_SUCCESS;\r
109 }\r
adbcbf8f 110 if (EFI_ERROR (Status)) {\r
111 return Status;\r
112 }\r
113 //\r
114 // Close the I/O Abstraction(s) used to perform the supported test\r
115 //\r
116 gBS->CloseProtocol (\r
ff61847d 117 ControllerHandle,\r
9be29006 118 &gEfiDiskIoProtocolGuid,\r
ff61847d 119 This->DriverBindingHandle,\r
120 ControllerHandle\r
121 );\r
adbcbf8f 122\r
123 //\r
9be29006 124 // Open the EFI Device Path protocol needed to perform the supported test\r
adbcbf8f 125 //\r
126 Status = gBS->OpenProtocol (\r
127 ControllerHandle,\r
9be29006 128 &gEfiDevicePathProtocolGuid,\r
129 (VOID **) &ParentDevicePath,\r
adbcbf8f 130 This->DriverBindingHandle,\r
131 ControllerHandle,\r
132 EFI_OPEN_PROTOCOL_BY_DRIVER\r
133 );\r
134 if (Status == EFI_ALREADY_STARTED) {\r
135 return EFI_SUCCESS;\r
136 }\r
137\r
138 if (EFI_ERROR (Status)) {\r
139 return Status;\r
140 }\r
9be29006 141\r
adbcbf8f 142 //\r
9be29006 143 // Close protocol, don't use device path protocol in the Support() function\r
adbcbf8f 144 //\r
145 gBS->CloseProtocol (\r
146 ControllerHandle,\r
9be29006 147 &gEfiDevicePathProtocolGuid,\r
adbcbf8f 148 This->DriverBindingHandle,\r
149 ControllerHandle\r
150 );\r
151\r
152 //\r
153 // Open the IO Abstraction(s) needed to perform the supported test\r
154 //\r
155 Status = gBS->OpenProtocol (\r
156 ControllerHandle,\r
157 &gEfiBlockIoProtocolGuid,\r
158 NULL,\r
159 This->DriverBindingHandle,\r
160 ControllerHandle,\r
161 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
162 );\r
21e1018b 163\r
69c0fbd2 164 return Status;\r
adbcbf8f 165}\r
166\r
adbcbf8f 167/**\r
490b5ea1 168 Start this driver on ControllerHandle by opening a Block IO or a Block IO2\r
169 or both, and Disk IO protocol, reading Device Path, and creating a child\r
170 handle with a Disk IO and device path protocol.\r
adbcbf8f 171\r
490b5ea1 172 @param[in] This Protocol instance pointer.\r
173 @param[in] ControllerHandle Handle of device to bind driver to\r
174 @param[in] RemainingDevicePath Optional parameter use to pick a specific child\r
175 device to start.\r
adbcbf8f 176\r
177 @retval EFI_SUCCESS This driver is added to ControllerHandle\r
178 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
179 @retval other This driver does not support this device\r
180\r
181**/\r
182EFI_STATUS\r
183EFIAPI\r
184PartitionDriverBindingStart (\r
185 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
186 IN EFI_HANDLE ControllerHandle,\r
187 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
188 )\r
189{\r
190 EFI_STATUS Status;\r
191 EFI_STATUS OpenStatus;\r
192 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
490b5ea1 193 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
adbcbf8f 194 EFI_DISK_IO_PROTOCOL *DiskIo;\r
493d8e3a 195 EFI_DISK_IO2_PROTOCOL *DiskIo2;\r
adbcbf8f 196 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
197 PARTITION_DETECT_ROUTINE *Routine;\r
9afd0514 198 BOOLEAN MediaPresent;\r
15cc67e6 199 EFI_TPL OldTpl;\r
adbcbf8f 200\r
21e1018b 201 BlockIo2 = NULL;\r
d1102dba 202 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
9be29006 203 //\r
204 // Check RemainingDevicePath validation\r
205 //\r
206 if (RemainingDevicePath != NULL) {\r
207 //\r
d1102dba 208 // Check if RemainingDevicePath is the End of Device Path Node,\r
9be29006 209 // if yes, return EFI_SUCCESS\r
210 //\r
211 if (IsDevicePathEnd (RemainingDevicePath)) {\r
15cc67e6 212 Status = EFI_SUCCESS;\r
213 goto Exit;\r
9be29006 214 }\r
215 }\r
216\r
490b5ea1 217 //\r
218 // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,\r
219 // otherwise, return error.\r
220 //\r
adbcbf8f 221 Status = gBS->OpenProtocol (\r
222 ControllerHandle,\r
223 &gEfiBlockIoProtocolGuid,\r
224 (VOID **) &BlockIo,\r
225 This->DriverBindingHandle,\r
226 ControllerHandle,\r
227 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
228 );\r
229 if (EFI_ERROR (Status)) {\r
15cc67e6 230 goto Exit;\r
adbcbf8f 231 }\r
490b5ea1 232\r
233 Status = gBS->OpenProtocol (\r
234 ControllerHandle,\r
235 &gEfiBlockIo2ProtocolGuid,\r
236 (VOID **) &BlockIo2,\r
237 This->DriverBindingHandle,\r
238 ControllerHandle,\r
493d8e3a 239 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
490b5ea1 240 );\r
493d8e3a
RN
241 if (EFI_ERROR (Status)) {\r
242 BlockIo2 = NULL;\r
243 }\r
490b5ea1 244\r
adbcbf8f 245 //\r
490b5ea1 246 // Get the Device Path Protocol on ControllerHandle's handle.\r
adbcbf8f 247 //\r
248 Status = gBS->OpenProtocol (\r
249 ControllerHandle,\r
250 &gEfiDevicePathProtocolGuid,\r
251 (VOID **) &ParentDevicePath,\r
252 This->DriverBindingHandle,\r
253 ControllerHandle,\r
254 EFI_OPEN_PROTOCOL_BY_DRIVER\r
255 );\r
256 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
15cc67e6 257 goto Exit;\r
adbcbf8f 258 }\r
259\r
493d8e3a
RN
260 //\r
261 // Get the DiskIo and DiskIo2.\r
262 //\r
adbcbf8f 263 Status = gBS->OpenProtocol (\r
264 ControllerHandle,\r
265 &gEfiDiskIoProtocolGuid,\r
266 (VOID **) &DiskIo,\r
267 This->DriverBindingHandle,\r
268 ControllerHandle,\r
269 EFI_OPEN_PROTOCOL_BY_DRIVER\r
270 );\r
271 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
272 gBS->CloseProtocol (\r
273 ControllerHandle,\r
274 &gEfiDevicePathProtocolGuid,\r
275 This->DriverBindingHandle,\r
276 ControllerHandle\r
277 );\r
15cc67e6 278 goto Exit;\r
adbcbf8f 279 }\r
280\r
281 OpenStatus = Status;\r
282\r
493d8e3a
RN
283 Status = gBS->OpenProtocol (\r
284 ControllerHandle,\r
285 &gEfiDiskIo2ProtocolGuid,\r
286 (VOID **) &DiskIo2,\r
287 This->DriverBindingHandle,\r
288 ControllerHandle,\r
289 EFI_OPEN_PROTOCOL_BY_DRIVER\r
290 );\r
291 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
292 DiskIo2 = NULL;\r
293 }\r
294\r
adbcbf8f 295 //\r
9afd0514 296 // Try to read blocks when there's media or it is removable physical partition.\r
adbcbf8f 297 //\r
9afd0514 298 Status = EFI_UNSUPPORTED;\r
299 MediaPresent = BlockIo->Media->MediaPresent;\r
300 if (BlockIo->Media->MediaPresent ||\r
301 (BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) {\r
adbcbf8f 302 //\r
01a68fd3
HW
303 // Try for GPT, then legacy MBR partition types, and then UDF and El Torito.\r
304 // If the media supports a given partition type install child handles to\r
305 // represent the partitions described by the media.\r
adbcbf8f 306 //\r
307 Routine = &mPartitionDetectRoutineTable[0];\r
308 while (*Routine != NULL) {\r
309 Status = (*Routine) (\r
310 This,\r
311 ControllerHandle,\r
312 DiskIo,\r
493d8e3a 313 DiskIo2,\r
adbcbf8f 314 BlockIo,\r
490b5ea1 315 BlockIo2,\r
adbcbf8f 316 ParentDevicePath\r
317 );\r
9afd0514 318 if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {\r
adbcbf8f 319 break;\r
320 }\r
321 Routine++;\r
322 }\r
323 }\r
324 //\r
325 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),\r
326 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the\r
327 // driver. So don't try to close them. Otherwise, we will break the dependency\r
328 // between the controller and the driver set up before.\r
329 //\r
d1102dba 330 // In the case that when the media changes on a device it will Reinstall the\r
9afd0514 331 // BlockIo interaface. This will cause a call to our Stop(), and a subsequent\r
332 // reentrant call to our Start() successfully. We should leave the device open\r
333 // when this happen. The "media change" case includes either the status is\r
d1102dba
LG
334 // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.\r
335 //\r
9afd0514 336 if (EFI_ERROR (Status) &&\r
337 !EFI_ERROR (OpenStatus) &&\r
338 Status != EFI_MEDIA_CHANGED &&\r
339 !(MediaPresent && Status == EFI_NO_MEDIA)) {\r
adbcbf8f 340 gBS->CloseProtocol (\r
341 ControllerHandle,\r
342 &gEfiDiskIoProtocolGuid,\r
343 This->DriverBindingHandle,\r
344 ControllerHandle\r
345 );\r
490b5ea1 346 //\r
80c83a69 347 // Close Parent DiskIo2 if has.\r
d1102dba 348 //\r
490b5ea1 349 gBS->CloseProtocol (\r
350 ControllerHandle,\r
80c83a69 351 &gEfiDiskIo2ProtocolGuid,\r
490b5ea1 352 This->DriverBindingHandle,\r
353 ControllerHandle\r
354 );\r
adbcbf8f 355\r
356 gBS->CloseProtocol (\r
357 ControllerHandle,\r
358 &gEfiDevicePathProtocolGuid,\r
359 This->DriverBindingHandle,\r
360 ControllerHandle\r
361 );\r
362 }\r
363\r
15cc67e6 364Exit:\r
365 gBS->RestoreTPL (OldTpl);\r
adbcbf8f 366 return Status;\r
367}\r
368\r
adbcbf8f 369/**\r
48557c65 370 Stop this driver on ControllerHandle. Support stopping any child handles\r
adbcbf8f 371 created by this driver.\r
372\r
373 @param This Protocol instance pointer.\r
374 @param ControllerHandle Handle of device to stop driver on\r
375 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
376 children is zero stop the entire bus driver.\r
377 @param ChildHandleBuffer List of Child Handles to Stop.\r
378\r
379 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
380 @retval other This driver was not removed from this device\r
381\r
382**/\r
383EFI_STATUS\r
384EFIAPI\r
385PartitionDriverBindingStop (\r
386 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
387 IN EFI_HANDLE ControllerHandle,\r
388 IN UINTN NumberOfChildren,\r
389 IN EFI_HANDLE *ChildHandleBuffer\r
390 )\r
391{\r
392 EFI_STATUS Status;\r
393 UINTN Index;\r
394 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
490b5ea1 395 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
adbcbf8f 396 BOOLEAN AllChildrenStopped;\r
397 PARTITION_PRIVATE_DATA *Private;\r
398 EFI_DISK_IO_PROTOCOL *DiskIo;\r
709c9fd5 399 EFI_GUID *TypeGuid;\r
adbcbf8f 400\r
490b5ea1 401 BlockIo = NULL;\r
402 BlockIo2 = NULL;\r
403 Private = NULL;\r
404\r
adbcbf8f 405 if (NumberOfChildren == 0) {\r
e3325721
HW
406 //\r
407 // In the case of re-entry of the PartitionDriverBindingStop, the\r
408 // NumberOfChildren may not reflect the actual number of children on the\r
409 // bus driver. Hence, additional check is needed here.\r
410 //\r
411 if (HasChildren (ControllerHandle)) {\r
412 DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: Still has child.\n"));\r
413 return EFI_DEVICE_ERROR;\r
414 }\r
415\r
adbcbf8f 416 //\r
417 // Close the bus driver\r
418 //\r
419 gBS->CloseProtocol (\r
420 ControllerHandle,\r
421 &gEfiDiskIoProtocolGuid,\r
422 This->DriverBindingHandle,\r
423 ControllerHandle\r
424 );\r
490b5ea1 425 //\r
426 // Close Parent BlockIO2 if has.\r
d1102dba 427 //\r
490b5ea1 428 gBS->CloseProtocol (\r
429 ControllerHandle,\r
493d8e3a 430 &gEfiDiskIo2ProtocolGuid,\r
490b5ea1 431 This->DriverBindingHandle,\r
432 ControllerHandle\r
433 );\r
adbcbf8f 434\r
435 gBS->CloseProtocol (\r
436 ControllerHandle,\r
437 &gEfiDevicePathProtocolGuid,\r
438 This->DriverBindingHandle,\r
439 ControllerHandle\r
440 );\r
adbcbf8f 441 return EFI_SUCCESS;\r
442 }\r
443\r
444 AllChildrenStopped = TRUE;\r
445 for (Index = 0; Index < NumberOfChildren; Index++) {\r
490b5ea1 446 gBS->OpenProtocol (\r
447 ChildHandleBuffer[Index],\r
448 &gEfiBlockIoProtocolGuid,\r
449 (VOID **) &BlockIo,\r
450 This->DriverBindingHandle,\r
451 ControllerHandle,\r
452 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
453 );\r
454 //\r
455 // Try to locate BlockIo2.\r
456 //\r
457 gBS->OpenProtocol (\r
458 ChildHandleBuffer[Index],\r
459 &gEfiBlockIo2ProtocolGuid,\r
460 (VOID **) &BlockIo2,\r
461 This->DriverBindingHandle,\r
462 ControllerHandle,\r
463 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
d1102dba 464 );\r
490b5ea1 465\r
d0844d13 466\r
467 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);\r
e3325721
HW
468 if (Private->InStop) {\r
469 //\r
470 // If the child handle is going to be stopped again during the re-entry\r
471 // of DriverBindingStop, just do nothing.\r
472 //\r
473 break;\r
474 }\r
475 Private->InStop = TRUE;\r
adbcbf8f 476\r
e3325721
HW
477 BlockIo->FlushBlocks (BlockIo);\r
478\r
479 if (BlockIo2 != NULL) {\r
480 Status = BlockIo2->FlushBlocksEx (BlockIo2, NULL);\r
481 DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status));\r
482 } else {\r
483 Status = EFI_SUCCESS;\r
484 }\r
485\r
486 gBS->CloseProtocol (\r
487 ControllerHandle,\r
488 &gEfiDiskIoProtocolGuid,\r
489 This->DriverBindingHandle,\r
490 ChildHandleBuffer[Index]\r
491 );\r
709c9fd5
JB
492\r
493 if (IsZeroGuid (&Private->TypeGuid)) {\r
494 TypeGuid = NULL;\r
495 } else {\r
496 TypeGuid = &Private->TypeGuid;\r
497 }\r
498\r
490b5ea1 499 //\r
500 // All Software protocols have be freed from the handle so remove it.\r
501 // Remove the BlockIo Protocol if has.\r
502 // Remove the BlockIo2 Protocol if has.\r
503 //\r
504 if (BlockIo2 != NULL) {\r
e3325721
HW
505 //\r
506 // Some device drivers might re-install the BlockIO(2) protocols for a\r
507 // media change condition. Therefore, if the FlushBlocksEx returned with\r
508 // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential\r
509 // reference of already stopped child handle.\r
510 //\r
511 if (Status != EFI_MEDIA_CHANGED) {\r
512 Status = gBS->UninstallMultipleProtocolInterfaces (\r
513 ChildHandleBuffer[Index],\r
514 &gEfiDevicePathProtocolGuid,\r
515 Private->DevicePath,\r
516 &gEfiBlockIoProtocolGuid,\r
517 &Private->BlockIo,\r
518 &gEfiBlockIo2ProtocolGuid,\r
519 &Private->BlockIo2,\r
3a3d62d2
HW
520 &gEfiPartitionInfoProtocolGuid,\r
521 &Private->PartitionInfo,\r
709c9fd5 522 TypeGuid,\r
e3325721
HW
523 NULL,\r
524 NULL\r
525 );\r
526 }\r
490b5ea1 527 } else {\r
490b5ea1 528 Status = gBS->UninstallMultipleProtocolInterfaces (\r
529 ChildHandleBuffer[Index],\r
530 &gEfiDevicePathProtocolGuid,\r
531 Private->DevicePath,\r
532 &gEfiBlockIoProtocolGuid,\r
533 &Private->BlockIo,\r
3a3d62d2
HW
534 &gEfiPartitionInfoProtocolGuid,\r
535 &Private->PartitionInfo,\r
709c9fd5 536 TypeGuid,\r
490b5ea1 537 NULL,\r
538 NULL\r
539 );\r
540 }\r
adbcbf8f 541\r
490b5ea1 542 if (EFI_ERROR (Status)) {\r
e3325721 543 Private->InStop = FALSE;\r
490b5ea1 544 gBS->OpenProtocol (\r
545 ControllerHandle,\r
546 &gEfiDiskIoProtocolGuid,\r
547 (VOID **) &DiskIo,\r
548 This->DriverBindingHandle,\r
549 ChildHandleBuffer[Index],\r
550 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
551 );\r
552 } else {\r
553 FreePool (Private->DevicePath);\r
554 FreePool (Private);\r
adbcbf8f 555 }\r
556\r
557 if (EFI_ERROR (Status)) {\r
558 AllChildrenStopped = FALSE;\r
e3325721
HW
559 if (Status == EFI_MEDIA_CHANGED) {\r
560 break;\r
561 }\r
adbcbf8f 562 }\r
563 }\r
564\r
565 if (!AllChildrenStopped) {\r
566 return EFI_DEVICE_ERROR;\r
567 }\r
568\r
569 return EFI_SUCCESS;\r
570}\r
571\r
572\r
573/**\r
574 Reset the Block Device.\r
575\r
576 @param This Protocol instance pointer.\r
577 @param ExtendedVerification Driver may perform diagnostics on reset.\r
578\r
579 @retval EFI_SUCCESS The device was reset.\r
580 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
581 not be reset.\r
582\r
583**/\r
adbcbf8f 584EFI_STATUS\r
585EFIAPI\r
586PartitionReset (\r
587 IN EFI_BLOCK_IO_PROTOCOL *This,\r
588 IN BOOLEAN ExtendedVerification\r
589 )\r
590{\r
591 PARTITION_PRIVATE_DATA *Private;\r
592\r
593 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
594\r
595 return Private->ParentBlockIo->Reset (\r
596 Private->ParentBlockIo,\r
597 ExtendedVerification\r
598 );\r
599}\r
600\r
fcf5e49d
RN
601/**\r
602 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED\r
603 for no media or media change case. Otherwise DefaultStatus is returned.\r
604\r
605 @param DiskIo Pointer to the DiskIo instance.\r
606 @param MediaId Id of the media, changes every time the media is replaced.\r
607 @param DefaultStatus The default status to return when it's not the no media\r
608 or media change case.\r
609\r
610 @retval EFI_NO_MEDIA There is no media.\r
611 @retval EFI_MEDIA_CHANGED The media was changed.\r
612 @retval others The default status to return.\r
613**/\r
614EFI_STATUS\r
615ProbeMediaStatus (\r
616 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
617 IN UINT32 MediaId,\r
618 IN EFI_STATUS DefaultStatus\r
619 )\r
620{\r
621 EFI_STATUS Status;\r
df473cc1 622 UINT8 Buffer[1];\r
fcf5e49d
RN
623\r
624 //\r
df473cc1
RC
625 // Read 1 byte from offset 0 to check if the MediaId is still valid.\r
626 // The reading operation is synchronious thus it is not worth it to\r
627 // allocate a buffer from the pool. The destination buffer for the\r
628 // data is in the stack.\r
fcf5e49d 629 //\r
df473cc1 630 Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, (VOID*)Buffer);\r
fcf5e49d
RN
631 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {\r
632 return Status;\r
633 }\r
634 return DefaultStatus;\r
635}\r
adbcbf8f 636\r
637/**\r
638 Read by using the Disk IO protocol on the parent device. Lba addresses\r
639 must be converted to byte offsets.\r
640\r
641 @param This Protocol instance pointer.\r
642 @param MediaId Id of the media, changes every time the media is replaced.\r
643 @param Lba The starting Logical Block Address to read from\r
644 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
645 @param Buffer Buffer containing read data\r
646\r
647 @retval EFI_SUCCESS The data was read correctly from the device.\r
648 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
649 @retval EFI_NO_MEDIA There is no media in the device.\r
650 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
651 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
652 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not\r
653 valid for the device.\r
654\r
655**/\r
adbcbf8f 656EFI_STATUS\r
657EFIAPI\r
658PartitionReadBlocks (\r
659 IN EFI_BLOCK_IO_PROTOCOL *This,\r
660 IN UINT32 MediaId,\r
661 IN EFI_LBA Lba,\r
662 IN UINTN BufferSize,\r
663 OUT VOID *Buffer\r
664 )\r
665{\r
666 PARTITION_PRIVATE_DATA *Private;\r
667 UINT64 Offset;\r
668\r
669 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
670\r
671 if (BufferSize % Private->BlockSize != 0) {\r
fcf5e49d 672 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);\r
adbcbf8f 673 }\r
674\r
675 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
676 if (Offset + BufferSize > Private->End) {\r
fcf5e49d 677 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);\r
adbcbf8f 678 }\r
679 //\r
680 // Because some kinds of partition have different block size from their parent\r
681 // device, we call the Disk IO protocol on the parent device, not the Block IO\r
682 // protocol\r
683 //\r
684 return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);\r
685}\r
686\r
687/**\r
688 Write by using the Disk IO protocol on the parent device. Lba addresses\r
689 must be converted to byte offsets.\r
690\r
490b5ea1 691 @param[in] This Protocol instance pointer.\r
692 @param[in] MediaId Id of the media, changes every time the media is replaced.\r
693 @param[in] Lba The starting Logical Block Address to read from\r
694 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
695 @param[in] Buffer Buffer containing data to be written to device.\r
adbcbf8f 696\r
697 @retval EFI_SUCCESS The data was written correctly to the device.\r
698 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
699 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
700 @retval EFI_NO_MEDIA There is no media in the device.\r
701 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
702 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
703 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not\r
704 valid for the device.\r
705\r
706**/\r
adbcbf8f 707EFI_STATUS\r
708EFIAPI\r
709PartitionWriteBlocks (\r
710 IN EFI_BLOCK_IO_PROTOCOL *This,\r
711 IN UINT32 MediaId,\r
712 IN EFI_LBA Lba,\r
713 IN UINTN BufferSize,\r
490b5ea1 714 IN VOID *Buffer\r
adbcbf8f 715 )\r
716{\r
717 PARTITION_PRIVATE_DATA *Private;\r
718 UINT64 Offset;\r
719\r
720 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
721\r
722 if (BufferSize % Private->BlockSize != 0) {\r
fcf5e49d 723 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);\r
adbcbf8f 724 }\r
725\r
726 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
727 if (Offset + BufferSize > Private->End) {\r
fcf5e49d 728 return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);\r
adbcbf8f 729 }\r
730 //\r
731 // Because some kinds of partition have different block size from their parent\r
732 // device, we call the Disk IO protocol on the parent device, not the Block IO\r
733 // protocol\r
734 //\r
735 return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);\r
736}\r
737\r
738\r
739/**\r
740 Flush the parent Block Device.\r
741\r
742 @param This Protocol instance pointer.\r
743\r
744 @retval EFI_SUCCESS All outstanding data was written to the device\r
745 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data\r
746 @retval EFI_NO_MEDIA There is no media in the device.\r
747\r
748**/\r
adbcbf8f 749EFI_STATUS\r
750EFIAPI\r
751PartitionFlushBlocks (\r
752 IN EFI_BLOCK_IO_PROTOCOL *This\r
753 )\r
754{\r
755 PARTITION_PRIVATE_DATA *Private;\r
756\r
757 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);\r
758\r
759 return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);\r
760}\r
761\r
65fd3952
RN
762/**\r
763 Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED\r
764 for no media or media change case. Otherwise DefaultStatus is returned.\r
765\r
493d8e3a 766 @param DiskIo2 Pointer to the DiskIo2 instance.\r
65fd3952
RN
767 @param MediaId Id of the media, changes every time the media is replaced.\r
768 @param DefaultStatus The default status to return when it's not the no media\r
769 or media change case.\r
770\r
771 @retval EFI_NO_MEDIA There is no media.\r
772 @retval EFI_MEDIA_CHANGED The media was changed.\r
773 @retval others The default status to return.\r
774**/\r
775EFI_STATUS\r
776ProbeMediaStatusEx (\r
493d8e3a 777 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,\r
65fd3952
RN
778 IN UINT32 MediaId,\r
779 IN EFI_STATUS DefaultStatus\r
780 )\r
781{\r
782 EFI_STATUS Status;\r
68599525 783 UINT8 Buffer[1];\r
65fd3952
RN
784\r
785 //\r
68599525
RN
786 // Read 1 byte from offset 0 to check if the MediaId is still valid.\r
787 // The reading operation is synchronious thus it is not worth it to\r
788 // allocate a buffer from the pool. The destination buffer for the\r
789 // data is in the stack.\r
65fd3952 790 //\r
68599525 791 Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, (VOID*)Buffer);\r
65fd3952
RN
792 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {\r
793 return Status;\r
794 }\r
795 return DefaultStatus;\r
796}\r
797\r
490b5ea1 798/**\r
799 Reset the Block Device throught Block I/O2 protocol.\r
800\r
801 @param This Protocol instance pointer.\r
802 @param ExtendedVerification Driver may perform diagnostics on reset.\r
803\r
804 @retval EFI_SUCCESS The device was reset.\r
805 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
806 not be reset.\r
807\r
808**/\r
809EFI_STATUS\r
810EFIAPI\r
811PartitionResetEx (\r
812 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
813 IN BOOLEAN ExtendedVerification\r
814 )\r
815{\r
816 PARTITION_PRIVATE_DATA *Private;\r
817\r
818 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
819\r
820 return Private->ParentBlockIo2->Reset (\r
821 Private->ParentBlockIo2,\r
822 ExtendedVerification\r
823 );\r
824}\r
825\r
493d8e3a
RN
826/**\r
827 The general callback for the DiskIo2 interfaces.\r
828 @param Event Event whose notification function is being invoked.\r
829 @param Context The pointer to the notification function's context,\r
830 which points to the PARTITION_ACCESS_TASK instance.\r
831**/\r
832VOID\r
833EFIAPI\r
834PartitionOnAccessComplete (\r
835 IN EFI_EVENT Event,\r
836 IN VOID *Context\r
837 )\r
838{\r
839 PARTITION_ACCESS_TASK *Task;\r
840\r
841 Task = (PARTITION_ACCESS_TASK *) Context;\r
842\r
843 gBS->CloseEvent (Event);\r
844\r
845 Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus;\r
846 gBS->SignalEvent (Task->BlockIo2Token->Event);\r
847\r
848 FreePool (Task);\r
849}\r
850\r
851/**\r
852 Create a new PARTITION_ACCESS_TASK instance.\r
853\r
854 @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.\r
855\r
856 @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.\r
857**/\r
858PARTITION_ACCESS_TASK *\r
859PartitionCreateAccessTask (\r
860 IN EFI_BLOCK_IO2_TOKEN *Token\r
861 )\r
862{\r
863 EFI_STATUS Status;\r
864 PARTITION_ACCESS_TASK *Task;\r
865\r
866 Task = AllocatePool (sizeof (*Task));\r
867 if (Task == NULL) {\r
868 return NULL;\r
869 }\r
870\r
871 Status = gBS->CreateEvent (\r
872 EVT_NOTIFY_SIGNAL,\r
80c83a69 873 TPL_NOTIFY,\r
493d8e3a
RN
874 PartitionOnAccessComplete,\r
875 Task,\r
876 &Task->DiskIo2Token.Event\r
877 );\r
878 if (EFI_ERROR (Status)) {\r
879 FreePool (Task);\r
880 return NULL;\r
881 }\r
882\r
883 Task->BlockIo2Token = Token;\r
884\r
885 return Task;\r
886}\r
887\r
490b5ea1 888/**\r
889 Read BufferSize bytes from Lba into Buffer.\r
d1102dba 890\r
490b5ea1 891 This function reads the requested number of blocks from the device. All the\r
892 blocks are read, or an error is returned.\r
893 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and\r
894 non-blocking I/O is being used, the Event associated with this request will\r
895 not be signaled.\r
896\r
897 @param[in] This Indicates a pointer to the calling context.\r
d1102dba 898 @param[in] MediaId Id of the media, changes every time the media is\r
490b5ea1 899 replaced.\r
900 @param[in] Lba The starting Logical Block Address to read from.\r
d1102dba
LG
901 @param[in, out] Token A pointer to the token associated with the transaction.\r
902 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
903 @param[out] Buffer A pointer to the destination buffer for the data. The\r
904 caller is responsible for either having implicit or\r
490b5ea1 905 explicit ownership of the buffer.\r
906\r
907 @retval EFI_SUCCESS The read request was queued if Token->Event is\r
908 not NULL.The data was read correctly from the\r
909 device if the Token->Event is NULL.\r
910 @retval EFI_DEVICE_ERROR The device reported an error while performing\r
911 the read.\r
912 @retval EFI_NO_MEDIA There is no media in the device.\r
913 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
914 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
915 intrinsic block size of the device.\r
d1102dba 916 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
490b5ea1 917 or the buffer is not on proper alignment.\r
918 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
919 of resources.\r
920**/\r
921EFI_STATUS\r
922EFIAPI\r
923PartitionReadBlocksEx (\r
924 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
925 IN UINT32 MediaId,\r
926 IN EFI_LBA Lba,\r
927 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
928 IN UINTN BufferSize,\r
929 OUT VOID *Buffer\r
930 )\r
931{\r
493d8e3a 932 EFI_STATUS Status;\r
490b5ea1 933 PARTITION_PRIVATE_DATA *Private;\r
934 UINT64 Offset;\r
493d8e3a 935 PARTITION_ACCESS_TASK *Task;\r
490b5ea1 936\r
65fd3952
RN
937 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
938\r
490b5ea1 939 if (BufferSize % Private->BlockSize != 0) {\r
493d8e3a 940 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);\r
490b5ea1 941 }\r
942\r
943 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
944 if (Offset + BufferSize > Private->End) {\r
493d8e3a 945 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);\r
490b5ea1 946 }\r
947\r
493d8e3a
RN
948 if ((Token != NULL) && (Token->Event != NULL)) {\r
949 Task = PartitionCreateAccessTask (Token);\r
950 if (Task == NULL) {\r
951 return EFI_OUT_OF_RESOURCES;\r
952 }\r
490b5ea1 953\r
493d8e3a
RN
954 Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);\r
955 if (EFI_ERROR (Status)) {\r
956 gBS->CloseEvent (Task->DiskIo2Token.Event);\r
957 FreePool (Task);\r
958 }\r
959 } else {\r
960 Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);\r
490b5ea1 961 }\r
962\r
493d8e3a 963 return Status;\r
490b5ea1 964}\r
965\r
966/**\r
967 Write BufferSize bytes from Lba into Buffer.\r
968\r
969 This function writes the requested number of blocks to the device. All blocks\r
970 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,\r
971 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is\r
972 being used, the Event associated with this request will not be signaled.\r
973\r
974 @param[in] This Indicates a pointer to the calling context.\r
975 @param[in] MediaId The media ID that the write request is for.\r
976 @param[in] Lba The starting logical block address to be written. The\r
977 caller is responsible for writing to only legitimate\r
978 locations.\r
979 @param[in, out] Token A pointer to the token associated with the transaction.\r
980 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
981 @param[in] Buffer A pointer to the source buffer for the data.\r
982\r
983 @retval EFI_SUCCESS The write request was queued if Event is not NULL.\r
984 The data was written correctly to the device if\r
985 the Event is NULL.\r
986 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
987 @retval EFI_NO_MEDIA There is no media in the device.\r
988 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
989 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
990 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
d1102dba 991 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
490b5ea1 992 or the buffer is not on proper alignment.\r
993 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
994 of resources.\r
995\r
996**/\r
997EFI_STATUS\r
998EFIAPI\r
999PartitionWriteBlocksEx (\r
1000 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
1001 IN UINT32 MediaId,\r
1002 IN EFI_LBA Lba,\r
1003 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
1004 IN UINTN BufferSize,\r
1005 IN VOID *Buffer\r
1006 )\r
1007{\r
493d8e3a 1008 EFI_STATUS Status;\r
490b5ea1 1009 PARTITION_PRIVATE_DATA *Private;\r
1010 UINT64 Offset;\r
493d8e3a 1011 PARTITION_ACCESS_TASK *Task;\r
490b5ea1 1012\r
65fd3952
RN
1013 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
1014\r
490b5ea1 1015 if (BufferSize % Private->BlockSize != 0) {\r
493d8e3a 1016 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);\r
490b5ea1 1017 }\r
1018\r
1019 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;\r
1020 if (Offset + BufferSize > Private->End) {\r
493d8e3a 1021 return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);\r
490b5ea1 1022 }\r
d1102dba 1023\r
493d8e3a
RN
1024 if ((Token != NULL) && (Token->Event != NULL)) {\r
1025 Task = PartitionCreateAccessTask (Token);\r
1026 if (Task == NULL) {\r
1027 return EFI_OUT_OF_RESOURCES;\r
1028 }\r
490b5ea1 1029\r
493d8e3a
RN
1030 Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);\r
1031 if (EFI_ERROR (Status)) {\r
1032 gBS->CloseEvent (Task->DiskIo2Token.Event);\r
1033 FreePool (Task);\r
1034 }\r
1035 } else {\r
1036 Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);\r
490b5ea1 1037 }\r
493d8e3a 1038 return Status;\r
490b5ea1 1039}\r
1040\r
1041/**\r
1042 Flush the Block Device.\r
d1102dba 1043\r
490b5ea1 1044 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED\r
1045 is returned and non-blocking I/O is being used, the Event associated with\r
d1102dba 1046 this request will not be signaled.\r
490b5ea1 1047\r
1048 @param[in] This Indicates a pointer to the calling context.\r
86d8e199 1049 @param[in, out] Token A pointer to the token associated with the transaction\r
490b5ea1 1050\r
1051 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.\r
1052 All outstanding data was written correctly to the\r
1053 device if the Event is NULL.\r
1054 @retval EFI_DEVICE_ERROR The device reported an error while writting back\r
1055 the data.\r
1056 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
1057 @retval EFI_NO_MEDIA There is no media in the device.\r
1058 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
1059 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
1060 of resources.\r
1061\r
1062**/\r
1063EFI_STATUS\r
1064EFIAPI\r
1065PartitionFlushBlocksEx (\r
1066 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
1067 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
1068 )\r
1069{\r
493d8e3a 1070 EFI_STATUS Status;\r
490b5ea1 1071 PARTITION_PRIVATE_DATA *Private;\r
493d8e3a 1072 PARTITION_ACCESS_TASK *Task;\r
490b5ea1 1073\r
1074 Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);\r
1075\r
493d8e3a
RN
1076 if ((Token != NULL) && (Token->Event != NULL)) {\r
1077 Task = PartitionCreateAccessTask (Token);\r
1078 if (Task == NULL) {\r
1079 return EFI_OUT_OF_RESOURCES;\r
1080 }\r
490b5ea1 1081\r
493d8e3a
RN
1082 Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token);\r
1083 if (EFI_ERROR (Status)) {\r
1084 gBS->CloseEvent (Task->DiskIo2Token.Event);\r
1085 FreePool (Task);\r
1086 }\r
1087 } else {\r
1088 Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL);\r
1089 }\r
1090 return Status;\r
490b5ea1 1091}\r
adbcbf8f 1092\r
1093\r
1094/**\r
1095 Create a child handle for a logical block device that represents the\r
1096 bytes Start to End of the Parent Block IO device.\r
1097\r
490b5ea1 1098 @param[in] This Protocol instance pointer.\r
1099 @param[in] ParentHandle Parent Handle for new child.\r
1100 @param[in] ParentDiskIo Parent DiskIo interface.\r
493d8e3a 1101 @param[in] ParentDiskIo2 Parent DiskIo2 interface.\r
490b5ea1 1102 @param[in] ParentBlockIo Parent BlockIo interface.\r
1103 @param[in] ParentBlockIo2 Parent BlockIo2 interface.\r
1104 @param[in] ParentDevicePath Parent Device Path.\r
1105 @param[in] DevicePathNode Child Device Path node.\r
3a3d62d2 1106 @param[in] PartitionInfo Child Partition Information interface.\r
490b5ea1 1107 @param[in] Start Start Block.\r
1108 @param[in] End End Block.\r
1109 @param[in] BlockSize Child block size.\r
709c9fd5 1110 @param[in] TypeGuid Partition GUID Type.\r
490b5ea1 1111\r
1112 @retval EFI_SUCCESS A child handle was added.\r
1113 @retval other A child handle was not added.\r
adbcbf8f 1114\r
1115**/\r
1116EFI_STATUS\r
1117PartitionInstallChildHandle (\r
1118 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1119 IN EFI_HANDLE ParentHandle,\r
1120 IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,\r
493d8e3a 1121 IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,\r
adbcbf8f 1122 IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,\r
490b5ea1 1123 IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,\r
adbcbf8f 1124 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
1125 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,\r
3a3d62d2 1126 IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,\r
adbcbf8f 1127 IN EFI_LBA Start,\r
1128 IN EFI_LBA End,\r
709c9fd5
JB
1129 IN UINT32 BlockSize,\r
1130 IN EFI_GUID *TypeGuid\r
adbcbf8f 1131 )\r
1132{\r
1133 EFI_STATUS Status;\r
1134 PARTITION_PRIVATE_DATA *Private;\r
1135\r
490b5ea1 1136 Status = EFI_SUCCESS;\r
adbcbf8f 1137 Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));\r
1138 if (Private == NULL) {\r
1139 return EFI_OUT_OF_RESOURCES;\r
1140 }\r
1141\r
1142 Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;\r
1143\r
1144 Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);\r
1145 Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);\r
1146\r
1147 Private->BlockSize = BlockSize;\r
1148 Private->ParentBlockIo = ParentBlockIo;\r
490b5ea1 1149 Private->ParentBlockIo2 = ParentBlockIo2;\r
adbcbf8f 1150 Private->DiskIo = ParentDiskIo;\r
493d8e3a 1151 Private->DiskIo2 = ParentDiskIo2;\r
adbcbf8f 1152\r
d0844d13 1153 //\r
1154 // Set the BlockIO into Private Data.\r
1155 //\r
1156 Private->BlockIo.Revision = ParentBlockIo->Revision;\r
d1102dba 1157\r
d0844d13 1158 Private->BlockIo.Media = &Private->Media;\r
1159 CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
490b5ea1 1160\r
d0844d13 1161 Private->BlockIo.Reset = PartitionReset;\r
1162 Private->BlockIo.ReadBlocks = PartitionReadBlocks;\r
1163 Private->BlockIo.WriteBlocks = PartitionWriteBlocks;\r
1164 Private->BlockIo.FlushBlocks = PartitionFlushBlocks;\r
490b5ea1 1165\r
d0844d13 1166 //\r
1167 // Set the BlockIO2 into Private Data.\r
1168 //\r
493d8e3a
RN
1169 if (Private->DiskIo2 != NULL) {\r
1170 ASSERT (Private->ParentBlockIo2 != NULL);\r
490b5ea1 1171 Private->BlockIo2.Media = &Private->Media2;\r
1172 CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
1173\r
1174 Private->BlockIo2.Reset = PartitionResetEx;\r
1175 Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;\r
1176 Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;\r
d1102dba 1177 Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;\r
490b5ea1 1178 }\r
67f802ed 1179\r
67f802ed 1180 Private->Media.IoAlign = 0;\r
490b5ea1 1181 Private->Media.LogicalPartition = TRUE;\r
adbcbf8f 1182 Private->Media.LastBlock = DivU64x32 (\r
1183 MultU64x32 (\r
1184 End - Start + 1,\r
d0844d13 1185 ParentBlockIo->Media->BlockSize\r
adbcbf8f 1186 ),\r
490b5ea1 1187 BlockSize\r
adbcbf8f 1188 ) - 1;\r
1189\r
67f802ed 1190 Private->Media.BlockSize = (UINT32) BlockSize;\r
adbcbf8f 1191\r
493d8e3a 1192 Private->Media2.IoAlign = 0;\r
490b5ea1 1193 Private->Media2.LogicalPartition = TRUE;\r
1194 Private->Media2.LastBlock = Private->Media.LastBlock;\r
1195 Private->Media2.BlockSize = (UINT32) BlockSize;\r
1196\r
fe3b68bb 1197 //\r
0e87144e 1198 // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0\r
fe3b68bb
RN
1199 // for logical partitions.\r
1200 //\r
1201 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {\r
c582ad45
EB
1202 Private->Media.LowestAlignedLba = 0;\r
1203 Private->Media.LogicalBlocksPerPhysicalBlock = 0;\r
1204 Private->Media2.LowestAlignedLba = 0;\r
1205 Private->Media2.LogicalBlocksPerPhysicalBlock = 0;\r
0e87144e 1206 if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {\r
c582ad45
EB
1207 Private->Media.OptimalTransferLengthGranularity = 0;\r
1208 Private->Media2.OptimalTransferLengthGranularity = 0;\r
0e87144e 1209 }\r
fe3b68bb
RN
1210 }\r
1211\r
490b5ea1 1212 Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);\r
adbcbf8f 1213\r
1214 if (Private->DevicePath == NULL) {\r
1215 FreePool (Private);\r
1216 return EFI_OUT_OF_RESOURCES;\r
1217 }\r
1218\r
3a3d62d2
HW
1219 //\r
1220 // Set the PartitionInfo into Private Data.\r
1221 //\r
1222 CopyMem (&Private->PartitionInfo, PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));\r
1223\r
709c9fd5
JB
1224 if (TypeGuid != NULL) {\r
1225 CopyGuid(&(Private->TypeGuid), TypeGuid);\r
adbcbf8f 1226 } else {\r
709c9fd5 1227 ZeroMem ((VOID *)&(Private->TypeGuid), sizeof (EFI_GUID));\r
adbcbf8f 1228 }\r
490b5ea1 1229\r
adbcbf8f 1230 //\r
d1102dba 1231 // Create the new handle.\r
adbcbf8f 1232 //\r
1233 Private->Handle = NULL;\r
493d8e3a 1234 if (Private->DiskIo2 != NULL) {\r
490b5ea1 1235 Status = gBS->InstallMultipleProtocolInterfaces (\r
1236 &Private->Handle,\r
1237 &gEfiDevicePathProtocolGuid,\r
1238 Private->DevicePath,\r
1239 &gEfiBlockIoProtocolGuid,\r
1240 &Private->BlockIo,\r
1241 &gEfiBlockIo2ProtocolGuid,\r
1242 &Private->BlockIo2,\r
3a3d62d2
HW
1243 &gEfiPartitionInfoProtocolGuid,\r
1244 &Private->PartitionInfo,\r
709c9fd5 1245 TypeGuid,\r
490b5ea1 1246 NULL,\r
1247 NULL\r
1248 );\r
d1102dba 1249 } else {\r
d0844d13 1250 Status = gBS->InstallMultipleProtocolInterfaces (\r
1251 &Private->Handle,\r
1252 &gEfiDevicePathProtocolGuid,\r
1253 Private->DevicePath,\r
1254 &gEfiBlockIoProtocolGuid,\r
1255 &Private->BlockIo,\r
3a3d62d2
HW
1256 &gEfiPartitionInfoProtocolGuid,\r
1257 &Private->PartitionInfo,\r
709c9fd5 1258 TypeGuid,\r
d0844d13 1259 NULL,\r
1260 NULL\r
1261 );\r
490b5ea1 1262 }\r
adbcbf8f 1263\r
1264 if (!EFI_ERROR (Status)) {\r
1265 //\r
1266 // Open the Parent Handle for the child\r
1267 //\r
1268 Status = gBS->OpenProtocol (\r
1269 ParentHandle,\r
1270 &gEfiDiskIoProtocolGuid,\r
1271 (VOID **) &ParentDiskIo,\r
1272 This->DriverBindingHandle,\r
1273 Private->Handle,\r
1274 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1275 );\r
1276 } else {\r
1277 FreePool (Private->DevicePath);\r
1278 FreePool (Private);\r
c7195b9e
ZG
1279\r
1280 //\r
1281 // if the Status == EFI_ALREADY_STARTED, it means the child handles\r
1282 // are already installed. So return EFI_SUCCESS to avoid do the next\r
1283 // partition type check.\r
1284 //\r
1285 if (Status == EFI_ALREADY_STARTED) {\r
1286 Status = EFI_SUCCESS;\r
1287 }\r
adbcbf8f 1288 }\r
1289\r
1290 return Status;\r
1291}\r
1292\r
1293\r
1294/**\r
1295 The user Entry Point for module Partition. The user code starts with this function.\r
1296\r
d1102dba 1297 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
adbcbf8f 1298 @param[in] SystemTable A pointer to the EFI System Table.\r
d1102dba 1299\r
adbcbf8f 1300 @retval EFI_SUCCESS The entry point is executed successfully.\r
1301 @retval other Some error occurs when executing this entry point.\r
1302\r
1303**/\r
1304EFI_STATUS\r
1305EFIAPI\r
1306InitializePartition (\r
1307 IN EFI_HANDLE ImageHandle,\r
1308 IN EFI_SYSTEM_TABLE *SystemTable\r
1309 )\r
1310{\r
1311 EFI_STATUS Status;\r
1312\r
1313 //\r
1314 // Install driver model protocol(s).\r
1315 //\r
d38a0f44 1316 Status = EfiLibInstallDriverBindingComponentName2 (\r
adbcbf8f 1317 ImageHandle,\r
1318 SystemTable,\r
1319 &gPartitionDriverBinding,\r
1320 ImageHandle,\r
1321 &gPartitionComponentName,\r
d38a0f44 1322 &gPartitionComponentName2\r
adbcbf8f 1323 );\r
1324 ASSERT_EFI_ERROR (Status);\r
1325\r
1326\r
1327 return Status;\r
1328}\r
1329\r
e3325721
HW
1330\r
1331/**\r
1332 Test to see if there is any child on ControllerHandle.\r
1333\r
1334 @param[in] ControllerHandle Handle of device to test.\r
1335\r
1336 @retval TRUE There are children on the ControllerHandle.\r
1337 @retval FALSE No child is on the ControllerHandle.\r
1338\r
1339**/\r
1340BOOLEAN\r
1341HasChildren (\r
1342 IN EFI_HANDLE ControllerHandle\r
1343 )\r
1344{\r
1345 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
1346 UINTN EntryCount;\r
1347 EFI_STATUS Status;\r
1348 UINTN Index;\r
1349\r
1350 Status = gBS->OpenProtocolInformation (\r
1351 ControllerHandle,\r
1352 &gEfiDiskIoProtocolGuid,\r
1353 &OpenInfoBuffer,\r
1354 &EntryCount\r
1355 );\r
1356 ASSERT_EFI_ERROR (Status);\r
1357\r
1358 for (Index = 0; Index < EntryCount; Index++) {\r
1359 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
1360 break;\r
1361 }\r
1362 }\r
1363 FreePool (OpenInfoBuffer);\r
1364\r
1365 return (BOOLEAN) (Index < EntryCount);\r
1366}\r
1367\r