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