]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
Code Scrub:
[mirror_edk2.git] / MdeModulePkg / Bus / Scsi / ScsiDiskDxe / ScsiDisk.c
1 /** @file
2 SCSI disk driver that layers on every SCSI IO protocol in the system.
3
4 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15
16 #include "ScsiDisk.h"
17
18
19 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
20 ScsiDiskDriverBindingSupported,
21 ScsiDiskDriverBindingStart,
22 ScsiDiskDriverBindingStop,
23 0xa,
24 NULL,
25 NULL
26 };
27
28 /**
29 The user Entry Point for module ScsiDisk.
30
31 The user code starts with this function.
32
33 @param ImageHandle The firmware allocated handle for the EFI image.
34 @param SystemTable A pointer to the EFI System Table.
35
36 @retval EFI_SUCCESS The entry point is executed successfully.
37 @retval other Some error occurs when executing this entry point.
38
39 **/
40 EFI_STATUS
41 EFIAPI
42 InitializeScsiDisk(
43 IN EFI_HANDLE ImageHandle,
44 IN EFI_SYSTEM_TABLE *SystemTable
45 )
46 {
47 EFI_STATUS Status;
48
49 //
50 // Install driver model protocol(s).
51 //
52 Status = EfiLibInstallDriverBindingComponentName2 (
53 ImageHandle,
54 SystemTable,
55 &gScsiDiskDriverBinding,
56 ImageHandle,
57 &gScsiDiskComponentName,
58 &gScsiDiskComponentName2
59 );
60 ASSERT_EFI_ERROR (Status);
61
62
63 return Status;
64 }
65
66 /**
67 Test to see if this driver supports ControllerHandle.
68
69 This service is called by the EFI boot service ConnectController(). In order
70 to make drivers as small as possible, there are a few calling restrictions for
71 this service. ConnectController() must follow these calling restrictions.
72 If any other agent wishes to call Supported() it must also follow these
73 calling restrictions.
74
75 @param This Protocol instance pointer.
76 @param ControllerHandle Handle of device to test
77 @param RemainingDevicePath Optional parameter use to pick a specific child
78 device to start.
79
80 @retval EFI_SUCCESS This driver supports this device
81 @retval EFI_ALREADY_STARTED This driver is already running on this device
82 @retval other This driver does not support this device
83
84 **/
85 EFI_STATUS
86 EFIAPI
87 ScsiDiskDriverBindingSupported (
88 IN EFI_DRIVER_BINDING_PROTOCOL *This,
89 IN EFI_HANDLE Controller,
90 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
91 )
92 {
93 EFI_STATUS Status;
94 EFI_SCSI_IO_PROTOCOL *ScsiIo;
95 UINT8 DeviceType;
96
97 Status = gBS->OpenProtocol (
98 Controller,
99 &gEfiScsiIoProtocolGuid,
100 (VOID **) &ScsiIo,
101 This->DriverBindingHandle,
102 Controller,
103 EFI_OPEN_PROTOCOL_BY_DRIVER
104 );
105 if (EFI_ERROR (Status)) {
106 return Status;
107 }
108
109 Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
110 if (!EFI_ERROR (Status)) {
111 if ((DeviceType == EFI_SCSI_TYPE_DISK) || (DeviceType == EFI_SCSI_TYPE_CDROM)) {
112 Status = EFI_SUCCESS;
113 } else {
114 Status = EFI_UNSUPPORTED;
115 }
116 }
117
118 gBS->CloseProtocol (
119 Controller,
120 &gEfiScsiIoProtocolGuid,
121 This->DriverBindingHandle,
122 Controller
123 );
124 return Status;
125 }
126
127
128 /**
129 Start this driver on ControllerHandle.
130
131 This service is called by the EFI boot service ConnectController(). In order
132 to make drivers as small as possible, there are a few calling restrictions for
133 this service. ConnectController() must follow these calling restrictions. If
134 any other agent wishes to call Start() it must also follow these calling
135 restrictions.
136
137 @param This Protocol instance pointer.
138 @param ControllerHandle Handle of device to bind driver to
139 @param RemainingDevicePath Optional parameter use to pick a specific child
140 device to start.
141
142 @retval EFI_SUCCESS This driver is added to ControllerHandle
143 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
144 @retval other This driver does not support this device
145
146 **/
147 EFI_STATUS
148 EFIAPI
149 ScsiDiskDriverBindingStart (
150 IN EFI_DRIVER_BINDING_PROTOCOL *This,
151 IN EFI_HANDLE Controller,
152 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
153 )
154 {
155 EFI_STATUS Status;
156 EFI_SCSI_IO_PROTOCOL *ScsiIo;
157 SCSI_DISK_DEV *ScsiDiskDevice;
158 BOOLEAN Temp;
159 UINT8 Index;
160 UINT8 MaxRetry;
161 BOOLEAN NeedRetry;
162
163 Status = gBS->AllocatePool (
164 EfiBootServicesData,
165 sizeof (SCSI_DISK_DEV),
166 (VOID **) &ScsiDiskDevice
167 );
168 if (EFI_ERROR (Status)) {
169 return Status;
170 }
171
172 ZeroMem (ScsiDiskDevice, sizeof (SCSI_DISK_DEV));
173
174 Status = gBS->OpenProtocol (
175 Controller,
176 &gEfiScsiIoProtocolGuid,
177 (VOID **) &ScsiIo,
178 This->DriverBindingHandle,
179 Controller,
180 EFI_OPEN_PROTOCOL_BY_DRIVER
181 );
182 if (EFI_ERROR (Status)) {
183 gBS->FreePool (ScsiDiskDevice);
184 return Status;
185 }
186
187 ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE;
188 ScsiDiskDevice->ScsiIo = ScsiIo;
189 ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia;
190 ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset;
191 ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;
192 ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;
193 ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;
194 ScsiDiskDevice->Handle = Controller;
195
196 ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
197 switch (ScsiDiskDevice->DeviceType) {
198 case EFI_SCSI_TYPE_DISK:
199 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
200 break;
201
202 case EFI_SCSI_TYPE_CDROM:
203 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
204 break;
205 }
206 //
207 // The Sense Data Array's initial size is 6
208 //
209 ScsiDiskDevice->SenseDataNumber = 6;
210 Status = gBS->AllocatePool (
211 EfiBootServicesData,
212 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber,
213 (VOID **) &(ScsiDiskDevice->SenseData)
214 );
215 if (EFI_ERROR (Status)) {
216 gBS->CloseProtocol (
217 Controller,
218 &gEfiScsiIoProtocolGuid,
219 This->DriverBindingHandle,
220 Controller
221 );
222 gBS->FreePool (ScsiDiskDevice);
223 return Status;
224 }
225
226 ZeroMem (
227 ScsiDiskDevice->SenseData,
228 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
229 );
230
231 //
232 // Retrive device information
233 //
234 MaxRetry = 2;
235 for (Index = 0; Index < MaxRetry; Index++) {
236 Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
237 if (!EFI_ERROR (Status)) {
238 break;
239 }
240
241 if (!NeedRetry) {
242 gBS->FreePool (ScsiDiskDevice->SenseData);
243 gBS->CloseProtocol (
244 Controller,
245 &gEfiScsiIoProtocolGuid,
246 This->DriverBindingHandle,
247 Controller
248 );
249 gBS->FreePool (ScsiDiskDevice);
250 return EFI_DEVICE_ERROR;
251 }
252 }
253 //
254 // The second parameter "TRUE" means must
255 // retrieve media capacity
256 //
257 Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp);
258 if (!EFI_ERROR (Status)) {
259 Status = gBS->InstallMultipleProtocolInterfaces (
260 &Controller,
261 &gEfiBlockIoProtocolGuid,
262 &ScsiDiskDevice->BlkIo,
263 NULL
264 );
265 }
266
267 if (EFI_ERROR (Status)) {
268 gBS->FreePool (ScsiDiskDevice->SenseData);
269 gBS->CloseProtocol (
270 Controller,
271 &gEfiScsiIoProtocolGuid,
272 This->DriverBindingHandle,
273 Controller
274 );
275 gBS->FreePool (ScsiDiskDevice);
276 return Status;
277 }
278
279 ScsiDiskDevice->ControllerNameTable = NULL;
280 AddUnicodeString2 (
281 "eng",
282 gScsiDiskComponentName.SupportedLanguages,
283 &ScsiDiskDevice->ControllerNameTable,
284 L"SCSI Disk Device",
285 TRUE
286 );
287 AddUnicodeString2 (
288 "en",
289 gScsiDiskComponentName2.SupportedLanguages,
290 &ScsiDiskDevice->ControllerNameTable,
291 L"SCSI Disk Device",
292 FALSE
293 );
294
295
296 return EFI_SUCCESS;
297
298 }
299
300
301 /**
302 Stop this driver on ControllerHandle.
303
304 This service is called by the EFI boot service DisconnectController().
305 In order to make drivers as small as possible, there are a few calling
306 restrictions for this service. DisconnectController() must follow these
307 calling restrictions. If any other agent wishes to call Stop() it must
308 also follow these calling restrictions.
309
310 @param This Protocol instance pointer.
311 @param ControllerHandle Handle of device to stop driver on
312 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
313 children is zero stop the entire bus driver.
314 @param ChildHandleBuffer List of Child Handles to Stop.
315
316 @retval EFI_SUCCESS This driver is removed ControllerHandle
317 @retval other This driver was not removed from this device
318
319 **/
320 EFI_STATUS
321 EFIAPI
322 ScsiDiskDriverBindingStop (
323 IN EFI_DRIVER_BINDING_PROTOCOL *This,
324 IN EFI_HANDLE Controller,
325 IN UINTN NumberOfChildren,
326 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
327 )
328 {
329 EFI_BLOCK_IO_PROTOCOL *BlkIo;
330 SCSI_DISK_DEV *ScsiDiskDevice;
331 EFI_STATUS Status;
332
333 Status = gBS->OpenProtocol (
334 Controller,
335 &gEfiBlockIoProtocolGuid,
336 (VOID **) &BlkIo,
337 This->DriverBindingHandle,
338 Controller,
339 EFI_OPEN_PROTOCOL_GET_PROTOCOL
340 );
341 if (EFI_ERROR (Status)) {
342 return Status;
343 }
344
345 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo);
346 Status = gBS->UninstallProtocolInterface (
347 Controller,
348 &gEfiBlockIoProtocolGuid,
349 &ScsiDiskDevice->BlkIo
350 );
351 if (!EFI_ERROR (Status)) {
352 gBS->CloseProtocol (
353 Controller,
354 &gEfiScsiIoProtocolGuid,
355 This->DriverBindingHandle,
356 Controller
357 );
358
359 ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
360
361 return EFI_SUCCESS;
362 }
363 //
364 // errors met
365 //
366 return Status;
367 }
368
369 /**
370 Reset SCSI Disk.
371
372
373 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
374 @param ExtendedVerification The flag about if extend verificate
375
376 @retval EFI_SUCCESS The device was reset.
377 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
378 not be reset.
379 @return EFI_STATUS is retured from EFI_SCSI_IO_PROTOCOL.ResetDevice().
380
381 **/
382 EFI_STATUS
383 EFIAPI
384 ScsiDiskReset (
385 IN EFI_BLOCK_IO_PROTOCOL *This,
386 IN BOOLEAN ExtendedVerification
387 )
388 {
389 EFI_TPL OldTpl;
390 SCSI_DISK_DEV *ScsiDiskDevice;
391 EFI_STATUS Status;
392
393 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
394
395 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
396
397 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
398
399 if (!ExtendedVerification) {
400 goto Done;
401 }
402
403 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
404
405 Done:
406 gBS->RestoreTPL (OldTpl);
407 return Status;
408 }
409
410 /**
411 The function is to Read Block from SCSI Disk.
412
413 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
414 @param MediaId The Id of Media detected
415 @param Lba The logic block address
416 @param BufferSize The size of Buffer
417 @param Buffer The buffer to fill the read out data
418
419 @retval EFI_SUCCESS Successfully to read out block.
420 @retval EFI_DEVICE_ERROR Fail to detect media.
421 @retval EFI_NO_MEDIA Media is not present.
422 @retval EFI_MEDIA_CHANGED Media has changed.
423 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
424 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
425
426 **/
427 EFI_STATUS
428 EFIAPI
429 ScsiDiskReadBlocks (
430 IN EFI_BLOCK_IO_PROTOCOL *This,
431 IN UINT32 MediaId,
432 IN EFI_LBA Lba,
433 IN UINTN BufferSize,
434 OUT VOID *Buffer
435 )
436 {
437 SCSI_DISK_DEV *ScsiDiskDevice;
438 EFI_BLOCK_IO_MEDIA *Media;
439 EFI_STATUS Status;
440 UINTN BlockSize;
441 UINTN NumberOfBlocks;
442 BOOLEAN MediaChange;
443 EFI_TPL OldTpl;
444
445 MediaChange = FALSE;
446 if (Buffer == NULL) {
447 return EFI_INVALID_PARAMETER;
448 }
449
450 if (BufferSize == 0) {
451 return EFI_SUCCESS;
452 }
453
454 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
455
456 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
457
458 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
459
460 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
461 if (EFI_ERROR (Status)) {
462 Status = EFI_DEVICE_ERROR;
463 goto Done;
464 }
465
466 if (MediaChange) {
467 gBS->ReinstallProtocolInterface (
468 ScsiDiskDevice->Handle,
469 &gEfiBlockIoProtocolGuid,
470 &ScsiDiskDevice->BlkIo,
471 &ScsiDiskDevice->BlkIo
472 );
473 }
474 }
475 //
476 // Get the intrinsic block size
477 //
478 Media = ScsiDiskDevice->BlkIo.Media;
479 BlockSize = Media->BlockSize;
480
481 NumberOfBlocks = BufferSize / BlockSize;
482
483 if (!(Media->MediaPresent)) {
484 Status = EFI_NO_MEDIA;
485 goto Done;
486 }
487
488 if (MediaId != Media->MediaId) {
489 Status = EFI_MEDIA_CHANGED;
490 goto Done;
491 }
492
493 if (BufferSize % BlockSize != 0) {
494 Status = EFI_BAD_BUFFER_SIZE;
495 goto Done;
496 }
497
498 if (Lba > Media->LastBlock) {
499 Status = EFI_INVALID_PARAMETER;
500 goto Done;
501 }
502
503 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
504 Status = EFI_INVALID_PARAMETER;
505 goto Done;
506 }
507
508 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
509 Status = EFI_INVALID_PARAMETER;
510 goto Done;
511 }
512
513 //
514 // If all the parameters are valid, then perform read sectors command
515 // to transfer data from device to host.
516 //
517 Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
518
519 Done:
520 gBS->RestoreTPL (OldTpl);
521 return Status;
522 }
523
524 /**
525 The function is to Write Block to SCSI Disk.
526
527 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
528 @param MediaId The Id of Media detected
529 @param Lba The logic block address
530 @param BufferSize The size of Buffer
531 @param Buffer The buffer to fill the read out data
532
533 @retval EFI_SUCCESS Successfully to read out block.
534 @retval EFI_WRITE_PROTECTED The device can not be written to.
535 @retval EFI_DEVICE_ERROR Fail to detect media.
536 @retval EFI_NO_MEDIA Media is not present.
537 @retval EFI_MEDIA_CHNAGED Media has changed.
538 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
539 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
540
541 **/
542 EFI_STATUS
543 EFIAPI
544 ScsiDiskWriteBlocks (
545 IN EFI_BLOCK_IO_PROTOCOL *This,
546 IN UINT32 MediaId,
547 IN EFI_LBA Lba,
548 IN UINTN BufferSize,
549 IN VOID *Buffer
550 )
551 {
552 SCSI_DISK_DEV *ScsiDiskDevice;
553 EFI_BLOCK_IO_MEDIA *Media;
554 EFI_STATUS Status;
555 UINTN BlockSize;
556 UINTN NumberOfBlocks;
557 BOOLEAN MediaChange;
558 EFI_TPL OldTpl;
559
560 MediaChange = FALSE;
561 if (Buffer == NULL) {
562 return EFI_INVALID_PARAMETER;
563 }
564
565 if (BufferSize == 0) {
566 return EFI_SUCCESS;
567 }
568
569 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
570
571 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
572
573 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
574
575 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
576 if (EFI_ERROR (Status)) {
577 Status = EFI_DEVICE_ERROR;
578 goto Done;
579 }
580
581 if (MediaChange) {
582 gBS->ReinstallProtocolInterface (
583 ScsiDiskDevice->Handle,
584 &gEfiBlockIoProtocolGuid,
585 &ScsiDiskDevice->BlkIo,
586 &ScsiDiskDevice->BlkIo
587 );
588 }
589 }
590 //
591 // Get the intrinsic block size
592 //
593 Media = ScsiDiskDevice->BlkIo.Media;
594 BlockSize = Media->BlockSize;
595
596 NumberOfBlocks = BufferSize / BlockSize;
597
598 if (!(Media->MediaPresent)) {
599 Status = EFI_NO_MEDIA;
600 goto Done;
601 }
602
603 if (MediaId != Media->MediaId) {
604 Status = EFI_MEDIA_CHANGED;
605 goto Done;
606 }
607
608 if (BufferSize % BlockSize != 0) {
609 Status = EFI_BAD_BUFFER_SIZE;
610 goto Done;
611 }
612
613 if (Lba > Media->LastBlock) {
614 Status = EFI_INVALID_PARAMETER;
615 goto Done;
616 }
617
618 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
619 Status = EFI_INVALID_PARAMETER;
620 goto Done;
621 }
622
623 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
624 Status = EFI_INVALID_PARAMETER;
625 goto Done;
626 }
627 //
628 // if all the parameters are valid, then perform read sectors command
629 // to transfer data from device to host.
630 //
631 Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
632
633 Done:
634 gBS->RestoreTPL (OldTpl);
635 return Status;
636 }
637
638 /**
639 Flush Block to Disk.
640
641 EFI_SUCCESS is returned directly.
642
643 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
644
645 @retval EFI_SUCCESS All outstanding data was written to the device
646
647 **/
648 EFI_STATUS
649 EFIAPI
650 ScsiDiskFlushBlocks (
651 IN EFI_BLOCK_IO_PROTOCOL *This
652 )
653 {
654 //
655 // return directly
656 //
657 return EFI_SUCCESS;
658 }
659
660
661 /**
662 Dectect Device and read out capacity ,if error occurs, parse the sense key.
663
664 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
665 @param MustReadCapacity The flag about reading device capacity
666 @param MediaChange The pointer of flag indicates if media has changed
667
668 @retval EFI_DEVICE_ERROR Indicates that error occurs
669 @retval EFI_SUCCESS Successfully to detect media
670
671 **/
672 EFI_STATUS
673 ScsiDiskDetectMedia (
674 IN SCSI_DISK_DEV *ScsiDiskDevice,
675 IN BOOLEAN MustReadCapacity,
676 OUT BOOLEAN *MediaChange
677 )
678 {
679 EFI_STATUS Status;
680 EFI_STATUS ReadCapacityStatus;
681 EFI_SCSI_SENSE_DATA *SenseData;
682 UINTN NumberOfSenseKeys;
683 BOOLEAN NeedRetry;
684 BOOLEAN NeedReadCapacity;
685 UINT8 Index;
686 UINT8 MaxRetry;
687 EFI_BLOCK_IO_MEDIA OldMedia;
688 UINTN Action;
689
690 Status = EFI_SUCCESS;
691 ReadCapacityStatus = EFI_SUCCESS;
692 SenseData = NULL;
693 NumberOfSenseKeys = 0;
694 NeedReadCapacity = FALSE;
695 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
696 *MediaChange = FALSE;
697 MaxRetry = 3;
698
699 for (Index = 0; Index < MaxRetry; Index++) {
700 Status = ScsiDiskTestUnitReady (
701 ScsiDiskDevice,
702 &NeedRetry,
703 &SenseData,
704 &NumberOfSenseKeys
705 );
706 if (!EFI_ERROR (Status)) {
707 break;
708 }
709
710 if (!NeedRetry) {
711 return Status;
712 }
713 }
714
715 if ((Index == MaxRetry) && EFI_ERROR (Status)) {
716 return EFI_DEVICE_ERROR;
717 }
718
719 Status = DetectMediaParsingSenseKeys (
720 ScsiDiskDevice,
721 SenseData,
722 NumberOfSenseKeys,
723 &Action
724 );
725 if (EFI_ERROR (Status)) {
726 return Status;
727 }
728 //
729 // ACTION_NO_ACTION: need not read capacity
730 // other action code: need read capacity
731 //
732 if (Action == ACTION_NO_ACTION) {
733 NeedReadCapacity = FALSE;
734 } else {
735 NeedReadCapacity = TRUE;
736 }
737
738 //
739 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
740 // retrieve capacity via Read Capacity command
741 //
742 if (NeedReadCapacity || MustReadCapacity) {
743 //
744 // retrieve media information
745 //
746 MaxRetry = 3;
747 for (Index = 0; Index < MaxRetry; Index++) {
748
749 ReadCapacityStatus = ScsiDiskReadCapacity (
750 ScsiDiskDevice,
751 &NeedRetry,
752 &SenseData,
753 &NumberOfSenseKeys
754 );
755 if (EFI_ERROR (ReadCapacityStatus) && !NeedRetry) {
756 return EFI_DEVICE_ERROR;
757 }
758 //
759 // analyze sense key to action
760 //
761 Status = DetectMediaParsingSenseKeys (
762 ScsiDiskDevice,
763 SenseData,
764 NumberOfSenseKeys,
765 &Action
766 );
767 //
768 // if Status is error, it may indicate crisis error,
769 // so return without retry.
770 //
771 if (EFI_ERROR (Status)) {
772 return Status;
773 }
774
775 switch (Action) {
776 case ACTION_NO_ACTION:
777 //
778 // no retry
779 //
780 Index = MaxRetry;
781 break;
782
783 case ACTION_RETRY_COMMAND_LATER:
784 //
785 // retry the ReadCapacity later and continuously, until the condition
786 // no longer emerges.
787 // stall time is 100000us, or say 0.1 second.
788 //
789 gBS->Stall (100000);
790 Index = 0;
791 break;
792
793 default:
794 //
795 // other cases, just retry the command
796 //
797 break;
798 }
799 }
800
801 if ((Index == MaxRetry) && EFI_ERROR (ReadCapacityStatus)) {
802 return EFI_DEVICE_ERROR;
803 }
804 }
805
806 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
807 //
808 // Media change information got from the device
809 //
810 *MediaChange = TRUE;
811 }
812
813 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
814 *MediaChange = TRUE;
815 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
816 }
817
818 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
819 *MediaChange = TRUE;
820 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
821 }
822
823 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
824 *MediaChange = TRUE;
825 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
826 }
827
828 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
829 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
830 //
831 // when change from no media to media present, reset the MediaId to 1.
832 //
833 ScsiDiskDevice->BlkIo.Media->MediaId = 1;
834 } else {
835 //
836 // when no media, reset the MediaId to zero.
837 //
838 ScsiDiskDevice->BlkIo.Media->MediaId = 0;
839 }
840
841 *MediaChange = TRUE;
842 }
843
844 return EFI_SUCCESS;
845 }
846
847
848 /**
849 Send out Inquiry command to Device.
850
851 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
852 @param NeedRetry Indicates if needs try again when error happens
853
854 @retval EFI_DEVICE_ERROR Indicates that error occurs
855 @retval EFI_SUCCESS Successfully to detect media
856
857 **/
858 EFI_STATUS
859 ScsiDiskInquiryDevice (
860 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
861 OUT BOOLEAN *NeedRetry
862 )
863 {
864 UINT32 InquiryDataLength;
865 UINT8 SenseDataLength;
866 UINT8 HostAdapterStatus;
867 UINT8 TargetStatus;
868 EFI_SCSI_SENSE_DATA *SenseDataArray;
869 UINTN NumberOfSenseKeys;
870 EFI_STATUS Status;
871 UINT8 MaxRetry;
872 UINT8 Index;
873
874 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
875 SenseDataLength = 0;
876
877 Status = ScsiInquiryCommand (
878 ScsiDiskDevice->ScsiIo,
879 EFI_SCSI_STALL_SECONDS (1),
880 NULL,
881 &SenseDataLength,
882 &HostAdapterStatus,
883 &TargetStatus,
884 (VOID *) &(ScsiDiskDevice->InquiryData),
885 &InquiryDataLength,
886 FALSE
887 );
888 //
889 // no need to check HostAdapterStatus and TargetStatus
890 //
891 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
892 ParseInquiryData (ScsiDiskDevice);
893 return EFI_SUCCESS;
894
895 } else if (Status == EFI_NOT_READY) {
896 *NeedRetry = TRUE;
897 return EFI_DEVICE_ERROR;
898
899 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
900 *NeedRetry = FALSE;
901 return EFI_DEVICE_ERROR;
902 }
903 //
904 // go ahead to check HostAdapterStatus and TargetStatus
905 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
906 //
907
908 Status = CheckHostAdapterStatus (HostAdapterStatus);
909 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
910 *NeedRetry = TRUE;
911 return EFI_DEVICE_ERROR;
912 } else if (Status == EFI_DEVICE_ERROR) {
913 //
914 // reset the scsi channel
915 //
916 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
917 *NeedRetry = FALSE;
918 return EFI_DEVICE_ERROR;
919 }
920
921 Status = CheckTargetStatus (TargetStatus);
922 if (Status == EFI_NOT_READY) {
923 //
924 // reset the scsi device
925 //
926 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
927 *NeedRetry = TRUE;
928 return EFI_DEVICE_ERROR;
929
930 } else if (Status == EFI_DEVICE_ERROR) {
931 *NeedRetry = FALSE;
932 return EFI_DEVICE_ERROR;
933 }
934
935 //
936 // if goes here, meant SubmitInquiryCommand() failed.
937 // if ScsiDiskRequestSenseKeys() succeeds at last,
938 // better retry SubmitInquiryCommand(). (by setting *NeedRetry = TRUE)
939 //
940 MaxRetry = 3;
941 for (Index = 0; Index < MaxRetry; Index++) {
942 Status = ScsiDiskRequestSenseKeys (
943 ScsiDiskDevice,
944 NeedRetry,
945 &SenseDataArray,
946 &NumberOfSenseKeys,
947 TRUE
948 );
949 if (!EFI_ERROR (Status)) {
950 *NeedRetry = TRUE;
951 return EFI_DEVICE_ERROR;
952 }
953
954 if (!*NeedRetry) {
955 return EFI_DEVICE_ERROR;
956 }
957 }
958 //
959 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
960 // set *NeedRetry = FALSE to avoid the outside caller try again.
961 //
962 *NeedRetry = FALSE;
963 return EFI_DEVICE_ERROR;
964 }
965
966 /**
967 To test deivice.
968
969 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
970 When Test Unit Ready command encounters any error caused by host adapter or
971 target, return error without retrieving Sense Keys.
972
973 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
974 @param NeedRetry The pointer of flag indicates try again
975 @param SenseDataArray The pointer of an array of sense data
976 @param NumberOfSenseKeys The pointer of the number of sense data array
977
978 @retval EFI_DEVICE_ERROR Indicates that error occurs
979 @retval EFI_SUCCESS Successfully to test unit
980
981 **/
982 EFI_STATUS
983 ScsiDiskTestUnitReady (
984 IN SCSI_DISK_DEV *ScsiDiskDevice,
985 OUT BOOLEAN *NeedRetry,
986 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
987 OUT UINTN *NumberOfSenseKeys
988 )
989 {
990 EFI_STATUS Status;
991 UINT8 SenseDataLength;
992 UINT8 HostAdapterStatus;
993 UINT8 TargetStatus;
994 UINT8 Index;
995 UINT8 MaxRetry;
996
997 SenseDataLength = 0;
998 *NumberOfSenseKeys = 0;
999
1000 //
1001 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1002 //
1003 Status = ScsiTestUnitReadyCommand (
1004 ScsiDiskDevice->ScsiIo,
1005 EFI_SCSI_STALL_SECONDS (1),
1006 NULL,
1007 &SenseDataLength,
1008 &HostAdapterStatus,
1009 &TargetStatus
1010 );
1011 //
1012 // no need to check HostAdapterStatus and TargetStatus
1013 //
1014 if (Status == EFI_NOT_READY) {
1015 *NeedRetry = TRUE;
1016 return EFI_DEVICE_ERROR;
1017
1018 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1019 *NeedRetry = FALSE;
1020 return EFI_DEVICE_ERROR;
1021 }
1022 //
1023 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1024 //
1025
1026 Status = CheckHostAdapterStatus (HostAdapterStatus);
1027 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1028 *NeedRetry = TRUE;
1029 return EFI_DEVICE_ERROR;
1030
1031 } else if (Status == EFI_DEVICE_ERROR) {
1032 //
1033 // reset the scsi channel
1034 //
1035 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1036 *NeedRetry = FALSE;
1037 return EFI_DEVICE_ERROR;
1038 }
1039
1040 Status = CheckTargetStatus (TargetStatus);
1041 if (Status == EFI_NOT_READY) {
1042 //
1043 // reset the scsi device
1044 //
1045 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1046 *NeedRetry = TRUE;
1047 return EFI_DEVICE_ERROR;
1048
1049 } else if (Status == EFI_DEVICE_ERROR) {
1050 *NeedRetry = FALSE;
1051 return EFI_DEVICE_ERROR;
1052 }
1053
1054 MaxRetry = 3;
1055 for (Index = 0; Index < MaxRetry; Index++) {
1056 Status = ScsiDiskRequestSenseKeys (
1057 ScsiDiskDevice,
1058 NeedRetry,
1059 SenseDataArray,
1060 NumberOfSenseKeys,
1061 FALSE
1062 );
1063 if (!EFI_ERROR (Status)) {
1064 return EFI_SUCCESS;
1065 }
1066
1067 if (!*NeedRetry) {
1068 return EFI_DEVICE_ERROR;
1069 }
1070 }
1071 //
1072 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1073 // set *NeedRetry = FALSE to avoid the outside caller try again.
1074 //
1075 *NeedRetry = FALSE;
1076 return EFI_DEVICE_ERROR;
1077 }
1078
1079 /**
1080 Parsing Sense Keys which got from request sense command.
1081
1082 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1083 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1084 @param NumberOfSenseKeys The number of sense key
1085 @param Action The pointer of action which indicates what is need to do next
1086
1087 @retval EFI_DEVICE_ERROR Indicates that error occurs
1088 @retval EFI_SUCCESS Successfully to complete the parsing
1089
1090 **/
1091 EFI_STATUS
1092 DetectMediaParsingSenseKeys (
1093 OUT SCSI_DISK_DEV *ScsiDiskDevice,
1094 IN EFI_SCSI_SENSE_DATA *SenseData,
1095 IN UINTN NumberOfSenseKeys,
1096 OUT UINTN *Action
1097 )
1098 {
1099 BOOLEAN RetryLater;
1100
1101 //
1102 // Default is to read capacity, unless..
1103 //
1104 *Action = ACTION_READ_CAPACITY;
1105
1106 if (NumberOfSenseKeys == 0) {
1107 *Action = ACTION_NO_ACTION;
1108 return EFI_SUCCESS;
1109 }
1110
1111 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
1112 //
1113 // No Sense Key returned from last submitted command
1114 //
1115 *Action = ACTION_NO_ACTION;
1116 return EFI_SUCCESS;
1117 }
1118
1119 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
1120 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
1121 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
1122 *Action = ACTION_NO_ACTION;
1123 return EFI_SUCCESS;
1124 }
1125
1126 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
1127 ScsiDiskDevice->BlkIo.Media->MediaId++;
1128 return EFI_SUCCESS;
1129 }
1130
1131 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
1132 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
1133 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
1134 return EFI_DEVICE_ERROR;
1135 }
1136
1137 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
1138 return EFI_DEVICE_ERROR;
1139 }
1140
1141 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
1142 if (RetryLater) {
1143 *Action = ACTION_RETRY_COMMAND_LATER;
1144 return EFI_SUCCESS;
1145 }
1146
1147 return EFI_DEVICE_ERROR;
1148 }
1149
1150 return EFI_SUCCESS;
1151 }
1152
1153
1154 /**
1155 Send read capacity command to device and get the device parameter.
1156
1157 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1158 @param NeedRetry The pointer of flag indicates if need a retry
1159 @param SenseDataArray The pointer of an array of sense data
1160 @param NumberOfSenseKeys The number of sense key
1161
1162 @retval EFI_DEVICE_ERROR Indicates that error occurs
1163 @retval EFI_SUCCESS Successfully to read capacity
1164
1165 **/
1166 EFI_STATUS
1167 ScsiDiskReadCapacity (
1168 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1169 OUT BOOLEAN *NeedRetry,
1170 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1171 OUT UINTN *NumberOfSenseKeys
1172 )
1173 {
1174 EFI_SCSI_DISK_CAPACITY_DATA CapacityData;
1175 UINT32 DataLength;
1176 UINT8 HostAdapterStatus;
1177 UINT8 TargetStatus;
1178 EFI_STATUS CommandStatus;
1179 EFI_STATUS Status;
1180 UINT8 Index;
1181 UINT8 MaxRetry;
1182 UINT8 SenseDataLength;
1183
1184 SenseDataLength = 0;
1185 ZeroMem (&CapacityData, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1186 DataLength = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
1187
1188 *NumberOfSenseKeys = 0;
1189 *NeedRetry = FALSE;
1190 //
1191 // submit Read Capacity Command. in this call,not request sense data
1192 //
1193 CommandStatus = ScsiReadCapacityCommand (
1194 ScsiDiskDevice->ScsiIo,
1195 EFI_SCSI_STALL_SECONDS (1),
1196 NULL,
1197 &SenseDataLength,
1198 &HostAdapterStatus,
1199 &TargetStatus,
1200 (VOID *) &CapacityData,
1201 &DataLength,
1202 FALSE
1203 );
1204 //
1205 // no need to check HostAdapterStatus and TargetStatus
1206 //
1207 if (CommandStatus == EFI_SUCCESS) {
1208 GetMediaInfo (ScsiDiskDevice, &CapacityData);
1209 return EFI_SUCCESS;
1210
1211 } else if (CommandStatus == EFI_NOT_READY) {
1212 *NeedRetry = TRUE;
1213 return EFI_DEVICE_ERROR;
1214
1215 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
1216 *NeedRetry = FALSE;
1217 return EFI_DEVICE_ERROR;
1218 }
1219 //
1220 // go ahead to check HostAdapterStatus and TargetStatus
1221 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1222 //
1223
1224 Status = CheckHostAdapterStatus (HostAdapterStatus);
1225 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1226 *NeedRetry = TRUE;
1227 return EFI_DEVICE_ERROR;
1228
1229 } else if (Status == EFI_DEVICE_ERROR) {
1230 //
1231 // reset the scsi channel
1232 //
1233 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1234 *NeedRetry = FALSE;
1235 return EFI_DEVICE_ERROR;
1236 }
1237
1238 Status = CheckTargetStatus (TargetStatus);
1239 if (Status == EFI_NOT_READY) {
1240 //
1241 // reset the scsi device
1242 //
1243 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1244 *NeedRetry = TRUE;
1245 return EFI_DEVICE_ERROR;
1246
1247 } else if (Status == EFI_DEVICE_ERROR) {
1248 *NeedRetry = FALSE;
1249 return EFI_DEVICE_ERROR;
1250 }
1251
1252 //
1253 // if goes here, meant SubmitReadCapacityCommand() failed.
1254 // if ScsiDiskRequestSenseKeys() succeeds at last,
1255 // better retry SubmitReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1256 //
1257 MaxRetry = 3;
1258 for (Index = 0; Index < MaxRetry; Index++) {
1259
1260 Status = ScsiDiskRequestSenseKeys (
1261 ScsiDiskDevice,
1262 NeedRetry,
1263 SenseDataArray,
1264 NumberOfSenseKeys,
1265 TRUE
1266 );
1267 if (!EFI_ERROR (Status)) {
1268 *NeedRetry = TRUE;
1269 return EFI_DEVICE_ERROR;
1270 }
1271
1272 if (!*NeedRetry) {
1273 return EFI_DEVICE_ERROR;
1274 }
1275 }
1276 //
1277 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1278 // set *NeedRetry = FALSE to avoid the outside caller try again.
1279 //
1280 *NeedRetry = FALSE;
1281 return EFI_DEVICE_ERROR;
1282 }
1283
1284 /**
1285 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1286
1287 @param HostAdapterStatus Host Adapter status
1288
1289 @retval EFI_SUCCESS Host adapter is OK.
1290 @retval EFI_TIMEOUT Timeout.
1291 @retval EFI_NOT_READY Adapter NOT ready.
1292 @retval EFI_DEVICE_ERROR Adapter device error.
1293
1294 **/
1295 EFI_STATUS
1296 CheckHostAdapterStatus (
1297 IN UINT8 HostAdapterStatus
1298 )
1299 {
1300 switch (HostAdapterStatus) {
1301 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
1302 return EFI_SUCCESS;
1303
1304 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
1305 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
1306 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
1307 return EFI_TIMEOUT;
1308
1309 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
1310 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
1311 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
1312 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
1313 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
1314 return EFI_NOT_READY;
1315
1316 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
1317 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
1318 return EFI_DEVICE_ERROR;
1319
1320 default:
1321 return EFI_SUCCESS;
1322 }
1323 }
1324
1325
1326 /**
1327 Check the target status and re-interpret it in EFI_STATUS.
1328
1329 @param TargetStatus Target status
1330
1331 @retval EFI_NOT_READY Device is NOT ready.
1332 @retval EFI_DEVICE_ERROR
1333 @retval EFI_SUCCESS
1334
1335 **/
1336 EFI_STATUS
1337 CheckTargetStatus (
1338 IN UINT8 TargetStatus
1339 )
1340 {
1341 switch (TargetStatus) {
1342 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
1343 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
1344 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
1345 return EFI_SUCCESS;
1346
1347 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
1348 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
1349 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
1350 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
1351 return EFI_NOT_READY;
1352
1353 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
1354 return EFI_DEVICE_ERROR;
1355 break;
1356
1357 default:
1358 return EFI_SUCCESS;
1359 }
1360 }
1361
1362
1363 /**
1364 Retrieve all sense keys from the device.
1365
1366 When encountering error during the process, if retrieve sense keys before
1367 error encounterred, it returns the sense keys with return status set to EFI_SUCCESS,
1368 and NeedRetry set to FALSE; otherwize, return the proper return status.
1369
1370 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1371 @param NeedRetry The pointer of flag indicates if need a retry
1372 @param SenseDataArray The pointer of an array of sense data
1373 @param NumberOfSenseKeys The number of sense key
1374 @param AskResetIfError The flag indicates if need reset when error occurs
1375
1376 @retval EFI_DEVICE_ERROR Indicates that error occurs
1377 @retval EFI_SUCCESS Successfully to request sense key
1378
1379 **/
1380 EFI_STATUS
1381 ScsiDiskRequestSenseKeys (
1382 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1383 OUT BOOLEAN *NeedRetry,
1384 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1385 OUT UINTN *NumberOfSenseKeys,
1386 IN BOOLEAN AskResetIfError
1387 )
1388 {
1389 EFI_SCSI_SENSE_DATA *PtrSenseData;
1390 UINT8 SenseDataLength;
1391 BOOLEAN SenseReq;
1392 EFI_STATUS Status;
1393 EFI_STATUS FallStatus;
1394 UINT8 HostAdapterStatus;
1395 UINT8 TargetStatus;
1396
1397 FallStatus = EFI_SUCCESS;
1398 SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);
1399
1400 ZeroMem (
1401 ScsiDiskDevice->SenseData,
1402 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
1403 );
1404
1405 *NumberOfSenseKeys = 0;
1406 *SenseDataArray = ScsiDiskDevice->SenseData;
1407 PtrSenseData = ScsiDiskDevice->SenseData;
1408
1409 for (SenseReq = TRUE; SenseReq;) {
1410 Status = ScsiRequestSenseCommand (
1411 ScsiDiskDevice->ScsiIo,
1412 EFI_SCSI_STALL_SECONDS (2),
1413 PtrSenseData,
1414 &SenseDataLength,
1415 &HostAdapterStatus,
1416 &TargetStatus
1417 );
1418 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
1419 FallStatus = EFI_SUCCESS;
1420
1421 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1422 *NeedRetry = TRUE;
1423 FallStatus = EFI_DEVICE_ERROR;
1424
1425 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1426 *NeedRetry = FALSE;
1427 FallStatus = EFI_DEVICE_ERROR;
1428
1429 } else if (Status == EFI_DEVICE_ERROR) {
1430 if (AskResetIfError) {
1431 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1432 }
1433
1434 FallStatus = EFI_DEVICE_ERROR;
1435 }
1436
1437 if (EFI_ERROR (FallStatus)) {
1438 if (*NumberOfSenseKeys != 0) {
1439 *NeedRetry = FALSE;
1440 return EFI_SUCCESS;
1441 } else {
1442 return EFI_DEVICE_ERROR;
1443 }
1444 }
1445
1446 (*NumberOfSenseKeys) += 1;
1447
1448 //
1449 // no more sense key or number of sense keys exceeds predefined,
1450 // skip the loop.
1451 //
1452 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
1453 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
1454 SenseReq = FALSE;
1455 }
1456 PtrSenseData += 1;
1457 }
1458 return EFI_SUCCESS;
1459 }
1460
1461
1462 /**
1463 Get information from media read capacity command.
1464
1465 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1466 @param Capacity The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1467
1468 **/
1469 VOID
1470 GetMediaInfo (
1471 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1472 IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity
1473 )
1474 {
1475 ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity->LastLba3 << 24) |
1476 (Capacity->LastLba2 << 16) |
1477 (Capacity->LastLba1 << 8) |
1478 Capacity->LastLba0;
1479
1480 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
1481 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity->BlockSize3 << 24) |
1482 (Capacity->BlockSize2 << 16) |
1483 (Capacity->BlockSize1 << 8) |
1484 Capacity->BlockSize0;
1485 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
1486 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
1487 }
1488
1489 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_CDROM) {
1490 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
1491 }
1492 }
1493
1494 /**
1495 Parse Inquiry data.
1496
1497 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1498
1499 **/
1500 VOID
1501 ParseInquiryData (
1502 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
1503 )
1504 {
1505 ScsiDiskDevice->FixedDevice = (BOOLEAN) (ScsiDiskDevice->InquiryData.RMB ? 0 : 1);
1506 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
1507 }
1508
1509 /**
1510 Read sector from SCSI Disk.
1511
1512 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV
1513 @param Buffer The buffer to fill in the read out data
1514 @param Lba Logic block address
1515 @param NumberOfBlocks The number of blocks to read
1516
1517 @retval EFI_DEVICE_ERROR Indicates a device error.
1518 @retval EFI_SUCCESS Operation is successful.
1519
1520 **/
1521 EFI_STATUS
1522 ScsiDiskReadSectors (
1523 IN SCSI_DISK_DEV *ScsiDiskDevice,
1524 OUT VOID *Buffer,
1525 IN EFI_LBA Lba,
1526 IN UINTN NumberOfBlocks
1527 )
1528 {
1529 UINTN BlocksRemaining;
1530 UINT32 Lba32;
1531 UINT8 *PtrBuffer;
1532 UINT32 BlockSize;
1533 UINT32 ByteCount;
1534 UINT32 MaxBlock;
1535 UINT32 SectorCount;
1536 UINT64 Timeout;
1537 EFI_STATUS Status;
1538 UINT8 Index;
1539 UINT8 MaxRetry;
1540 BOOLEAN NeedRetry;
1541 EFI_SCSI_SENSE_DATA *SenseData;
1542 UINTN NumberOfSenseKeys;
1543
1544 SenseData = NULL;
1545 NumberOfSenseKeys = 0;
1546
1547 Status = EFI_SUCCESS;
1548
1549 BlocksRemaining = NumberOfBlocks;
1550 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
1551 //
1552 // limit the data bytes that can be transferred by one Read(10) Command
1553 //
1554 MaxBlock = 65536;
1555
1556 PtrBuffer = Buffer;
1557 Lba32 = (UINT32) Lba;
1558
1559 while (BlocksRemaining > 0) {
1560
1561 if (BlocksRemaining <= MaxBlock) {
1562
1563 SectorCount = (UINT16) BlocksRemaining;
1564 } else {
1565
1566 SectorCount = MaxBlock;
1567 }
1568
1569 ByteCount = SectorCount * BlockSize;
1570 Timeout = EFI_SCSI_STALL_SECONDS (2);
1571
1572 MaxRetry = 2;
1573 for (Index = 0; Index < MaxRetry; Index++) {
1574
1575 Status = ScsiDiskRead10 (
1576 ScsiDiskDevice,
1577 &NeedRetry,
1578 &SenseData,
1579 &NumberOfSenseKeys,
1580 Timeout,
1581 PtrBuffer,
1582 &ByteCount,
1583 Lba32,
1584 SectorCount
1585 );
1586 if (!EFI_ERROR (Status)) {
1587 break;
1588 }
1589
1590 if (!NeedRetry) {
1591 return EFI_DEVICE_ERROR;
1592 }
1593
1594 }
1595
1596 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
1597 return EFI_DEVICE_ERROR;
1598 }
1599
1600 //
1601 // actual transferred sectors
1602 //
1603 SectorCount = ByteCount / BlockSize;
1604
1605 Lba32 += SectorCount;
1606 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
1607 BlocksRemaining -= SectorCount;
1608 }
1609
1610 return EFI_SUCCESS;
1611 }
1612
1613 /**
1614 Write sector to SCSI Disk.
1615
1616 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV
1617 @param Buffer The buffer of data to be written into SCSI Disk
1618 @param Lba Logic block address
1619 @param NumberOfBlocks The number of blocks to read
1620
1621 @retval EFI_DEVICE_ERROR Indicates a device error.
1622 @retval EFI_SUCCESS Operation is successful.
1623
1624 **/
1625 EFI_STATUS
1626 ScsiDiskWriteSectors (
1627 IN SCSI_DISK_DEV *ScsiDiskDevice,
1628 IN VOID *Buffer,
1629 IN EFI_LBA Lba,
1630 IN UINTN NumberOfBlocks
1631 )
1632 {
1633 UINTN BlocksRemaining;
1634 UINT32 Lba32;
1635 UINT8 *PtrBuffer;
1636 UINT32 BlockSize;
1637 UINT32 ByteCount;
1638 UINT32 MaxBlock;
1639 UINT32 SectorCount;
1640 UINT64 Timeout;
1641 EFI_STATUS Status;
1642 UINT8 Index;
1643 UINT8 MaxRetry;
1644 BOOLEAN NeedRetry;
1645 EFI_SCSI_SENSE_DATA *SenseData;
1646 UINTN NumberOfSenseKeys;
1647
1648 SenseData = NULL;
1649 NumberOfSenseKeys = 0;
1650
1651 Status = EFI_SUCCESS;
1652
1653 BlocksRemaining = NumberOfBlocks;
1654 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
1655 //
1656 // limit the data bytes that can be transferred by one Write(10) Command
1657 //
1658 MaxBlock = 65536;
1659
1660 PtrBuffer = Buffer;
1661 Lba32 = (UINT32) Lba;
1662
1663 while (BlocksRemaining > 0) {
1664
1665 if (BlocksRemaining <= MaxBlock) {
1666
1667 SectorCount = (UINT16) BlocksRemaining;
1668 } else {
1669
1670 SectorCount = MaxBlock;
1671 }
1672
1673 ByteCount = SectorCount * BlockSize;
1674 Timeout = EFI_SCSI_STALL_SECONDS (2);
1675 MaxRetry = 2;
1676 for (Index = 0; Index < MaxRetry; Index++) {
1677 Status = ScsiDiskWrite10 (
1678 ScsiDiskDevice,
1679 &NeedRetry,
1680 &SenseData,
1681 &NumberOfSenseKeys,
1682 Timeout,
1683 PtrBuffer,
1684 &ByteCount,
1685 Lba32,
1686 SectorCount
1687 );
1688 if (!EFI_ERROR (Status)) {
1689 break;
1690 }
1691
1692 if (!NeedRetry) {
1693 return EFI_DEVICE_ERROR;
1694 }
1695 }
1696
1697 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
1698 return EFI_DEVICE_ERROR;
1699 }
1700 //
1701 // actual transferred sectors
1702 //
1703 SectorCount = ByteCount / BlockSize;
1704
1705 Lba32 += SectorCount;
1706 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
1707 BlocksRemaining -= SectorCount;
1708 }
1709
1710 return EFI_SUCCESS;
1711 }
1712
1713
1714 /**
1715 Sumbmit Read command.
1716
1717 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1718 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1719 @param SenseDataArray NOT used yet in this function
1720 @param NumberOfSenseKeys The number of sense key
1721 @param Timeout The time to complete the command
1722 @param DataBuffer The buffer to fill with the read out data
1723 @param DataLength The length of buffer
1724 @param StartLba The start logic block address
1725 @param SectorSize The size of sector
1726
1727 @return EFI_STATUS is returned by calling ScsiRead10Command().
1728 **/
1729 EFI_STATUS
1730 ScsiDiskRead10 (
1731 IN SCSI_DISK_DEV *ScsiDiskDevice,
1732 OUT BOOLEAN *NeedRetry,
1733 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
1734 OUT UINTN *NumberOfSenseKeys,
1735 IN UINT64 Timeout,
1736 OUT UINT8 *DataBuffer,
1737 IN OUT UINT32 *DataLength,
1738 IN UINT32 StartLba,
1739 IN UINT32 SectorSize
1740 )
1741 {
1742 UINT8 SenseDataLength;
1743 EFI_STATUS Status;
1744 UINT8 HostAdapterStatus;
1745 UINT8 TargetStatus;
1746
1747 *NeedRetry = FALSE;
1748 *NumberOfSenseKeys = 0;
1749 SenseDataLength = 0;
1750 Status = ScsiRead10Command (
1751 ScsiDiskDevice->ScsiIo,
1752 Timeout,
1753 NULL,
1754 &SenseDataLength,
1755 &HostAdapterStatus,
1756 &TargetStatus,
1757 DataBuffer,
1758 DataLength,
1759 StartLba,
1760 SectorSize
1761 );
1762 return Status;
1763 }
1764
1765
1766 /**
1767 Submit Write Command.
1768
1769 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1770 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1771 @param SenseDataArray NOT used yet in this function
1772 @param NumberOfSenseKeys The number of sense key
1773 @param Timeout The time to complete the command
1774 @param DataBuffer The buffer to fill with the read out data
1775 @param DataLength The length of buffer
1776 @param StartLba The start logic block address
1777 @param SectorSize The size of sector
1778
1779 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1780
1781 **/
1782 EFI_STATUS
1783 ScsiDiskWrite10 (
1784 IN SCSI_DISK_DEV *ScsiDiskDevice,
1785 OUT BOOLEAN *NeedRetry,
1786 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
1787 OUT UINTN *NumberOfSenseKeys,
1788 IN UINT64 Timeout,
1789 IN UINT8 *DataBuffer,
1790 IN OUT UINT32 *DataLength,
1791 IN UINT32 StartLba,
1792 IN UINT32 SectorSize
1793 )
1794 {
1795 EFI_STATUS Status;
1796 UINT8 SenseDataLength;
1797 UINT8 HostAdapterStatus;
1798 UINT8 TargetStatus;
1799
1800 *NeedRetry = FALSE;
1801 *NumberOfSenseKeys = 0;
1802 SenseDataLength = 0;
1803 Status = ScsiWrite10Command (
1804 ScsiDiskDevice->ScsiIo,
1805 Timeout,
1806 NULL,
1807 &SenseDataLength,
1808 &HostAdapterStatus,
1809 &TargetStatus,
1810 DataBuffer,
1811 DataLength,
1812 StartLba,
1813 SectorSize
1814 );
1815 return Status;
1816 }
1817
1818
1819 /**
1820 Check sense key to find if media presents.
1821
1822 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1823 @param SenseCounts The number of sense key
1824
1825 @retval TRUE NOT any media
1826 @retval FALSE Media presents
1827 **/
1828 BOOLEAN
1829 ScsiDiskIsNoMedia (
1830 IN EFI_SCSI_SENSE_DATA *SenseData,
1831 IN UINTN SenseCounts
1832 )
1833 {
1834 EFI_SCSI_SENSE_DATA *SensePtr;
1835 UINTN Index;
1836 BOOLEAN IsNoMedia;
1837
1838 IsNoMedia = FALSE;
1839 SensePtr = SenseData;
1840
1841 for (Index = 0; Index < SenseCounts; Index++) {
1842 //
1843 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
1844 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
1845 //
1846 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
1847 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
1848 IsNoMedia = TRUE;
1849 }
1850 SensePtr++;
1851 }
1852
1853 return IsNoMedia;
1854 }
1855
1856
1857 /**
1858 Parse sense key.
1859
1860 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1861 @param SenseCounts The number of sense key
1862
1863 @retval TRUE Error
1864 @retval FALSE NOT error
1865
1866 **/
1867 BOOLEAN
1868 ScsiDiskIsMediaError (
1869 IN EFI_SCSI_SENSE_DATA *SenseData,
1870 IN UINTN SenseCounts
1871 )
1872 {
1873 EFI_SCSI_SENSE_DATA *SensePtr;
1874 UINTN Index;
1875 BOOLEAN IsError;
1876
1877 IsError = FALSE;
1878 SensePtr = SenseData;
1879
1880 for (Index = 0; Index < SenseCounts; Index++) {
1881
1882 switch (SensePtr->Sense_Key) {
1883
1884 case EFI_SCSI_SK_MEDIUM_ERROR:
1885 //
1886 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
1887 //
1888 switch (SensePtr->Addnl_Sense_Code) {
1889
1890 //
1891 // fall through
1892 //
1893 case EFI_SCSI_ASC_MEDIA_ERR1:
1894
1895 //
1896 // fall through
1897 //
1898 case EFI_SCSI_ASC_MEDIA_ERR2:
1899
1900 //
1901 // fall through
1902 //
1903 case EFI_SCSI_ASC_MEDIA_ERR3:
1904 case EFI_SCSI_ASC_MEDIA_ERR4:
1905 IsError = TRUE;
1906 break;
1907
1908 default:
1909 break;
1910 }
1911
1912 break;
1913
1914 case EFI_SCSI_SK_NOT_READY:
1915 //
1916 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
1917 //
1918 switch (SensePtr->Addnl_Sense_Code) {
1919 //
1920 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
1921 //
1922 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
1923 IsError = TRUE;
1924 break;
1925
1926 default:
1927 break;
1928 }
1929 break;
1930
1931 default:
1932 break;
1933 }
1934
1935 SensePtr++;
1936 }
1937
1938 return IsError;
1939 }
1940
1941
1942 /**
1943 Check sense key to find if hardware error happens.
1944
1945 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1946 @param SenseCounts The number of sense key
1947
1948 @retval TRUE Hardware error exits.
1949 @retval FALSE NO error.
1950
1951 **/
1952 BOOLEAN
1953 ScsiDiskIsHardwareError (
1954 IN EFI_SCSI_SENSE_DATA *SenseData,
1955 IN UINTN SenseCounts
1956 )
1957 {
1958 EFI_SCSI_SENSE_DATA *SensePtr;
1959 UINTN Index;
1960 BOOLEAN IsError;
1961
1962 IsError = FALSE;
1963 SensePtr = SenseData;
1964
1965 for (Index = 0; Index < SenseCounts; Index++) {
1966
1967 //
1968 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
1969 //
1970 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
1971 IsError = TRUE;
1972 }
1973
1974 SensePtr++;
1975 }
1976
1977 return IsError;
1978 }
1979
1980
1981 /**
1982 Check sense key to find if media has changed.
1983
1984 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1985 @param SenseCounts The number of sense key
1986
1987 @retval TRUE Media is changed.
1988 @retval FALSE Medit is NOT changed.
1989 **/
1990 BOOLEAN
1991 ScsiDiskIsMediaChange (
1992 IN EFI_SCSI_SENSE_DATA *SenseData,
1993 IN UINTN SenseCounts
1994 )
1995 {
1996 EFI_SCSI_SENSE_DATA *SensePtr;
1997 UINTN Index;
1998 BOOLEAN IsMediaChanged;
1999
2000 IsMediaChanged = FALSE;
2001 SensePtr = SenseData;
2002
2003 for (Index = 0; Index < SenseCounts; Index++) {
2004 //
2005 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2006 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2007 //
2008 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
2009 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
2010 IsMediaChanged = TRUE;
2011 }
2012
2013 SensePtr++;
2014 }
2015
2016 return IsMediaChanged;
2017 }
2018
2019 /**
2020 Check sense key to find if reset happens.
2021
2022 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2023 @param SenseCounts The number of sense key
2024
2025 @retval TRUE It is reset before.
2026 @retval FALSE It is NOT reset before.
2027
2028 **/
2029 BOOLEAN
2030 ScsiDiskIsResetBefore (
2031 IN EFI_SCSI_SENSE_DATA *SenseData,
2032 IN UINTN SenseCounts
2033 )
2034 {
2035 EFI_SCSI_SENSE_DATA *SensePtr;
2036 UINTN Index;
2037 BOOLEAN IsResetBefore;
2038
2039 IsResetBefore = FALSE;
2040 SensePtr = SenseData;
2041
2042 for (Index = 0; Index < SenseCounts; Index++) {
2043
2044 //
2045 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2046 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2047 //
2048 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
2049 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
2050 IsResetBefore = TRUE;
2051 }
2052
2053 SensePtr++;
2054 }
2055
2056 return IsResetBefore;
2057 }
2058
2059 /**
2060 Check sense key to find if the drive is ready.
2061
2062 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2063 @param SenseCounts The number of sense key
2064 @param RetryLater The flag means if need a retry
2065
2066 @retval TRUE Drive is ready.
2067 @retval FALSE Drive is NOT ready.
2068
2069 **/
2070 BOOLEAN
2071 ScsiDiskIsDriveReady (
2072 IN EFI_SCSI_SENSE_DATA *SenseData,
2073 IN UINTN SenseCounts,
2074 OUT BOOLEAN *RetryLater
2075 )
2076 {
2077 EFI_SCSI_SENSE_DATA *SensePtr;
2078 UINTN Index;
2079 BOOLEAN IsReady;
2080
2081 IsReady = TRUE;
2082 *RetryLater = FALSE;
2083 SensePtr = SenseData;
2084
2085 for (Index = 0; Index < SenseCounts; Index++) {
2086
2087 switch (SensePtr->Sense_Key) {
2088
2089 case EFI_SCSI_SK_NOT_READY:
2090 //
2091 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2092 //
2093 switch (SensePtr->Addnl_Sense_Code) {
2094 case EFI_SCSI_ASC_NOT_READY:
2095 //
2096 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2097 //
2098 switch (SensePtr->Addnl_Sense_Code_Qualifier) {
2099 case EFI_SCSI_ASCQ_IN_PROGRESS:
2100 //
2101 // Additional Sense Code Qualifier is
2102 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2103 //
2104 IsReady = FALSE;
2105 *RetryLater = TRUE;
2106 break;
2107
2108 default:
2109 IsReady = FALSE;
2110 *RetryLater = FALSE;
2111 break;
2112 }
2113 break;
2114
2115 default:
2116 break;
2117 }
2118 break;
2119
2120 default:
2121 break;
2122 }
2123
2124 SensePtr++;
2125 }
2126
2127 return IsReady;
2128 }
2129
2130 /**
2131 Check sense key to find if it has sense key.
2132
2133 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2134 @param SenseCounts - The number of sense key
2135
2136 @retval TRUE It has sense key.
2137 @retval FALSE It has NOT any sense key.
2138
2139 **/
2140 BOOLEAN
2141 ScsiDiskHaveSenseKey (
2142 IN EFI_SCSI_SENSE_DATA *SenseData,
2143 IN UINTN SenseCounts
2144 )
2145 {
2146 EFI_SCSI_SENSE_DATA *SensePtr;
2147 UINTN Index;
2148 BOOLEAN HaveSenseKey;
2149
2150 if (SenseCounts == 0) {
2151 HaveSenseKey = FALSE;
2152 } else {
2153 HaveSenseKey = TRUE;
2154 }
2155
2156 SensePtr = SenseData;
2157
2158 for (Index = 0; Index < SenseCounts; Index++) {
2159
2160 //
2161 // Sense Key is SK_NO_SENSE (0x0)
2162 //
2163 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
2164 (Index == 0)) {
2165 HaveSenseKey = FALSE;
2166 }
2167
2168 SensePtr++;
2169 }
2170
2171 return HaveSenseKey;
2172 }
2173
2174 /**
2175 Release resource about disk device.
2176
2177 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2178
2179 **/
2180 VOID
2181 ReleaseScsiDiskDeviceResources (
2182 IN SCSI_DISK_DEV *ScsiDiskDevice
2183 )
2184 {
2185 if (ScsiDiskDevice == NULL) {
2186 return ;
2187 }
2188
2189 if (ScsiDiskDevice->SenseData != NULL) {
2190 gBS->FreePool (ScsiDiskDevice->SenseData);
2191 ScsiDiskDevice->SenseData = NULL;
2192 }
2193
2194 if (ScsiDiskDevice->ControllerNameTable != NULL) {
2195 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
2196 ScsiDiskDevice->ControllerNameTable = NULL;
2197 }
2198
2199 gBS->FreePool (ScsiDiskDevice);
2200
2201 ScsiDiskDevice = NULL;
2202 }