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