]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
Read-Capacity16 command added for SCSI drivers
[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 ScsiInquiryCommand() failed.
925 // if ScsiDiskRequestSenseKeys() succeeds at last,
926 // better retry ScsiInquiryCommand(). (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 UINT8 HostAdapterStatus;
1163 UINT8 TargetStatus;
1164 EFI_STATUS CommandStatus;
1165 EFI_STATUS Status;
1166 UINT8 Index;
1167 UINT8 MaxRetry;
1168 UINT8 SenseDataLength;
1169 UINT8 ScsiVersion;
1170 UINT32 DataLength10;
1171 UINT32 DataLength16;
1172 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10;
1173 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16;
1174
1175
1176 SenseDataLength = 0;
1177 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
1178 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
1179 ZeroMem (&CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1180 ZeroMem (&CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1181
1182 *NumberOfSenseKeys = 0;
1183 *NeedRetry = FALSE;
1184 ScsiVersion = (UINT8)(ScsiDiskDevice->InquiryData.Version & 0x03);
1185
1186 if (ScsiVersion < SCSI_COMMAND_VERSION_3) {
1187 //
1188 // submit Read Capacity(10) Command. in this call,not request sense data
1189 //
1190 CommandStatus = ScsiReadCapacityCommand (
1191 ScsiDiskDevice->ScsiIo,
1192 EFI_TIMER_PERIOD_SECONDS(1),
1193 NULL,
1194 &SenseDataLength,
1195 &HostAdapterStatus,
1196 &TargetStatus,
1197 (VOID *) &CapacityData10,
1198 &DataLength10,
1199 FALSE
1200 );
1201 } else {
1202 //
1203 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1204 // and LowestAlignedLba
1205 //
1206 CommandStatus = ScsiReadCapacity16Command (
1207 ScsiDiskDevice->ScsiIo,
1208 EFI_TIMER_PERIOD_SECONDS (1),
1209 NULL,
1210 &SenseDataLength,
1211 &HostAdapterStatus,
1212 &TargetStatus,
1213 (VOID *) &CapacityData16,
1214 &DataLength16,
1215 FALSE
1216 );
1217 }
1218 //
1219 // no need to check HostAdapterStatus and TargetStatus
1220 //
1221 if (CommandStatus == EFI_SUCCESS) {
1222 GetMediaInfo (ScsiDiskDevice, &CapacityData10,&CapacityData16);
1223 return EFI_SUCCESS;
1224
1225 } else if (CommandStatus == EFI_NOT_READY) {
1226 *NeedRetry = TRUE;
1227 return EFI_DEVICE_ERROR;
1228
1229 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
1230 *NeedRetry = FALSE;
1231 return EFI_DEVICE_ERROR;
1232 }
1233 //
1234 // go ahead to check HostAdapterStatus and TargetStatus
1235 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1236 //
1237
1238 Status = CheckHostAdapterStatus (HostAdapterStatus);
1239 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1240 *NeedRetry = TRUE;
1241 return EFI_DEVICE_ERROR;
1242
1243 } else if (Status == EFI_DEVICE_ERROR) {
1244 //
1245 // reset the scsi channel
1246 //
1247 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1248 *NeedRetry = FALSE;
1249 return EFI_DEVICE_ERROR;
1250 }
1251
1252 Status = CheckTargetStatus (TargetStatus);
1253 if (Status == EFI_NOT_READY) {
1254 //
1255 // reset the scsi device
1256 //
1257 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1258 *NeedRetry = TRUE;
1259 return EFI_DEVICE_ERROR;
1260
1261 } else if (Status == EFI_DEVICE_ERROR) {
1262 *NeedRetry = FALSE;
1263 return EFI_DEVICE_ERROR;
1264 }
1265
1266 //
1267 // if goes here, meant ScsiReadCapacityCommand() failed.
1268 // if ScsiDiskRequestSenseKeys() succeeds at last,
1269 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1270 //
1271 MaxRetry = 3;
1272 for (Index = 0; Index < MaxRetry; Index++) {
1273
1274 Status = ScsiDiskRequestSenseKeys (
1275 ScsiDiskDevice,
1276 NeedRetry,
1277 SenseDataArray,
1278 NumberOfSenseKeys,
1279 TRUE
1280 );
1281 if (!EFI_ERROR (Status)) {
1282 *NeedRetry = TRUE;
1283 return EFI_DEVICE_ERROR;
1284 }
1285
1286 if (!*NeedRetry) {
1287 return EFI_DEVICE_ERROR;
1288 }
1289 }
1290 //
1291 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1292 // set *NeedRetry = FALSE to avoid the outside caller try again.
1293 //
1294 *NeedRetry = FALSE;
1295 return EFI_DEVICE_ERROR;
1296 }
1297
1298 /**
1299 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1300
1301 @param HostAdapterStatus Host Adapter status
1302
1303 @retval EFI_SUCCESS Host adapter is OK.
1304 @retval EFI_TIMEOUT Timeout.
1305 @retval EFI_NOT_READY Adapter NOT ready.
1306 @retval EFI_DEVICE_ERROR Adapter device error.
1307
1308 **/
1309 EFI_STATUS
1310 CheckHostAdapterStatus (
1311 IN UINT8 HostAdapterStatus
1312 )
1313 {
1314 switch (HostAdapterStatus) {
1315 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
1316 return EFI_SUCCESS;
1317
1318 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
1319 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
1320 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
1321 return EFI_TIMEOUT;
1322
1323 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
1324 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
1325 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
1326 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
1327 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
1328 return EFI_NOT_READY;
1329
1330 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
1331 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
1332 return EFI_DEVICE_ERROR;
1333
1334 default:
1335 return EFI_SUCCESS;
1336 }
1337 }
1338
1339
1340 /**
1341 Check the target status and re-interpret it in EFI_STATUS.
1342
1343 @param TargetStatus Target status
1344
1345 @retval EFI_NOT_READY Device is NOT ready.
1346 @retval EFI_DEVICE_ERROR
1347 @retval EFI_SUCCESS
1348
1349 **/
1350 EFI_STATUS
1351 CheckTargetStatus (
1352 IN UINT8 TargetStatus
1353 )
1354 {
1355 switch (TargetStatus) {
1356 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
1357 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
1358 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
1359 return EFI_SUCCESS;
1360
1361 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
1362 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
1363 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
1364 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
1365 return EFI_NOT_READY;
1366
1367 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
1368 return EFI_DEVICE_ERROR;
1369 break;
1370
1371 default:
1372 return EFI_SUCCESS;
1373 }
1374 }
1375
1376
1377 /**
1378 Retrieve all sense keys from the device.
1379
1380 When encountering error during the process, if retrieve sense keys before
1381 error encounterred, it returns the sense keys with return status set to EFI_SUCCESS,
1382 and NeedRetry set to FALSE; otherwize, return the proper return status.
1383
1384 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1385 @param NeedRetry The pointer of flag indicates if need a retry
1386 @param SenseDataArray The pointer of an array of sense data
1387 @param NumberOfSenseKeys The number of sense key
1388 @param AskResetIfError The flag indicates if need reset when error occurs
1389
1390 @retval EFI_DEVICE_ERROR Indicates that error occurs
1391 @retval EFI_SUCCESS Successfully to request sense key
1392
1393 **/
1394 EFI_STATUS
1395 ScsiDiskRequestSenseKeys (
1396 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1397 OUT BOOLEAN *NeedRetry,
1398 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1399 OUT UINTN *NumberOfSenseKeys,
1400 IN BOOLEAN AskResetIfError
1401 )
1402 {
1403 EFI_SCSI_SENSE_DATA *PtrSenseData;
1404 UINT8 SenseDataLength;
1405 BOOLEAN SenseReq;
1406 EFI_STATUS Status;
1407 EFI_STATUS FallStatus;
1408 UINT8 HostAdapterStatus;
1409 UINT8 TargetStatus;
1410
1411 FallStatus = EFI_SUCCESS;
1412 SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);
1413
1414 ZeroMem (
1415 ScsiDiskDevice->SenseData,
1416 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
1417 );
1418
1419 *NumberOfSenseKeys = 0;
1420 *SenseDataArray = ScsiDiskDevice->SenseData;
1421 PtrSenseData = ScsiDiskDevice->SenseData;
1422
1423 for (SenseReq = TRUE; SenseReq;) {
1424 Status = ScsiRequestSenseCommand (
1425 ScsiDiskDevice->ScsiIo,
1426 EFI_TIMER_PERIOD_SECONDS (2),
1427 PtrSenseData,
1428 &SenseDataLength,
1429 &HostAdapterStatus,
1430 &TargetStatus
1431 );
1432 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
1433 FallStatus = EFI_SUCCESS;
1434
1435 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1436 *NeedRetry = TRUE;
1437 FallStatus = EFI_DEVICE_ERROR;
1438
1439 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1440 *NeedRetry = FALSE;
1441 FallStatus = EFI_DEVICE_ERROR;
1442
1443 } else if (Status == EFI_DEVICE_ERROR) {
1444 if (AskResetIfError) {
1445 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1446 }
1447
1448 FallStatus = EFI_DEVICE_ERROR;
1449 }
1450
1451 if (EFI_ERROR (FallStatus)) {
1452 if (*NumberOfSenseKeys != 0) {
1453 *NeedRetry = FALSE;
1454 return EFI_SUCCESS;
1455 } else {
1456 return EFI_DEVICE_ERROR;
1457 }
1458 }
1459
1460 (*NumberOfSenseKeys) += 1;
1461
1462 //
1463 // no more sense key or number of sense keys exceeds predefined,
1464 // skip the loop.
1465 //
1466 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
1467 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
1468 SenseReq = FALSE;
1469 }
1470 PtrSenseData += 1;
1471 }
1472 return EFI_SUCCESS;
1473 }
1474
1475
1476 /**
1477 Get information from media read capacity command.
1478
1479 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1480 @param Capacity The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1481
1482 **/
1483 VOID
1484 GetMediaInfo (
1485 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1486 EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,
1487 EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16
1488 )
1489 {
1490 UINT8 ScsiVersion;
1491 UINT8 *Ptr;
1492
1493 ScsiVersion = (UINT8)(ScsiDiskDevice->InquiryData.Version & 0x03);
1494 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;
1495 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;
1496
1497
1498 if (ScsiVersion < SCSI_COMMAND_VERSION_3) {
1499 ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity10->LastLba3 << 24) |
1500 (Capacity10->LastLba2 << 16) |
1501 (Capacity10->LastLba1 << 8) |
1502 Capacity10->LastLba0;
1503
1504 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
1505 (Capacity10->BlockSize2 << 16) |
1506 (Capacity10->BlockSize1 << 8) |
1507 Capacity10->BlockSize0;
1508 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
1509 } else {
1510
1511 Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;
1512 *Ptr++ = Capacity16->LastLba0;
1513 *Ptr++ = Capacity16->LastLba1;
1514 *Ptr++ = Capacity16->LastLba2;
1515 *Ptr++ = Capacity16->LastLba3;
1516 *Ptr++ = Capacity16->LastLba4;
1517 *Ptr++ = Capacity16->LastLba5;
1518 *Ptr++ = Capacity16->LastLba6;
1519 *Ptr = Capacity16->LastLba7;
1520
1521 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
1522 (Capacity16->BlockSize2 << 16) |
1523 (Capacity16->BlockSize1 << 8) |
1524 Capacity16->BlockSize0;
1525
1526 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8)|(Capacity16->LowestAlignLogic1);
1527 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = Capacity16->LogicPerPhysical;
1528 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;
1529 }
1530
1531
1532 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
1533
1534 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
1535 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
1536 }
1537
1538 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_CDROM) {
1539 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
1540 }
1541 }
1542
1543 /**
1544 Parse Inquiry data.
1545
1546 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1547
1548 **/
1549 VOID
1550 ParseInquiryData (
1551 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
1552 )
1553 {
1554 ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
1555 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
1556 }
1557
1558 /**
1559 Read sector from SCSI Disk.
1560
1561 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV
1562 @param Buffer The buffer to fill in the read out data
1563 @param Lba Logic block address
1564 @param NumberOfBlocks The number of blocks to read
1565
1566 @retval EFI_DEVICE_ERROR Indicates a device error.
1567 @retval EFI_SUCCESS Operation is successful.
1568
1569 **/
1570 EFI_STATUS
1571 ScsiDiskReadSectors (
1572 IN SCSI_DISK_DEV *ScsiDiskDevice,
1573 OUT VOID *Buffer,
1574 IN EFI_LBA Lba,
1575 IN UINTN NumberOfBlocks
1576 )
1577 {
1578 UINTN BlocksRemaining;
1579 UINT32 Lba32;
1580 UINT8 *PtrBuffer;
1581 UINT32 BlockSize;
1582 UINT32 ByteCount;
1583 UINT32 MaxBlock;
1584 UINT32 SectorCount;
1585 UINT64 Timeout;
1586 EFI_STATUS Status;
1587 UINT8 Index;
1588 UINT8 MaxRetry;
1589 BOOLEAN NeedRetry;
1590 EFI_SCSI_SENSE_DATA *SenseData;
1591 UINTN NumberOfSenseKeys;
1592
1593 SenseData = NULL;
1594 NumberOfSenseKeys = 0;
1595
1596 Status = EFI_SUCCESS;
1597
1598 BlocksRemaining = NumberOfBlocks;
1599 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
1600 //
1601 // limit the data bytes that can be transferred by one Read(10) Command
1602 //
1603 MaxBlock = 65536;
1604
1605 PtrBuffer = Buffer;
1606 Lba32 = (UINT32) Lba;
1607
1608 while (BlocksRemaining > 0) {
1609
1610 if (BlocksRemaining <= MaxBlock) {
1611
1612 SectorCount = (UINT16) BlocksRemaining;
1613 } else {
1614
1615 SectorCount = MaxBlock;
1616 }
1617
1618 ByteCount = SectorCount * BlockSize;
1619 Timeout = EFI_TIMER_PERIOD_SECONDS (2);
1620
1621 MaxRetry = 2;
1622 for (Index = 0; Index < MaxRetry; Index++) {
1623
1624 Status = ScsiDiskRead10 (
1625 ScsiDiskDevice,
1626 &NeedRetry,
1627 &SenseData,
1628 &NumberOfSenseKeys,
1629 Timeout,
1630 PtrBuffer,
1631 &ByteCount,
1632 Lba32,
1633 SectorCount
1634 );
1635 if (!EFI_ERROR (Status)) {
1636 break;
1637 }
1638
1639 if (!NeedRetry) {
1640 return EFI_DEVICE_ERROR;
1641 }
1642
1643 }
1644
1645 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
1646 return EFI_DEVICE_ERROR;
1647 }
1648
1649 //
1650 // actual transferred sectors
1651 //
1652 SectorCount = ByteCount / BlockSize;
1653
1654 Lba32 += SectorCount;
1655 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
1656 BlocksRemaining -= SectorCount;
1657 }
1658
1659 return EFI_SUCCESS;
1660 }
1661
1662 /**
1663 Write sector to SCSI Disk.
1664
1665 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV
1666 @param Buffer The buffer of data to be written into SCSI Disk
1667 @param Lba Logic block address
1668 @param NumberOfBlocks The number of blocks to read
1669
1670 @retval EFI_DEVICE_ERROR Indicates a device error.
1671 @retval EFI_SUCCESS Operation is successful.
1672
1673 **/
1674 EFI_STATUS
1675 ScsiDiskWriteSectors (
1676 IN SCSI_DISK_DEV *ScsiDiskDevice,
1677 IN VOID *Buffer,
1678 IN EFI_LBA Lba,
1679 IN UINTN NumberOfBlocks
1680 )
1681 {
1682 UINTN BlocksRemaining;
1683 UINT32 Lba32;
1684 UINT8 *PtrBuffer;
1685 UINT32 BlockSize;
1686 UINT32 ByteCount;
1687 UINT32 MaxBlock;
1688 UINT32 SectorCount;
1689 UINT64 Timeout;
1690 EFI_STATUS Status;
1691 UINT8 Index;
1692 UINT8 MaxRetry;
1693 BOOLEAN NeedRetry;
1694 EFI_SCSI_SENSE_DATA *SenseData;
1695 UINTN NumberOfSenseKeys;
1696
1697 SenseData = NULL;
1698 NumberOfSenseKeys = 0;
1699
1700 Status = EFI_SUCCESS;
1701
1702 BlocksRemaining = NumberOfBlocks;
1703 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
1704 //
1705 // limit the data bytes that can be transferred by one Write(10) Command
1706 //
1707 MaxBlock = 65536;
1708
1709 PtrBuffer = Buffer;
1710 Lba32 = (UINT32) Lba;
1711
1712 while (BlocksRemaining > 0) {
1713
1714 if (BlocksRemaining <= MaxBlock) {
1715
1716 SectorCount = (UINT16) BlocksRemaining;
1717 } else {
1718
1719 SectorCount = MaxBlock;
1720 }
1721
1722 ByteCount = SectorCount * BlockSize;
1723 Timeout = EFI_TIMER_PERIOD_SECONDS (2);
1724 MaxRetry = 2;
1725 for (Index = 0; Index < MaxRetry; Index++) {
1726 Status = ScsiDiskWrite10 (
1727 ScsiDiskDevice,
1728 &NeedRetry,
1729 &SenseData,
1730 &NumberOfSenseKeys,
1731 Timeout,
1732 PtrBuffer,
1733 &ByteCount,
1734 Lba32,
1735 SectorCount
1736 );
1737 if (!EFI_ERROR (Status)) {
1738 break;
1739 }
1740
1741 if (!NeedRetry) {
1742 return EFI_DEVICE_ERROR;
1743 }
1744 }
1745
1746 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
1747 return EFI_DEVICE_ERROR;
1748 }
1749 //
1750 // actual transferred sectors
1751 //
1752 SectorCount = ByteCount / BlockSize;
1753
1754 Lba32 += SectorCount;
1755 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
1756 BlocksRemaining -= SectorCount;
1757 }
1758
1759 return EFI_SUCCESS;
1760 }
1761
1762
1763 /**
1764 Sumbmit Read command.
1765
1766 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1767 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1768 @param SenseDataArray NOT used yet in this function
1769 @param NumberOfSenseKeys The number of sense key
1770 @param Timeout The time to complete the command
1771 @param DataBuffer The buffer to fill with the read out data
1772 @param DataLength The length of buffer
1773 @param StartLba The start logic block address
1774 @param SectorSize The size of sector
1775
1776 @return EFI_STATUS is returned by calling ScsiRead10Command().
1777 **/
1778 EFI_STATUS
1779 ScsiDiskRead10 (
1780 IN SCSI_DISK_DEV *ScsiDiskDevice,
1781 OUT BOOLEAN *NeedRetry,
1782 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
1783 OUT UINTN *NumberOfSenseKeys,
1784 IN UINT64 Timeout,
1785 OUT UINT8 *DataBuffer,
1786 IN OUT UINT32 *DataLength,
1787 IN UINT32 StartLba,
1788 IN UINT32 SectorSize
1789 )
1790 {
1791 UINT8 SenseDataLength;
1792 EFI_STATUS Status;
1793 UINT8 HostAdapterStatus;
1794 UINT8 TargetStatus;
1795
1796 *NeedRetry = FALSE;
1797 *NumberOfSenseKeys = 0;
1798 SenseDataLength = 0;
1799 Status = ScsiRead10Command (
1800 ScsiDiskDevice->ScsiIo,
1801 Timeout,
1802 NULL,
1803 &SenseDataLength,
1804 &HostAdapterStatus,
1805 &TargetStatus,
1806 DataBuffer,
1807 DataLength,
1808 StartLba,
1809 SectorSize
1810 );
1811 return Status;
1812 }
1813
1814
1815 /**
1816 Submit Write Command.
1817
1818 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1819 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1820 @param SenseDataArray NOT used yet in this function
1821 @param NumberOfSenseKeys The number of sense key
1822 @param Timeout The time to complete the command
1823 @param DataBuffer The buffer to fill with the read out data
1824 @param DataLength The length of buffer
1825 @param StartLba The start logic block address
1826 @param SectorSize The size of sector
1827
1828 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1829
1830 **/
1831 EFI_STATUS
1832 ScsiDiskWrite10 (
1833 IN SCSI_DISK_DEV *ScsiDiskDevice,
1834 OUT BOOLEAN *NeedRetry,
1835 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
1836 OUT UINTN *NumberOfSenseKeys,
1837 IN UINT64 Timeout,
1838 IN UINT8 *DataBuffer,
1839 IN OUT UINT32 *DataLength,
1840 IN UINT32 StartLba,
1841 IN UINT32 SectorSize
1842 )
1843 {
1844 EFI_STATUS Status;
1845 UINT8 SenseDataLength;
1846 UINT8 HostAdapterStatus;
1847 UINT8 TargetStatus;
1848
1849 *NeedRetry = FALSE;
1850 *NumberOfSenseKeys = 0;
1851 SenseDataLength = 0;
1852 Status = ScsiWrite10Command (
1853 ScsiDiskDevice->ScsiIo,
1854 Timeout,
1855 NULL,
1856 &SenseDataLength,
1857 &HostAdapterStatus,
1858 &TargetStatus,
1859 DataBuffer,
1860 DataLength,
1861 StartLba,
1862 SectorSize
1863 );
1864 return Status;
1865 }
1866
1867
1868 /**
1869 Check sense key to find if media presents.
1870
1871 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1872 @param SenseCounts The number of sense key
1873
1874 @retval TRUE NOT any media
1875 @retval FALSE Media presents
1876 **/
1877 BOOLEAN
1878 ScsiDiskIsNoMedia (
1879 IN EFI_SCSI_SENSE_DATA *SenseData,
1880 IN UINTN SenseCounts
1881 )
1882 {
1883 EFI_SCSI_SENSE_DATA *SensePtr;
1884 UINTN Index;
1885 BOOLEAN IsNoMedia;
1886
1887 IsNoMedia = FALSE;
1888 SensePtr = SenseData;
1889
1890 for (Index = 0; Index < SenseCounts; Index++) {
1891 //
1892 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
1893 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
1894 //
1895 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
1896 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
1897 IsNoMedia = TRUE;
1898 }
1899 SensePtr++;
1900 }
1901
1902 return IsNoMedia;
1903 }
1904
1905
1906 /**
1907 Parse sense key.
1908
1909 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1910 @param SenseCounts The number of sense key
1911
1912 @retval TRUE Error
1913 @retval FALSE NOT error
1914
1915 **/
1916 BOOLEAN
1917 ScsiDiskIsMediaError (
1918 IN EFI_SCSI_SENSE_DATA *SenseData,
1919 IN UINTN SenseCounts
1920 )
1921 {
1922 EFI_SCSI_SENSE_DATA *SensePtr;
1923 UINTN Index;
1924 BOOLEAN IsError;
1925
1926 IsError = FALSE;
1927 SensePtr = SenseData;
1928
1929 for (Index = 0; Index < SenseCounts; Index++) {
1930
1931 switch (SensePtr->Sense_Key) {
1932
1933 case EFI_SCSI_SK_MEDIUM_ERROR:
1934 //
1935 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
1936 //
1937 switch (SensePtr->Addnl_Sense_Code) {
1938
1939 //
1940 // fall through
1941 //
1942 case EFI_SCSI_ASC_MEDIA_ERR1:
1943
1944 //
1945 // fall through
1946 //
1947 case EFI_SCSI_ASC_MEDIA_ERR2:
1948
1949 //
1950 // fall through
1951 //
1952 case EFI_SCSI_ASC_MEDIA_ERR3:
1953 case EFI_SCSI_ASC_MEDIA_ERR4:
1954 IsError = TRUE;
1955 break;
1956
1957 default:
1958 break;
1959 }
1960
1961 break;
1962
1963 case EFI_SCSI_SK_NOT_READY:
1964 //
1965 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
1966 //
1967 switch (SensePtr->Addnl_Sense_Code) {
1968 //
1969 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
1970 //
1971 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
1972 IsError = TRUE;
1973 break;
1974
1975 default:
1976 break;
1977 }
1978 break;
1979
1980 default:
1981 break;
1982 }
1983
1984 SensePtr++;
1985 }
1986
1987 return IsError;
1988 }
1989
1990
1991 /**
1992 Check sense key to find if hardware error happens.
1993
1994 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1995 @param SenseCounts The number of sense key
1996
1997 @retval TRUE Hardware error exits.
1998 @retval FALSE NO error.
1999
2000 **/
2001 BOOLEAN
2002 ScsiDiskIsHardwareError (
2003 IN EFI_SCSI_SENSE_DATA *SenseData,
2004 IN UINTN SenseCounts
2005 )
2006 {
2007 EFI_SCSI_SENSE_DATA *SensePtr;
2008 UINTN Index;
2009 BOOLEAN IsError;
2010
2011 IsError = FALSE;
2012 SensePtr = SenseData;
2013
2014 for (Index = 0; Index < SenseCounts; Index++) {
2015
2016 //
2017 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2018 //
2019 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
2020 IsError = TRUE;
2021 }
2022
2023 SensePtr++;
2024 }
2025
2026 return IsError;
2027 }
2028
2029
2030 /**
2031 Check sense key to find if media has changed.
2032
2033 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2034 @param SenseCounts The number of sense key
2035
2036 @retval TRUE Media is changed.
2037 @retval FALSE Medit is NOT changed.
2038 **/
2039 BOOLEAN
2040 ScsiDiskIsMediaChange (
2041 IN EFI_SCSI_SENSE_DATA *SenseData,
2042 IN UINTN SenseCounts
2043 )
2044 {
2045 EFI_SCSI_SENSE_DATA *SensePtr;
2046 UINTN Index;
2047 BOOLEAN IsMediaChanged;
2048
2049 IsMediaChanged = FALSE;
2050 SensePtr = SenseData;
2051
2052 for (Index = 0; Index < SenseCounts; Index++) {
2053 //
2054 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2055 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2056 //
2057 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
2058 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
2059 IsMediaChanged = TRUE;
2060 }
2061
2062 SensePtr++;
2063 }
2064
2065 return IsMediaChanged;
2066 }
2067
2068 /**
2069 Check sense key to find if reset happens.
2070
2071 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2072 @param SenseCounts The number of sense key
2073
2074 @retval TRUE It is reset before.
2075 @retval FALSE It is NOT reset before.
2076
2077 **/
2078 BOOLEAN
2079 ScsiDiskIsResetBefore (
2080 IN EFI_SCSI_SENSE_DATA *SenseData,
2081 IN UINTN SenseCounts
2082 )
2083 {
2084 EFI_SCSI_SENSE_DATA *SensePtr;
2085 UINTN Index;
2086 BOOLEAN IsResetBefore;
2087
2088 IsResetBefore = FALSE;
2089 SensePtr = SenseData;
2090
2091 for (Index = 0; Index < SenseCounts; Index++) {
2092
2093 //
2094 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2095 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2096 //
2097 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
2098 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
2099 IsResetBefore = TRUE;
2100 }
2101
2102 SensePtr++;
2103 }
2104
2105 return IsResetBefore;
2106 }
2107
2108 /**
2109 Check sense key to find if the drive is ready.
2110
2111 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2112 @param SenseCounts The number of sense key
2113 @param RetryLater The flag means if need a retry
2114
2115 @retval TRUE Drive is ready.
2116 @retval FALSE Drive is NOT ready.
2117
2118 **/
2119 BOOLEAN
2120 ScsiDiskIsDriveReady (
2121 IN EFI_SCSI_SENSE_DATA *SenseData,
2122 IN UINTN SenseCounts,
2123 OUT BOOLEAN *RetryLater
2124 )
2125 {
2126 EFI_SCSI_SENSE_DATA *SensePtr;
2127 UINTN Index;
2128 BOOLEAN IsReady;
2129
2130 IsReady = TRUE;
2131 *RetryLater = FALSE;
2132 SensePtr = SenseData;
2133
2134 for (Index = 0; Index < SenseCounts; Index++) {
2135
2136 switch (SensePtr->Sense_Key) {
2137
2138 case EFI_SCSI_SK_NOT_READY:
2139 //
2140 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2141 //
2142 switch (SensePtr->Addnl_Sense_Code) {
2143 case EFI_SCSI_ASC_NOT_READY:
2144 //
2145 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2146 //
2147 switch (SensePtr->Addnl_Sense_Code_Qualifier) {
2148 case EFI_SCSI_ASCQ_IN_PROGRESS:
2149 //
2150 // Additional Sense Code Qualifier is
2151 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2152 //
2153 IsReady = FALSE;
2154 *RetryLater = TRUE;
2155 break;
2156
2157 default:
2158 IsReady = FALSE;
2159 *RetryLater = FALSE;
2160 break;
2161 }
2162 break;
2163
2164 default:
2165 break;
2166 }
2167 break;
2168
2169 default:
2170 break;
2171 }
2172
2173 SensePtr++;
2174 }
2175
2176 return IsReady;
2177 }
2178
2179 /**
2180 Check sense key to find if it has sense key.
2181
2182 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2183 @param SenseCounts - The number of sense key
2184
2185 @retval TRUE It has sense key.
2186 @retval FALSE It has NOT any sense key.
2187
2188 **/
2189 BOOLEAN
2190 ScsiDiskHaveSenseKey (
2191 IN EFI_SCSI_SENSE_DATA *SenseData,
2192 IN UINTN SenseCounts
2193 )
2194 {
2195 EFI_SCSI_SENSE_DATA *SensePtr;
2196 UINTN Index;
2197 BOOLEAN HaveSenseKey;
2198
2199 if (SenseCounts == 0) {
2200 HaveSenseKey = FALSE;
2201 } else {
2202 HaveSenseKey = TRUE;
2203 }
2204
2205 SensePtr = SenseData;
2206
2207 for (Index = 0; Index < SenseCounts; Index++) {
2208
2209 //
2210 // Sense Key is SK_NO_SENSE (0x0)
2211 //
2212 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
2213 (Index == 0)) {
2214 HaveSenseKey = FALSE;
2215 }
2216
2217 SensePtr++;
2218 }
2219
2220 return HaveSenseKey;
2221 }
2222
2223 /**
2224 Release resource about disk device.
2225
2226 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2227
2228 **/
2229 VOID
2230 ReleaseScsiDiskDeviceResources (
2231 IN SCSI_DISK_DEV *ScsiDiskDevice
2232 )
2233 {
2234 if (ScsiDiskDevice == NULL) {
2235 return ;
2236 }
2237
2238 if (ScsiDiskDevice->SenseData != NULL) {
2239 FreePool (ScsiDiskDevice->SenseData);
2240 ScsiDiskDevice->SenseData = NULL;
2241 }
2242
2243 if (ScsiDiskDevice->ControllerNameTable != NULL) {
2244 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
2245 ScsiDiskDevice->ControllerNameTable = NULL;
2246 }
2247
2248 FreePool (ScsiDiskDevice);
2249
2250 ScsiDiskDevice = NULL;
2251 }