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