]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
Code scrub DxeIpl, Runtime, DevicePath, FvbServicesLib, DiskIo, Partition, English...
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Partition.c
1 /** @file
2 Partition driver that produces logical BlockIo devices from a physical
3 BlockIo device. The logical BlockIo devices are based on the format
4 of the raw block devices media. Currently "El Torito CD-ROM", Legacy
5 MBR, and GPT partition schemes are supported.
6
7 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
8 All rights reserved. This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18
19 #include "Partition.h"
20
21 //
22 // Partition Driver Global Variables.
23 //
24 EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
25 PartitionDriverBindingSupported,
26 PartitionDriverBindingStart,
27 PartitionDriverBindingStop,
28 0xa,
29 NULL,
30 NULL
31 };
32
33 //
34 // Prioritized function list to detect partition table.
35 //
36 PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
37 PartitionInstallGptChildHandles,
38 PartitionInstallElToritoChildHandles,
39 PartitionInstallMbrChildHandles,
40 NULL
41 };
42
43
44
45 /**
46 Test to see if this driver supports ControllerHandle. Any ControllerHandle
47 than contains a BlockIo and DiskIo protocol can be supported.
48
49 @param This Protocol instance pointer.
50 @param ControllerHandle Handle of device to test
51 @param RemainingDevicePath Optional parameter use to pick a specific child
52 device to start.
53
54 @retval EFI_SUCCESS This driver supports this device
55 @retval EFI_ALREADY_STARTED This driver is already running on this device
56 @retval other This driver does not support this device
57
58 **/
59 EFI_STATUS
60 EFIAPI
61 PartitionDriverBindingSupported (
62 IN EFI_DRIVER_BINDING_PROTOCOL *This,
63 IN EFI_HANDLE ControllerHandle,
64 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
65 )
66 {
67 EFI_STATUS Status;
68 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
69 EFI_DISK_IO_PROTOCOL *DiskIo;
70 EFI_DEV_PATH *Node;
71
72 if (RemainingDevicePath != NULL) {
73 Node = (EFI_DEV_PATH *) RemainingDevicePath;
74 if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||
75 Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||
76 DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)
77 ) {
78 return EFI_UNSUPPORTED;
79 }
80 }
81 //
82 // Open the IO Abstraction(s) needed to perform the supported test
83 //
84 Status = gBS->OpenProtocol (
85 ControllerHandle,
86 &gEfiDevicePathProtocolGuid,
87 (VOID **) &ParentDevicePath,
88 This->DriverBindingHandle,
89 ControllerHandle,
90 EFI_OPEN_PROTOCOL_BY_DRIVER
91 );
92 if (Status == EFI_ALREADY_STARTED) {
93 return EFI_SUCCESS;
94 }
95
96 if (EFI_ERROR (Status)) {
97 return Status;
98 }
99 //
100 // Close the I/O Abstraction(s) used to perform the supported test
101 //
102 gBS->CloseProtocol (
103 ControllerHandle,
104 &gEfiDevicePathProtocolGuid,
105 This->DriverBindingHandle,
106 ControllerHandle
107 );
108
109 //
110 // Open the IO Abstraction(s) needed to perform the supported test
111 //
112 Status = gBS->OpenProtocol (
113 ControllerHandle,
114 &gEfiDiskIoProtocolGuid,
115 (VOID **) &DiskIo,
116 This->DriverBindingHandle,
117 ControllerHandle,
118 EFI_OPEN_PROTOCOL_BY_DRIVER
119 );
120 if (Status == EFI_ALREADY_STARTED) {
121 return EFI_SUCCESS;
122 }
123
124 if (EFI_ERROR (Status)) {
125 return Status;
126 }
127 //
128 // Close the I/O Abstraction(s) used to perform the supported test
129 //
130 gBS->CloseProtocol (
131 ControllerHandle,
132 &gEfiDiskIoProtocolGuid,
133 This->DriverBindingHandle,
134 ControllerHandle
135 );
136
137 //
138 // Open the IO Abstraction(s) needed to perform the supported test
139 //
140 Status = gBS->OpenProtocol (
141 ControllerHandle,
142 &gEfiBlockIoProtocolGuid,
143 NULL,
144 This->DriverBindingHandle,
145 ControllerHandle,
146 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
147 );
148
149 return Status;
150 }
151
152
153 /**
154 Start this driver on ControllerHandle by opening a Block IO and Disk IO
155 protocol, reading Device Path, and creating a child handle with a
156 Disk IO and device path protocol.
157
158 @param This Protocol instance pointer.
159 @param ControllerHandle Handle of device to bind driver to
160 @param RemainingDevicePath Optional parameter use to pick a specific child
161 device to start.
162
163 @retval EFI_SUCCESS This driver is added to ControllerHandle
164 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
165 @retval other This driver does not support this device
166
167 **/
168 EFI_STATUS
169 EFIAPI
170 PartitionDriverBindingStart (
171 IN EFI_DRIVER_BINDING_PROTOCOL *This,
172 IN EFI_HANDLE ControllerHandle,
173 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
174 )
175 {
176 EFI_STATUS Status;
177 EFI_STATUS OpenStatus;
178 EFI_BLOCK_IO_PROTOCOL *BlockIo;
179 EFI_DISK_IO_PROTOCOL *DiskIo;
180 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
181 PARTITION_DETECT_ROUTINE *Routine;
182
183 Status = gBS->OpenProtocol (
184 ControllerHandle,
185 &gEfiBlockIoProtocolGuid,
186 (VOID **) &BlockIo,
187 This->DriverBindingHandle,
188 ControllerHandle,
189 EFI_OPEN_PROTOCOL_GET_PROTOCOL
190 );
191 if (EFI_ERROR (Status)) {
192 return Status;
193 }
194 //
195 // Get the Device Path Protocol on ControllerHandle's handle
196 //
197 Status = gBS->OpenProtocol (
198 ControllerHandle,
199 &gEfiDevicePathProtocolGuid,
200 (VOID **) &ParentDevicePath,
201 This->DriverBindingHandle,
202 ControllerHandle,
203 EFI_OPEN_PROTOCOL_BY_DRIVER
204 );
205 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
206 return Status;
207 }
208
209 Status = gBS->OpenProtocol (
210 ControllerHandle,
211 &gEfiDiskIoProtocolGuid,
212 (VOID **) &DiskIo,
213 This->DriverBindingHandle,
214 ControllerHandle,
215 EFI_OPEN_PROTOCOL_BY_DRIVER
216 );
217 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
218 gBS->CloseProtocol (
219 ControllerHandle,
220 &gEfiDevicePathProtocolGuid,
221 This->DriverBindingHandle,
222 ControllerHandle
223 );
224 return Status;
225 }
226
227 OpenStatus = Status;
228
229 //
230 // If no media is present, do nothing here.
231 //
232 Status = EFI_UNSUPPORTED;
233 if (BlockIo->Media->MediaPresent) {
234 //
235 // Try for GPT, then El Torito, and then legacy MBR partition types. If the
236 // media supports a given partition type install child handles to represent
237 // the partitions described by the media.
238 //
239 Routine = &mPartitionDetectRoutineTable[0];
240 while (*Routine != NULL) {
241 Status = (*Routine) (
242 This,
243 ControllerHandle,
244 DiskIo,
245 BlockIo,
246 ParentDevicePath
247 );
248 if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED) {
249 break;
250 }
251 Routine++;
252 }
253 }
254 //
255 // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
256 // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
257 // driver. So don't try to close them. Otherwise, we will break the dependency
258 // between the controller and the driver set up before.
259 //
260 if (EFI_ERROR (Status) && !EFI_ERROR (OpenStatus) && Status != EFI_MEDIA_CHANGED) {
261 gBS->CloseProtocol (
262 ControllerHandle,
263 &gEfiDiskIoProtocolGuid,
264 This->DriverBindingHandle,
265 ControllerHandle
266 );
267
268 gBS->CloseProtocol (
269 ControllerHandle,
270 &gEfiDevicePathProtocolGuid,
271 This->DriverBindingHandle,
272 ControllerHandle
273 );
274 }
275
276 return Status;
277 }
278
279
280 /**
281 Stop this driver on ControllerHandle. Support stopping any child handles
282 created by this driver.
283
284 @param This Protocol instance pointer.
285 @param ControllerHandle Handle of device to stop driver on
286 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
287 children is zero stop the entire bus driver.
288 @param ChildHandleBuffer List of Child Handles to Stop.
289
290 @retval EFI_SUCCESS This driver is removed ControllerHandle
291 @retval other This driver was not removed from this device
292
293 **/
294 EFI_STATUS
295 EFIAPI
296 PartitionDriverBindingStop (
297 IN EFI_DRIVER_BINDING_PROTOCOL *This,
298 IN EFI_HANDLE ControllerHandle,
299 IN UINTN NumberOfChildren,
300 IN EFI_HANDLE *ChildHandleBuffer
301 )
302 {
303 EFI_STATUS Status;
304 UINTN Index;
305 EFI_BLOCK_IO_PROTOCOL *BlockIo;
306 BOOLEAN AllChildrenStopped;
307 PARTITION_PRIVATE_DATA *Private;
308 EFI_DISK_IO_PROTOCOL *DiskIo;
309
310 if (NumberOfChildren == 0) {
311 //
312 // Close the bus driver
313 //
314 gBS->CloseProtocol (
315 ControllerHandle,
316 &gEfiDiskIoProtocolGuid,
317 This->DriverBindingHandle,
318 ControllerHandle
319 );
320
321 gBS->CloseProtocol (
322 ControllerHandle,
323 &gEfiDevicePathProtocolGuid,
324 This->DriverBindingHandle,
325 ControllerHandle
326 );
327
328 return EFI_SUCCESS;
329 }
330
331 AllChildrenStopped = TRUE;
332 for (Index = 0; Index < NumberOfChildren; Index++) {
333 Status = gBS->OpenProtocol (
334 ChildHandleBuffer[Index],
335 &gEfiBlockIoProtocolGuid,
336 (VOID **) &BlockIo,
337 This->DriverBindingHandle,
338 ControllerHandle,
339 EFI_OPEN_PROTOCOL_GET_PROTOCOL
340 );
341 if (!EFI_ERROR (Status)) {
342
343 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
344
345 //
346 // All Software protocols have be freed from the handle so remove it.
347 //
348 BlockIo->FlushBlocks (BlockIo);
349
350 Status = gBS->CloseProtocol (
351 ControllerHandle,
352 &gEfiDiskIoProtocolGuid,
353 This->DriverBindingHandle,
354 ChildHandleBuffer[Index]
355 );
356
357 Status = gBS->UninstallMultipleProtocolInterfaces (
358 ChildHandleBuffer[Index],
359 &gEfiDevicePathProtocolGuid,
360 Private->DevicePath,
361 &gEfiBlockIoProtocolGuid,
362 &Private->BlockIo,
363 Private->EspGuid,
364 NULL,
365 NULL
366 );
367 if (EFI_ERROR (Status)) {
368 gBS->OpenProtocol (
369 ControllerHandle,
370 &gEfiDiskIoProtocolGuid,
371 (VOID **) &DiskIo,
372 This->DriverBindingHandle,
373 ChildHandleBuffer[Index],
374 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
375 );
376 } else {
377 FreePool (Private->DevicePath);
378 FreePool (Private);
379 }
380
381 }
382
383 if (EFI_ERROR (Status)) {
384 AllChildrenStopped = FALSE;
385 }
386 }
387
388 if (!AllChildrenStopped) {
389 return EFI_DEVICE_ERROR;
390 }
391
392 return EFI_SUCCESS;
393 }
394
395
396 /**
397 Reset the Block Device.
398
399 @param This Protocol instance pointer.
400 @param ExtendedVerification Driver may perform diagnostics on reset.
401
402 @retval EFI_SUCCESS The device was reset.
403 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
404 not be reset.
405
406 **/
407 EFI_STATUS
408 EFIAPI
409 PartitionReset (
410 IN EFI_BLOCK_IO_PROTOCOL *This,
411 IN BOOLEAN ExtendedVerification
412 )
413 {
414 PARTITION_PRIVATE_DATA *Private;
415
416 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
417
418 return Private->ParentBlockIo->Reset (
419 Private->ParentBlockIo,
420 ExtendedVerification
421 );
422 }
423
424
425 /**
426 Read by using the Disk IO protocol on the parent device. Lba addresses
427 must be converted to byte offsets.
428
429 @param This Protocol instance pointer.
430 @param MediaId Id of the media, changes every time the media is replaced.
431 @param Lba The starting Logical Block Address to read from
432 @param BufferSize Size of Buffer, must be a multiple of device block size.
433 @param Buffer Buffer containing read data
434
435 @retval EFI_SUCCESS The data was read correctly from the device.
436 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
437 @retval EFI_NO_MEDIA There is no media in the device.
438 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
439 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
440 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
441 valid for the device.
442
443 **/
444 EFI_STATUS
445 EFIAPI
446 PartitionReadBlocks (
447 IN EFI_BLOCK_IO_PROTOCOL *This,
448 IN UINT32 MediaId,
449 IN EFI_LBA Lba,
450 IN UINTN BufferSize,
451 OUT VOID *Buffer
452 )
453 {
454 PARTITION_PRIVATE_DATA *Private;
455 UINT64 Offset;
456
457 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
458
459 if (BufferSize % Private->BlockSize != 0) {
460 return EFI_BAD_BUFFER_SIZE;
461 }
462
463 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
464 if (Offset + BufferSize > Private->End) {
465 return EFI_INVALID_PARAMETER;
466 }
467 //
468 // Because some kinds of partition have different block size from their parent
469 // device, we call the Disk IO protocol on the parent device, not the Block IO
470 // protocol
471 //
472 return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
473 }
474
475 /**
476 Write by using the Disk IO protocol on the parent device. Lba addresses
477 must be converted to byte offsets.
478
479 @param This Protocol instance pointer.
480 @param MediaId Id of the media, changes every time the media is replaced.
481 @param Lba The starting Logical Block Address to read from
482 @param BufferSize Size of Buffer, must be a multiple of device block size.
483 @param Buffer Buffer containing read data
484
485 @retval EFI_SUCCESS The data was written correctly to the device.
486 @retval EFI_WRITE_PROTECTED The device can not be written to.
487 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
488 @retval EFI_NO_MEDIA There is no media in the device.
489 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
490 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
491 @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
492 valid for the device.
493
494 **/
495 EFI_STATUS
496 EFIAPI
497 PartitionWriteBlocks (
498 IN EFI_BLOCK_IO_PROTOCOL *This,
499 IN UINT32 MediaId,
500 IN EFI_LBA Lba,
501 IN UINTN BufferSize,
502 OUT VOID *Buffer
503 )
504 {
505 PARTITION_PRIVATE_DATA *Private;
506 UINT64 Offset;
507
508 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
509
510 if (BufferSize % Private->BlockSize != 0) {
511 return EFI_BAD_BUFFER_SIZE;
512 }
513
514 Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
515 if (Offset + BufferSize > Private->End) {
516 return EFI_INVALID_PARAMETER;
517 }
518 //
519 // Because some kinds of partition have different block size from their parent
520 // device, we call the Disk IO protocol on the parent device, not the Block IO
521 // protocol
522 //
523 return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
524 }
525
526
527 /**
528 Flush the parent Block Device.
529
530 @param This Protocol instance pointer.
531
532 @retval EFI_SUCCESS All outstanding data was written to the device
533 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
534 @retval EFI_NO_MEDIA There is no media in the device.
535
536 **/
537 EFI_STATUS
538 EFIAPI
539 PartitionFlushBlocks (
540 IN EFI_BLOCK_IO_PROTOCOL *This
541 )
542 {
543 PARTITION_PRIVATE_DATA *Private;
544
545 Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
546
547 return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
548 }
549
550
551
552 /**
553 Create a child handle for a logical block device that represents the
554 bytes Start to End of the Parent Block IO device.
555
556 @param[in] This Protocol instance pointer
557 @param[in] ParentHandle Parent Handle for new child
558 @param[in] ParentDiskIo Parent DiskIo interface
559 @param[in] ParentBlockIo Parent BlockIo interface
560 @param[in] ParentDevicePath Parent Device Path
561 @param[in] DevicePathNode Child Device Path node
562 @param[in] Start Start Block
563 @param[in] End End Block
564 @param[in] BlockSize Child block size
565 @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle
566
567 @retval EFI_SUCCESS A child handle was added
568 @retval other A child handle was not added
569
570 **/
571 EFI_STATUS
572 PartitionInstallChildHandle (
573 IN EFI_DRIVER_BINDING_PROTOCOL *This,
574 IN EFI_HANDLE ParentHandle,
575 IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
576 IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
577 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
578 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
579 IN EFI_LBA Start,
580 IN EFI_LBA End,
581 IN UINT32 BlockSize,
582 IN BOOLEAN InstallEspGuid
583 )
584 {
585 EFI_STATUS Status;
586 PARTITION_PRIVATE_DATA *Private;
587
588 Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
589 if (Private == NULL) {
590 return EFI_OUT_OF_RESOURCES;
591 }
592
593 Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
594
595 Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
596 Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
597
598 Private->BlockSize = BlockSize;
599 Private->ParentBlockIo = ParentBlockIo;
600 Private->DiskIo = ParentDiskIo;
601
602 Private->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
603
604 Private->BlockIo.Media = &Private->Media;
605 CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
606 Private->Media.LogicalPartition = TRUE;
607 Private->Media.LastBlock = DivU64x32 (
608 MultU64x32 (
609 End - Start + 1,
610 ParentBlockIo->Media->BlockSize
611 ),
612 BlockSize
613 ) - 1;
614
615 Private->Media.BlockSize = (UINT32) BlockSize;
616
617 Private->BlockIo.Reset = PartitionReset;
618 Private->BlockIo.ReadBlocks = PartitionReadBlocks;
619 Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
620 Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
621
622 Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
623
624 if (Private->DevicePath == NULL) {
625 FreePool (Private);
626 return EFI_OUT_OF_RESOURCES;
627 }
628
629 if (InstallEspGuid) {
630 Private->EspGuid = &gEfiPartTypeSystemPartGuid;
631 } else {
632 //
633 // If NULL InstallMultipleProtocolInterfaces will ignore it.
634 //
635 Private->EspGuid = NULL;
636 }
637 //
638 // Create the new handle
639 //
640 Private->Handle = NULL;
641 Status = gBS->InstallMultipleProtocolInterfaces (
642 &Private->Handle,
643 &gEfiDevicePathProtocolGuid,
644 Private->DevicePath,
645 &gEfiBlockIoProtocolGuid,
646 &Private->BlockIo,
647 Private->EspGuid,
648 NULL,
649 NULL
650 );
651
652 if (!EFI_ERROR (Status)) {
653 //
654 // Open the Parent Handle for the child
655 //
656 Status = gBS->OpenProtocol (
657 ParentHandle,
658 &gEfiDiskIoProtocolGuid,
659 (VOID **) &ParentDiskIo,
660 This->DriverBindingHandle,
661 Private->Handle,
662 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
663 );
664 } else {
665 FreePool (Private->DevicePath);
666 FreePool (Private);
667 }
668
669 return Status;
670 }
671
672
673 /**
674 The user Entry Point for module Partition. The user code starts with this function.
675
676 @param[in] ImageHandle The firmware allocated handle for the EFI image.
677 @param[in] SystemTable A pointer to the EFI System Table.
678
679 @retval EFI_SUCCESS The entry point is executed successfully.
680 @retval other Some error occurs when executing this entry point.
681
682 **/
683 EFI_STATUS
684 EFIAPI
685 InitializePartition (
686 IN EFI_HANDLE ImageHandle,
687 IN EFI_SYSTEM_TABLE *SystemTable
688 )
689 {
690 EFI_STATUS Status;
691
692 //
693 // Install driver model protocol(s).
694 //
695 Status = EfiLibInstallDriverBindingComponentName2 (
696 ImageHandle,
697 SystemTable,
698 &gPartitionDriverBinding,
699 ImageHandle,
700 &gPartitionComponentName,
701 &gPartitionComponentName2
702 );
703 ASSERT_EFI_ERROR (Status);
704
705
706 return Status;
707 }
708