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