]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
Change MaxBlock to HEX value to avoid GCC build failure.
[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 - 2010, Intel Corporation. All rights reserved.<BR>
5 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 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
19 ScsiDiskDriverBindingSupported,
20 ScsiDiskDriverBindingStart,
21 ScsiDiskDriverBindingStop,
22 0xa,
23 NULL,
24 NULL
25 };
26
27 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {
28 EFI_DISK_INFO_SCSI_INTERFACE_GUID,
29 ScsiDiskInfoInquiry,
30 ScsiDiskInfoIdentify,
31 ScsiDiskInfoSenseData,
32 ScsiDiskInfoWhichIde
33 };
34
35 /**
36 The user Entry Point for module ScsiDisk.
37
38 The user code starts with this function.
39
40 @param ImageHandle The firmware allocated handle for the EFI image.
41 @param SystemTable A pointer to the EFI System Table.
42
43 @retval EFI_SUCCESS The entry point is executed successfully.
44 @retval other Some error occurs when executing this entry point.
45
46 **/
47 EFI_STATUS
48 EFIAPI
49 InitializeScsiDisk(
50 IN EFI_HANDLE ImageHandle,
51 IN EFI_SYSTEM_TABLE *SystemTable
52 )
53 {
54 EFI_STATUS Status;
55
56 //
57 // Install driver model protocol(s).
58 //
59 Status = EfiLibInstallDriverBindingComponentName2 (
60 ImageHandle,
61 SystemTable,
62 &gScsiDiskDriverBinding,
63 ImageHandle,
64 &gScsiDiskComponentName,
65 &gScsiDiskComponentName2
66 );
67 ASSERT_EFI_ERROR (Status);
68
69
70 return Status;
71 }
72
73 /**
74 Test to see if this driver supports ControllerHandle.
75
76 This service is called by the EFI boot service ConnectController(). In order
77 to make drivers as small as possible, there are a few calling restrictions for
78 this service. ConnectController() must follow these calling restrictions.
79 If any other agent wishes to call Supported() it must also follow these
80 calling restrictions.
81
82 @param This Protocol instance pointer.
83 @param ControllerHandle Handle of device to test
84 @param RemainingDevicePath Optional parameter use to pick a specific child
85 device to start.
86
87 @retval EFI_SUCCESS This driver supports this device
88 @retval EFI_ALREADY_STARTED This driver is already running on this device
89 @retval other This driver does not support this device
90
91 **/
92 EFI_STATUS
93 EFIAPI
94 ScsiDiskDriverBindingSupported (
95 IN EFI_DRIVER_BINDING_PROTOCOL *This,
96 IN EFI_HANDLE Controller,
97 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
98 )
99 {
100 EFI_STATUS Status;
101 EFI_SCSI_IO_PROTOCOL *ScsiIo;
102 UINT8 DeviceType;
103
104 Status = gBS->OpenProtocol (
105 Controller,
106 &gEfiScsiIoProtocolGuid,
107 (VOID **) &ScsiIo,
108 This->DriverBindingHandle,
109 Controller,
110 EFI_OPEN_PROTOCOL_BY_DRIVER
111 );
112 if (EFI_ERROR (Status)) {
113 return Status;
114 }
115
116 Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
117 if (!EFI_ERROR (Status)) {
118 if ((DeviceType == EFI_SCSI_TYPE_DISK) || (DeviceType == EFI_SCSI_TYPE_CDROM)) {
119 Status = EFI_SUCCESS;
120 } else {
121 Status = EFI_UNSUPPORTED;
122 }
123 }
124
125 gBS->CloseProtocol (
126 Controller,
127 &gEfiScsiIoProtocolGuid,
128 This->DriverBindingHandle,
129 Controller
130 );
131 return Status;
132 }
133
134
135 /**
136 Start this driver on ControllerHandle.
137
138 This service is called by the EFI boot service ConnectController(). In order
139 to make drivers as small as possible, there are a few calling restrictions for
140 this service. ConnectController() must follow these calling restrictions. If
141 any other agent wishes to call Start() it must also follow these calling
142 restrictions.
143
144 @param This Protocol instance pointer.
145 @param ControllerHandle Handle of device to bind driver to
146 @param RemainingDevicePath Optional parameter use to pick a specific child
147 device to start.
148
149 @retval EFI_SUCCESS This driver is added to ControllerHandle
150 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
151 @retval other This driver does not support this device
152
153 **/
154 EFI_STATUS
155 EFIAPI
156 ScsiDiskDriverBindingStart (
157 IN EFI_DRIVER_BINDING_PROTOCOL *This,
158 IN EFI_HANDLE Controller,
159 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
160 )
161 {
162 EFI_STATUS Status;
163 EFI_SCSI_IO_PROTOCOL *ScsiIo;
164 SCSI_DISK_DEV *ScsiDiskDevice;
165 BOOLEAN Temp;
166 UINT8 Index;
167 UINT8 MaxRetry;
168 BOOLEAN NeedRetry;
169
170 ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));
171 if (ScsiDiskDevice == NULL) {
172 return EFI_OUT_OF_RESOURCES;
173 }
174
175 Status = gBS->OpenProtocol (
176 Controller,
177 &gEfiScsiIoProtocolGuid,
178 (VOID **) &ScsiIo,
179 This->DriverBindingHandle,
180 Controller,
181 EFI_OPEN_PROTOCOL_BY_DRIVER
182 );
183 if (EFI_ERROR (Status)) {
184 FreePool (ScsiDiskDevice);
185 return Status;
186 }
187
188 ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE;
189 ScsiDiskDevice->ScsiIo = ScsiIo;
190 ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia;
191 ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset;
192 ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;
193 ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;
194 ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;
195 ScsiDiskDevice->Handle = Controller;
196
197 ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
198 switch (ScsiDiskDevice->DeviceType) {
199 case EFI_SCSI_TYPE_DISK:
200 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
201 break;
202
203 case EFI_SCSI_TYPE_CDROM:
204 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
205 break;
206 }
207 //
208 // The Sense Data Array's initial size is 6
209 //
210 ScsiDiskDevice->SenseDataNumber = 6;
211 ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool (
212 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
213 );
214 if (ScsiDiskDevice->SenseData == NULL) {
215 gBS->CloseProtocol (
216 Controller,
217 &gEfiScsiIoProtocolGuid,
218 This->DriverBindingHandle,
219 Controller
220 );
221 FreePool (ScsiDiskDevice);
222 return EFI_OUT_OF_RESOURCES;
223 }
224
225 //
226 // Retrieve device information
227 //
228 MaxRetry = 2;
229 for (Index = 0; Index < MaxRetry; Index++) {
230 Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
231 if (!EFI_ERROR (Status)) {
232 break;
233 }
234
235 if (!NeedRetry) {
236 FreePool (ScsiDiskDevice->SenseData);
237 gBS->CloseProtocol (
238 Controller,
239 &gEfiScsiIoProtocolGuid,
240 This->DriverBindingHandle,
241 Controller
242 );
243 FreePool (ScsiDiskDevice);
244 return EFI_DEVICE_ERROR;
245 }
246 }
247 //
248 // The second parameter "TRUE" means must
249 // retrieve media capacity
250 //
251 Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp);
252 if (!EFI_ERROR (Status)) {
253 //
254 // Determine if Block IO should be produced on this controller handle
255 //
256 if (DetermineInstallBlockIo(Controller)) {
257 InitializeInstallDiskInfo(ScsiDiskDevice, Controller);
258 Status = gBS->InstallMultipleProtocolInterfaces (
259 &Controller,
260 &gEfiBlockIoProtocolGuid,
261 &ScsiDiskDevice->BlkIo,
262 &gEfiDiskInfoProtocolGuid,
263 &ScsiDiskDevice->DiskInfo,
264 NULL
265 );
266 if (!EFI_ERROR(Status)) {
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 return EFI_SUCCESS;
283 }
284 }
285 }
286
287 gBS->FreePool (ScsiDiskDevice->SenseData);
288 gBS->FreePool (ScsiDiskDevice);
289 gBS->CloseProtocol (
290 Controller,
291 &gEfiScsiIoProtocolGuid,
292 This->DriverBindingHandle,
293 Controller
294 );
295 return Status;
296
297 }
298
299
300 /**
301 Stop this driver on ControllerHandle.
302
303 This service is called by the EFI boot service DisconnectController().
304 In order to make drivers as small as possible, there are a few calling
305 restrictions for this service. DisconnectController() must follow these
306 calling restrictions. If any other agent wishes to call Stop() it must
307 also follow these calling restrictions.
308
309 @param This Protocol instance pointer.
310 @param ControllerHandle Handle of device to stop driver on
311 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
312 children is zero stop the entire bus driver.
313 @param ChildHandleBuffer List of Child Handles to Stop.
314
315 @retval EFI_SUCCESS This driver is removed ControllerHandle
316 @retval other This driver was not removed from this device
317
318 **/
319 EFI_STATUS
320 EFIAPI
321 ScsiDiskDriverBindingStop (
322 IN EFI_DRIVER_BINDING_PROTOCOL *This,
323 IN EFI_HANDLE Controller,
324 IN UINTN NumberOfChildren,
325 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
326 )
327 {
328 EFI_BLOCK_IO_PROTOCOL *BlkIo;
329 SCSI_DISK_DEV *ScsiDiskDevice;
330 EFI_STATUS Status;
331
332 Status = gBS->OpenProtocol (
333 Controller,
334 &gEfiBlockIoProtocolGuid,
335 (VOID **) &BlkIo,
336 This->DriverBindingHandle,
337 Controller,
338 EFI_OPEN_PROTOCOL_GET_PROTOCOL
339 );
340 if (EFI_ERROR (Status)) {
341 return Status;
342 }
343
344 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo);
345 Status = gBS->UninstallMultipleProtocolInterfaces (
346 Controller,
347 &gEfiBlockIoProtocolGuid,
348 &ScsiDiskDevice->BlkIo,
349 &gEfiDiskInfoProtocolGuid,
350 &ScsiDiskDevice->DiskInfo,
351 NULL
352 );
353 if (!EFI_ERROR (Status)) {
354 gBS->CloseProtocol (
355 Controller,
356 &gEfiScsiIoProtocolGuid,
357 This->DriverBindingHandle,
358 Controller
359 );
360
361 ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
362
363 return EFI_SUCCESS;
364 }
365 //
366 // errors met
367 //
368 return Status;
369 }
370
371 /**
372 Reset SCSI Disk.
373
374
375 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
376 @param ExtendedVerification The flag about if extend verificate
377
378 @retval EFI_SUCCESS The device was reset.
379 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
380 not be reset.
381 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
382
383 **/
384 EFI_STATUS
385 EFIAPI
386 ScsiDiskReset (
387 IN EFI_BLOCK_IO_PROTOCOL *This,
388 IN BOOLEAN ExtendedVerification
389 )
390 {
391 EFI_TPL OldTpl;
392 SCSI_DISK_DEV *ScsiDiskDevice;
393 EFI_STATUS Status;
394
395 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
396
397 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
398
399 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
400
401 if (!ExtendedVerification) {
402 goto Done;
403 }
404
405 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
406
407 Done:
408 gBS->RestoreTPL (OldTpl);
409 return Status;
410 }
411
412 /**
413 The function is to Read Block from SCSI Disk.
414
415 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
416 @param MediaId The Id of Media detected
417 @param Lba The logic block address
418 @param BufferSize The size of Buffer
419 @param Buffer The buffer to fill the read out data
420
421 @retval EFI_SUCCESS Successfully to read out block.
422 @retval EFI_DEVICE_ERROR Fail to detect media.
423 @retval EFI_NO_MEDIA Media is not present.
424 @retval EFI_MEDIA_CHANGED Media has changed.
425 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
426 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
427
428 **/
429 EFI_STATUS
430 EFIAPI
431 ScsiDiskReadBlocks (
432 IN EFI_BLOCK_IO_PROTOCOL *This,
433 IN UINT32 MediaId,
434 IN EFI_LBA Lba,
435 IN UINTN BufferSize,
436 OUT VOID *Buffer
437 )
438 {
439 SCSI_DISK_DEV *ScsiDiskDevice;
440 EFI_BLOCK_IO_MEDIA *Media;
441 EFI_STATUS Status;
442 UINTN BlockSize;
443 UINTN NumberOfBlocks;
444 BOOLEAN MediaChange;
445 EFI_TPL OldTpl;
446
447 MediaChange = FALSE;
448 if (Buffer == NULL) {
449 return EFI_INVALID_PARAMETER;
450 }
451
452 if (BufferSize == 0) {
453 return EFI_SUCCESS;
454 }
455
456 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
457
458 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
459
460 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
461
462 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
463 if (EFI_ERROR (Status)) {
464 Status = EFI_DEVICE_ERROR;
465 goto Done;
466 }
467
468 if (MediaChange) {
469 gBS->ReinstallProtocolInterface (
470 ScsiDiskDevice->Handle,
471 &gEfiBlockIoProtocolGuid,
472 &ScsiDiskDevice->BlkIo,
473 &ScsiDiskDevice->BlkIo
474 );
475 }
476 }
477 //
478 // Get the intrinsic block size
479 //
480 Media = ScsiDiskDevice->BlkIo.Media;
481 BlockSize = Media->BlockSize;
482
483 NumberOfBlocks = BufferSize / BlockSize;
484
485 if (!(Media->MediaPresent)) {
486 Status = EFI_NO_MEDIA;
487 goto Done;
488 }
489
490 if (MediaId != Media->MediaId) {
491 Status = EFI_MEDIA_CHANGED;
492 goto Done;
493 }
494
495 if (BufferSize % BlockSize != 0) {
496 Status = EFI_BAD_BUFFER_SIZE;
497 goto Done;
498 }
499
500 if (Lba > Media->LastBlock) {
501 Status = EFI_INVALID_PARAMETER;
502 goto Done;
503 }
504
505 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
506 Status = EFI_INVALID_PARAMETER;
507 goto Done;
508 }
509
510 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
511 Status = EFI_INVALID_PARAMETER;
512 goto Done;
513 }
514
515 //
516 // If all the parameters are valid, then perform read sectors command
517 // to transfer data from device to host.
518 //
519 Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
520
521 Done:
522 gBS->RestoreTPL (OldTpl);
523 return Status;
524 }
525
526 /**
527 The function is to Write Block to SCSI Disk.
528
529 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
530 @param MediaId The Id of Media detected
531 @param Lba The logic block address
532 @param BufferSize The size of Buffer
533 @param Buffer The buffer to fill the read out data
534
535 @retval EFI_SUCCESS Successfully to read out block.
536 @retval EFI_WRITE_PROTECTED The device can not be written to.
537 @retval EFI_DEVICE_ERROR Fail to detect media.
538 @retval EFI_NO_MEDIA Media is not present.
539 @retval EFI_MEDIA_CHNAGED Media has changed.
540 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
541 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
542
543 **/
544 EFI_STATUS
545 EFIAPI
546 ScsiDiskWriteBlocks (
547 IN EFI_BLOCK_IO_PROTOCOL *This,
548 IN UINT32 MediaId,
549 IN EFI_LBA Lba,
550 IN UINTN BufferSize,
551 IN VOID *Buffer
552 )
553 {
554 SCSI_DISK_DEV *ScsiDiskDevice;
555 EFI_BLOCK_IO_MEDIA *Media;
556 EFI_STATUS Status;
557 UINTN BlockSize;
558 UINTN NumberOfBlocks;
559 BOOLEAN MediaChange;
560 EFI_TPL OldTpl;
561
562 MediaChange = FALSE;
563 if (Buffer == NULL) {
564 return EFI_INVALID_PARAMETER;
565 }
566
567 if (BufferSize == 0) {
568 return EFI_SUCCESS;
569 }
570
571 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
572
573 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);
574
575 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
576
577 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
578 if (EFI_ERROR (Status)) {
579 Status = EFI_DEVICE_ERROR;
580 goto Done;
581 }
582
583 if (MediaChange) {
584 gBS->ReinstallProtocolInterface (
585 ScsiDiskDevice->Handle,
586 &gEfiBlockIoProtocolGuid,
587 &ScsiDiskDevice->BlkIo,
588 &ScsiDiskDevice->BlkIo
589 );
590 }
591 }
592 //
593 // Get the intrinsic block size
594 //
595 Media = ScsiDiskDevice->BlkIo.Media;
596 BlockSize = Media->BlockSize;
597
598 NumberOfBlocks = BufferSize / BlockSize;
599
600 if (!(Media->MediaPresent)) {
601 Status = EFI_NO_MEDIA;
602 goto Done;
603 }
604
605 if (MediaId != Media->MediaId) {
606 Status = EFI_MEDIA_CHANGED;
607 goto Done;
608 }
609
610 if (BufferSize % BlockSize != 0) {
611 Status = EFI_BAD_BUFFER_SIZE;
612 goto Done;
613 }
614
615 if (Lba > Media->LastBlock) {
616 Status = EFI_INVALID_PARAMETER;
617 goto Done;
618 }
619
620 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
621 Status = EFI_INVALID_PARAMETER;
622 goto Done;
623 }
624
625 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
626 Status = EFI_INVALID_PARAMETER;
627 goto Done;
628 }
629 //
630 // if all the parameters are valid, then perform read sectors command
631 // to transfer data from device to host.
632 //
633 Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
634
635 Done:
636 gBS->RestoreTPL (OldTpl);
637 return Status;
638 }
639
640 /**
641 Flush Block to Disk.
642
643 EFI_SUCCESS is returned directly.
644
645 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
646
647 @retval EFI_SUCCESS All outstanding data was written to the device
648
649 **/
650 EFI_STATUS
651 EFIAPI
652 ScsiDiskFlushBlocks (
653 IN EFI_BLOCK_IO_PROTOCOL *This
654 )
655 {
656 //
657 // return directly
658 //
659 return EFI_SUCCESS;
660 }
661
662
663 /**
664 Detect Device and read out capacity ,if error occurs, parse the sense key.
665
666 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
667 @param MustReadCapacity The flag about reading device capacity
668 @param MediaChange The pointer of flag indicates if media has changed
669
670 @retval EFI_DEVICE_ERROR Indicates that error occurs
671 @retval EFI_SUCCESS Successfully to detect media
672
673 **/
674 EFI_STATUS
675 ScsiDiskDetectMedia (
676 IN SCSI_DISK_DEV *ScsiDiskDevice,
677 IN BOOLEAN MustReadCapacity,
678 OUT BOOLEAN *MediaChange
679 )
680 {
681 EFI_STATUS Status;
682 EFI_STATUS ReadCapacityStatus;
683 EFI_SCSI_SENSE_DATA *SenseData;
684 UINTN NumberOfSenseKeys;
685 BOOLEAN NeedRetry;
686 BOOLEAN NeedReadCapacity;
687 UINT8 Index;
688 UINT8 MaxRetry;
689 EFI_BLOCK_IO_MEDIA OldMedia;
690 UINTN Action;
691
692 Status = EFI_SUCCESS;
693 ReadCapacityStatus = EFI_SUCCESS;
694 SenseData = NULL;
695 NumberOfSenseKeys = 0;
696 NeedReadCapacity = FALSE;
697 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
698 *MediaChange = FALSE;
699 MaxRetry = 3;
700
701 for (Index = 0; Index < MaxRetry; Index++) {
702 Status = ScsiDiskTestUnitReady (
703 ScsiDiskDevice,
704 &NeedRetry,
705 &SenseData,
706 &NumberOfSenseKeys
707 );
708 if (!EFI_ERROR (Status)) {
709 break;
710 }
711
712 if (!NeedRetry) {
713 return Status;
714 }
715 }
716
717 if ((Index == MaxRetry) && EFI_ERROR (Status)) {
718 return EFI_DEVICE_ERROR;
719 }
720
721 Status = DetectMediaParsingSenseKeys (
722 ScsiDiskDevice,
723 SenseData,
724 NumberOfSenseKeys,
725 &Action
726 );
727 if (EFI_ERROR (Status)) {
728 return Status;
729 }
730 //
731 // ACTION_NO_ACTION: need not read capacity
732 // other action code: need read capacity
733 //
734 if (Action == ACTION_NO_ACTION) {
735 NeedReadCapacity = FALSE;
736 } else {
737 NeedReadCapacity = TRUE;
738 }
739
740 //
741 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
742 // retrieve capacity via Read Capacity command
743 //
744 if (NeedReadCapacity || MustReadCapacity) {
745 //
746 // retrieve media information
747 //
748 MaxRetry = 3;
749 for (Index = 0; Index < MaxRetry; Index++) {
750
751 ReadCapacityStatus = ScsiDiskReadCapacity (
752 ScsiDiskDevice,
753 &NeedRetry,
754 &SenseData,
755 &NumberOfSenseKeys
756 );
757 if (EFI_ERROR (ReadCapacityStatus) && !NeedRetry) {
758 return EFI_DEVICE_ERROR;
759 }
760 //
761 // analyze sense key to action
762 //
763 Status = DetectMediaParsingSenseKeys (
764 ScsiDiskDevice,
765 SenseData,
766 NumberOfSenseKeys,
767 &Action
768 );
769 //
770 // if Status is error, it may indicate crisis error,
771 // so return without retry.
772 //
773 if (EFI_ERROR (Status)) {
774 return Status;
775 }
776
777 switch (Action) {
778 case ACTION_NO_ACTION:
779 //
780 // no retry
781 //
782 Index = MaxRetry;
783 break;
784
785 case ACTION_RETRY_COMMAND_LATER:
786 //
787 // retry the ReadCapacity later and continuously, until the condition
788 // no longer emerges.
789 // stall time is 100000us, or say 0.1 second.
790 //
791 gBS->Stall (100000);
792 Index = 0;
793 break;
794
795 default:
796 //
797 // other cases, just retry the command
798 //
799 break;
800 }
801 }
802
803 if ((Index == MaxRetry) && EFI_ERROR (ReadCapacityStatus)) {
804 return EFI_DEVICE_ERROR;
805 }
806 }
807
808 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
809 //
810 // Media change information got from the device
811 //
812 *MediaChange = TRUE;
813 }
814
815 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
816 *MediaChange = TRUE;
817 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
818 }
819
820 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
821 *MediaChange = TRUE;
822 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
823 }
824
825 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
826 *MediaChange = TRUE;
827 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
828 }
829
830 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
831 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
832 //
833 // when change from no media to media present, reset the MediaId to 1.
834 //
835 ScsiDiskDevice->BlkIo.Media->MediaId = 1;
836 } else {
837 //
838 // when no media, reset the MediaId to zero.
839 //
840 ScsiDiskDevice->BlkIo.Media->MediaId = 0;
841 }
842
843 *MediaChange = TRUE;
844 }
845
846 return EFI_SUCCESS;
847 }
848
849
850 /**
851 Send out Inquiry command to Device.
852
853 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
854 @param NeedRetry Indicates if needs try again when error happens
855
856 @retval EFI_DEVICE_ERROR Indicates that error occurs
857 @retval EFI_SUCCESS Successfully to detect media
858
859 **/
860 EFI_STATUS
861 ScsiDiskInquiryDevice (
862 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
863 OUT BOOLEAN *NeedRetry
864 )
865 {
866 UINT32 InquiryDataLength;
867 UINT8 SenseDataLength;
868 UINT8 HostAdapterStatus;
869 UINT8 TargetStatus;
870 EFI_SCSI_SENSE_DATA *SenseDataArray;
871 UINTN NumberOfSenseKeys;
872 EFI_STATUS Status;
873 UINT8 MaxRetry;
874 UINT8 Index;
875
876 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
877 SenseDataLength = 0;
878
879 Status = ScsiInquiryCommand (
880 ScsiDiskDevice->ScsiIo,
881 EFI_TIMER_PERIOD_SECONDS (1),
882 NULL,
883 &SenseDataLength,
884 &HostAdapterStatus,
885 &TargetStatus,
886 (VOID *) &(ScsiDiskDevice->InquiryData),
887 &InquiryDataLength,
888 FALSE
889 );
890 //
891 // no need to check HostAdapterStatus and TargetStatus
892 //
893 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
894 ParseInquiryData (ScsiDiskDevice);
895 return EFI_SUCCESS;
896
897 } else if (Status == EFI_NOT_READY) {
898 *NeedRetry = TRUE;
899 return EFI_DEVICE_ERROR;
900
901 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
902 *NeedRetry = FALSE;
903 return EFI_DEVICE_ERROR;
904 }
905 //
906 // go ahead to check HostAdapterStatus and TargetStatus
907 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
908 //
909
910 Status = CheckHostAdapterStatus (HostAdapterStatus);
911 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
912 *NeedRetry = TRUE;
913 return EFI_DEVICE_ERROR;
914 } else if (Status == EFI_DEVICE_ERROR) {
915 //
916 // reset the scsi channel
917 //
918 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
919 *NeedRetry = FALSE;
920 return EFI_DEVICE_ERROR;
921 }
922
923 Status = CheckTargetStatus (TargetStatus);
924 if (Status == EFI_NOT_READY) {
925 //
926 // reset the scsi device
927 //
928 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
929 *NeedRetry = TRUE;
930 return EFI_DEVICE_ERROR;
931
932 } else if (Status == EFI_DEVICE_ERROR) {
933 *NeedRetry = FALSE;
934 return EFI_DEVICE_ERROR;
935 }
936
937 //
938 // if goes here, meant ScsiInquiryCommand() failed.
939 // if ScsiDiskRequestSenseKeys() succeeds at last,
940 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
941 //
942 MaxRetry = 3;
943 for (Index = 0; Index < MaxRetry; Index++) {
944 Status = ScsiDiskRequestSenseKeys (
945 ScsiDiskDevice,
946 NeedRetry,
947 &SenseDataArray,
948 &NumberOfSenseKeys,
949 TRUE
950 );
951 if (!EFI_ERROR (Status)) {
952 *NeedRetry = TRUE;
953 return EFI_DEVICE_ERROR;
954 }
955
956 if (!*NeedRetry) {
957 return EFI_DEVICE_ERROR;
958 }
959 }
960 //
961 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
962 // set *NeedRetry = FALSE to avoid the outside caller try again.
963 //
964 *NeedRetry = FALSE;
965 return EFI_DEVICE_ERROR;
966 }
967
968 /**
969 To test device.
970
971 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
972 When Test Unit Ready command encounters any error caused by host adapter or
973 target, return error without retrieving Sense Keys.
974
975 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
976 @param NeedRetry The pointer of flag indicates try again
977 @param SenseDataArray The pointer of an array of sense data
978 @param NumberOfSenseKeys The pointer of the number of sense data array
979
980 @retval EFI_DEVICE_ERROR Indicates that error occurs
981 @retval EFI_SUCCESS Successfully to test unit
982
983 **/
984 EFI_STATUS
985 ScsiDiskTestUnitReady (
986 IN SCSI_DISK_DEV *ScsiDiskDevice,
987 OUT BOOLEAN *NeedRetry,
988 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
989 OUT UINTN *NumberOfSenseKeys
990 )
991 {
992 EFI_STATUS Status;
993 UINT8 SenseDataLength;
994 UINT8 HostAdapterStatus;
995 UINT8 TargetStatus;
996 UINT8 Index;
997 UINT8 MaxRetry;
998
999 SenseDataLength = 0;
1000 *NumberOfSenseKeys = 0;
1001
1002 //
1003 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1004 //
1005 Status = ScsiTestUnitReadyCommand (
1006 ScsiDiskDevice->ScsiIo,
1007 EFI_TIMER_PERIOD_SECONDS (1),
1008 NULL,
1009 &SenseDataLength,
1010 &HostAdapterStatus,
1011 &TargetStatus
1012 );
1013 //
1014 // no need to check HostAdapterStatus and TargetStatus
1015 //
1016 if (Status == EFI_NOT_READY) {
1017 *NeedRetry = TRUE;
1018 return EFI_DEVICE_ERROR;
1019
1020 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1021 *NeedRetry = FALSE;
1022 return EFI_DEVICE_ERROR;
1023 }
1024 //
1025 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1026 //
1027
1028 Status = CheckHostAdapterStatus (HostAdapterStatus);
1029 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1030 *NeedRetry = TRUE;
1031 return EFI_DEVICE_ERROR;
1032
1033 } else if (Status == EFI_DEVICE_ERROR) {
1034 //
1035 // reset the scsi channel
1036 //
1037 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1038 *NeedRetry = FALSE;
1039 return EFI_DEVICE_ERROR;
1040 }
1041
1042 Status = CheckTargetStatus (TargetStatus);
1043 if (Status == EFI_NOT_READY) {
1044 //
1045 // reset the scsi device
1046 //
1047 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1048 *NeedRetry = TRUE;
1049 return EFI_DEVICE_ERROR;
1050
1051 } else if (Status == EFI_DEVICE_ERROR) {
1052 *NeedRetry = FALSE;
1053 return EFI_DEVICE_ERROR;
1054 }
1055
1056 MaxRetry = 3;
1057 for (Index = 0; Index < MaxRetry; Index++) {
1058 Status = ScsiDiskRequestSenseKeys (
1059 ScsiDiskDevice,
1060 NeedRetry,
1061 SenseDataArray,
1062 NumberOfSenseKeys,
1063 FALSE
1064 );
1065 if (!EFI_ERROR (Status)) {
1066 return EFI_SUCCESS;
1067 }
1068
1069 if (!*NeedRetry) {
1070 return EFI_DEVICE_ERROR;
1071 }
1072 }
1073 //
1074 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1075 // set *NeedRetry = FALSE to avoid the outside caller try again.
1076 //
1077 *NeedRetry = FALSE;
1078 return EFI_DEVICE_ERROR;
1079 }
1080
1081 /**
1082 Parsing Sense Keys which got from request sense command.
1083
1084 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1085 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1086 @param NumberOfSenseKeys The number of sense key
1087 @param Action The pointer of action which indicates what is need to do next
1088
1089 @retval EFI_DEVICE_ERROR Indicates that error occurs
1090 @retval EFI_SUCCESS Successfully to complete the parsing
1091
1092 **/
1093 EFI_STATUS
1094 DetectMediaParsingSenseKeys (
1095 OUT SCSI_DISK_DEV *ScsiDiskDevice,
1096 IN EFI_SCSI_SENSE_DATA *SenseData,
1097 IN UINTN NumberOfSenseKeys,
1098 OUT UINTN *Action
1099 )
1100 {
1101 BOOLEAN RetryLater;
1102
1103 //
1104 // Default is to read capacity, unless..
1105 //
1106 *Action = ACTION_READ_CAPACITY;
1107
1108 if (NumberOfSenseKeys == 0) {
1109 *Action = ACTION_NO_ACTION;
1110 return EFI_SUCCESS;
1111 }
1112
1113 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
1114 //
1115 // No Sense Key returned from last submitted command
1116 //
1117 *Action = ACTION_NO_ACTION;
1118 return EFI_SUCCESS;
1119 }
1120
1121 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
1122 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
1123 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
1124 *Action = ACTION_NO_ACTION;
1125 return EFI_SUCCESS;
1126 }
1127
1128 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
1129 ScsiDiskDevice->BlkIo.Media->MediaId++;
1130 return EFI_SUCCESS;
1131 }
1132
1133 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
1134 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
1135 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
1136 return EFI_DEVICE_ERROR;
1137 }
1138
1139 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
1140 return EFI_DEVICE_ERROR;
1141 }
1142
1143 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
1144 if (RetryLater) {
1145 *Action = ACTION_RETRY_COMMAND_LATER;
1146 return EFI_SUCCESS;
1147 }
1148
1149 return EFI_DEVICE_ERROR;
1150 }
1151
1152 return EFI_SUCCESS;
1153 }
1154
1155
1156 /**
1157 Send read capacity command to device and get the device parameter.
1158
1159 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1160 @param NeedRetry The pointer of flag indicates if need a retry
1161 @param SenseDataArray The pointer of an array of sense data
1162 @param NumberOfSenseKeys The number of sense key
1163
1164 @retval EFI_DEVICE_ERROR Indicates that error occurs
1165 @retval EFI_SUCCESS Successfully to read capacity
1166
1167 **/
1168 EFI_STATUS
1169 ScsiDiskReadCapacity (
1170 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1171 OUT BOOLEAN *NeedRetry,
1172 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1173 OUT UINTN *NumberOfSenseKeys
1174 )
1175 {
1176 UINT8 HostAdapterStatus;
1177 UINT8 TargetStatus;
1178 EFI_STATUS CommandStatus;
1179 EFI_STATUS Status;
1180 UINT8 Index;
1181 UINT8 MaxRetry;
1182 UINT8 SenseDataLength;
1183 UINT8 ScsiVersion;
1184 UINT32 DataLength10;
1185 UINT32 DataLength16;
1186 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10;
1187 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16;
1188
1189
1190 SenseDataLength = 0;
1191 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
1192 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
1193 ZeroMem (&CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1194 ZeroMem (&CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1195
1196 *NumberOfSenseKeys = 0;
1197 *NeedRetry = FALSE;
1198 ScsiVersion = (UINT8)(ScsiDiskDevice->InquiryData.Version & 0x03);
1199
1200 if (ScsiVersion < SCSI_COMMAND_VERSION_3) {
1201 //
1202 // submit Read Capacity(10) Command. in this call,not request sense data
1203 //
1204 CommandStatus = ScsiReadCapacityCommand (
1205 ScsiDiskDevice->ScsiIo,
1206 EFI_TIMER_PERIOD_SECONDS(1),
1207 NULL,
1208 &SenseDataLength,
1209 &HostAdapterStatus,
1210 &TargetStatus,
1211 (VOID *) &CapacityData10,
1212 &DataLength10,
1213 FALSE
1214 );
1215 } else {
1216 //
1217 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1218 // and LowestAlignedLba
1219 //
1220 CommandStatus = ScsiReadCapacity16Command (
1221 ScsiDiskDevice->ScsiIo,
1222 EFI_TIMER_PERIOD_SECONDS (1),
1223 NULL,
1224 &SenseDataLength,
1225 &HostAdapterStatus,
1226 &TargetStatus,
1227 (VOID *) &CapacityData16,
1228 &DataLength16,
1229 FALSE
1230 );
1231 }
1232 //
1233 // no need to check HostAdapterStatus and TargetStatus
1234 //
1235 if (CommandStatus == EFI_SUCCESS) {
1236 GetMediaInfo (ScsiDiskDevice, &CapacityData10,&CapacityData16);
1237 return EFI_SUCCESS;
1238
1239 } else if (CommandStatus == EFI_NOT_READY) {
1240 *NeedRetry = TRUE;
1241 return EFI_DEVICE_ERROR;
1242
1243 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
1244 *NeedRetry = FALSE;
1245 return EFI_DEVICE_ERROR;
1246 }
1247 //
1248 // go ahead to check HostAdapterStatus and TargetStatus
1249 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1250 //
1251
1252 Status = CheckHostAdapterStatus (HostAdapterStatus);
1253 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1254 *NeedRetry = TRUE;
1255 return EFI_DEVICE_ERROR;
1256
1257 } else if (Status == EFI_DEVICE_ERROR) {
1258 //
1259 // reset the scsi channel
1260 //
1261 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1262 *NeedRetry = FALSE;
1263 return EFI_DEVICE_ERROR;
1264 }
1265
1266 Status = CheckTargetStatus (TargetStatus);
1267 if (Status == EFI_NOT_READY) {
1268 //
1269 // reset the scsi device
1270 //
1271 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1272 *NeedRetry = TRUE;
1273 return EFI_DEVICE_ERROR;
1274
1275 } else if (Status == EFI_DEVICE_ERROR) {
1276 *NeedRetry = FALSE;
1277 return EFI_DEVICE_ERROR;
1278 }
1279
1280 //
1281 // if goes here, meant ScsiReadCapacityCommand() failed.
1282 // if ScsiDiskRequestSenseKeys() succeeds at last,
1283 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1284 //
1285 MaxRetry = 3;
1286 for (Index = 0; Index < MaxRetry; Index++) {
1287
1288 Status = ScsiDiskRequestSenseKeys (
1289 ScsiDiskDevice,
1290 NeedRetry,
1291 SenseDataArray,
1292 NumberOfSenseKeys,
1293 TRUE
1294 );
1295 if (!EFI_ERROR (Status)) {
1296 *NeedRetry = TRUE;
1297 return EFI_DEVICE_ERROR;
1298 }
1299
1300 if (!*NeedRetry) {
1301 return EFI_DEVICE_ERROR;
1302 }
1303 }
1304 //
1305 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1306 // set *NeedRetry = FALSE to avoid the outside caller try again.
1307 //
1308 *NeedRetry = FALSE;
1309 return EFI_DEVICE_ERROR;
1310 }
1311
1312 /**
1313 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1314
1315 @param HostAdapterStatus Host Adapter status
1316
1317 @retval EFI_SUCCESS Host adapter is OK.
1318 @retval EFI_TIMEOUT Timeout.
1319 @retval EFI_NOT_READY Adapter NOT ready.
1320 @retval EFI_DEVICE_ERROR Adapter device error.
1321
1322 **/
1323 EFI_STATUS
1324 CheckHostAdapterStatus (
1325 IN UINT8 HostAdapterStatus
1326 )
1327 {
1328 switch (HostAdapterStatus) {
1329 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
1330 return EFI_SUCCESS;
1331
1332 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
1333 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
1334 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
1335 return EFI_TIMEOUT;
1336
1337 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
1338 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
1339 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
1340 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
1341 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
1342 return EFI_NOT_READY;
1343
1344 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
1345 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
1346 return EFI_DEVICE_ERROR;
1347
1348 default:
1349 return EFI_SUCCESS;
1350 }
1351 }
1352
1353
1354 /**
1355 Check the target status and re-interpret it in EFI_STATUS.
1356
1357 @param TargetStatus Target status
1358
1359 @retval EFI_NOT_READY Device is NOT ready.
1360 @retval EFI_DEVICE_ERROR
1361 @retval EFI_SUCCESS
1362
1363 **/
1364 EFI_STATUS
1365 CheckTargetStatus (
1366 IN UINT8 TargetStatus
1367 )
1368 {
1369 switch (TargetStatus) {
1370 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
1371 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
1372 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
1373 return EFI_SUCCESS;
1374
1375 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
1376 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
1377 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
1378 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
1379 return EFI_NOT_READY;
1380
1381 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
1382 return EFI_DEVICE_ERROR;
1383 break;
1384
1385 default:
1386 return EFI_SUCCESS;
1387 }
1388 }
1389
1390
1391 /**
1392 Retrieve all sense keys from the device.
1393
1394 When encountering error during the process, if retrieve sense keys before
1395 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1396 and NeedRetry set to FALSE; otherwize, return the proper return status.
1397
1398 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1399 @param NeedRetry The pointer of flag indicates if need a retry
1400 @param SenseDataArray The pointer of an array of sense data
1401 @param NumberOfSenseKeys The number of sense key
1402 @param AskResetIfError The flag indicates if need reset when error occurs
1403
1404 @retval EFI_DEVICE_ERROR Indicates that error occurs
1405 @retval EFI_SUCCESS Successfully to request sense key
1406
1407 **/
1408 EFI_STATUS
1409 ScsiDiskRequestSenseKeys (
1410 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1411 OUT BOOLEAN *NeedRetry,
1412 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1413 OUT UINTN *NumberOfSenseKeys,
1414 IN BOOLEAN AskResetIfError
1415 )
1416 {
1417 EFI_SCSI_SENSE_DATA *PtrSenseData;
1418 UINT8 SenseDataLength;
1419 BOOLEAN SenseReq;
1420 EFI_STATUS Status;
1421 EFI_STATUS FallStatus;
1422 UINT8 HostAdapterStatus;
1423 UINT8 TargetStatus;
1424
1425 FallStatus = EFI_SUCCESS;
1426 SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);
1427
1428 ZeroMem (
1429 ScsiDiskDevice->SenseData,
1430 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
1431 );
1432
1433 *NumberOfSenseKeys = 0;
1434 *SenseDataArray = ScsiDiskDevice->SenseData;
1435 PtrSenseData = ScsiDiskDevice->SenseData;
1436
1437 for (SenseReq = TRUE; SenseReq;) {
1438 Status = ScsiRequestSenseCommand (
1439 ScsiDiskDevice->ScsiIo,
1440 EFI_TIMER_PERIOD_SECONDS (2),
1441 PtrSenseData,
1442 &SenseDataLength,
1443 &HostAdapterStatus,
1444 &TargetStatus
1445 );
1446 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
1447 FallStatus = EFI_SUCCESS;
1448
1449 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1450 *NeedRetry = TRUE;
1451 FallStatus = EFI_DEVICE_ERROR;
1452
1453 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1454 *NeedRetry = FALSE;
1455 FallStatus = EFI_DEVICE_ERROR;
1456
1457 } else if (Status == EFI_DEVICE_ERROR) {
1458 if (AskResetIfError) {
1459 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1460 }
1461
1462 FallStatus = EFI_DEVICE_ERROR;
1463 }
1464
1465 if (EFI_ERROR (FallStatus)) {
1466 if (*NumberOfSenseKeys != 0) {
1467 *NeedRetry = FALSE;
1468 return EFI_SUCCESS;
1469 } else {
1470 return EFI_DEVICE_ERROR;
1471 }
1472 }
1473
1474 (*NumberOfSenseKeys) += 1;
1475
1476 //
1477 // no more sense key or number of sense keys exceeds predefined,
1478 // skip the loop.
1479 //
1480 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
1481 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
1482 SenseReq = FALSE;
1483 }
1484 PtrSenseData += 1;
1485 }
1486 return EFI_SUCCESS;
1487 }
1488
1489
1490 /**
1491 Get information from media read capacity command.
1492
1493 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1494 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1495 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1496
1497 **/
1498 VOID
1499 GetMediaInfo (
1500 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1501 IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,
1502 IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16
1503 )
1504 {
1505 UINT8 ScsiVersion;
1506 UINT8 *Ptr;
1507
1508 ScsiVersion = (UINT8)(ScsiDiskDevice->InquiryData.Version & 0x03);
1509 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;
1510 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;
1511
1512
1513 if (ScsiVersion < SCSI_COMMAND_VERSION_3) {
1514 ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity10->LastLba3 << 24) |
1515 (Capacity10->LastLba2 << 16) |
1516 (Capacity10->LastLba1 << 8) |
1517 Capacity10->LastLba0;
1518
1519 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
1520 (Capacity10->BlockSize2 << 16) |
1521 (Capacity10->BlockSize1 << 8) |
1522 Capacity10->BlockSize0;
1523 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
1524 } else {
1525
1526 Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;
1527 *Ptr++ = Capacity16->LastLba0;
1528 *Ptr++ = Capacity16->LastLba1;
1529 *Ptr++ = Capacity16->LastLba2;
1530 *Ptr++ = Capacity16->LastLba3;
1531 *Ptr++ = Capacity16->LastLba4;
1532 *Ptr++ = Capacity16->LastLba5;
1533 *Ptr++ = Capacity16->LastLba6;
1534 *Ptr = Capacity16->LastLba7;
1535
1536 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
1537 (Capacity16->BlockSize2 << 16) |
1538 (Capacity16->BlockSize1 << 8) |
1539 Capacity16->BlockSize0;
1540
1541 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8)|(Capacity16->LowestAlignLogic1);
1542 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = Capacity16->LogicPerPhysical;
1543 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;
1544 }
1545
1546
1547 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
1548
1549 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
1550 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
1551 }
1552
1553 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_CDROM) {
1554 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
1555 }
1556 }
1557
1558 /**
1559 Parse Inquiry data.
1560
1561 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1562
1563 **/
1564 VOID
1565 ParseInquiryData (
1566 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
1567 )
1568 {
1569 ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
1570 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
1571 }
1572
1573 /**
1574 Read sector from SCSI Disk.
1575
1576 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1577 @param Buffer The buffer to fill in the read out data
1578 @param Lba Logic block address
1579 @param NumberOfBlocks The number of blocks to read
1580
1581 @retval EFI_DEVICE_ERROR Indicates a device error.
1582 @retval EFI_SUCCESS Operation is successful.
1583
1584 **/
1585 EFI_STATUS
1586 ScsiDiskReadSectors (
1587 IN SCSI_DISK_DEV *ScsiDiskDevice,
1588 OUT VOID *Buffer,
1589 IN EFI_LBA Lba,
1590 IN UINTN NumberOfBlocks
1591 )
1592 {
1593 UINTN BlocksRemaining;
1594 UINT8 *PtrBuffer;
1595 UINT32 BlockSize;
1596 UINT32 ByteCount;
1597 UINT32 MaxBlock;
1598 UINT32 SectorCount;
1599 UINT64 Timeout;
1600 EFI_STATUS Status;
1601 UINT8 Index;
1602 UINT8 MaxRetry;
1603 BOOLEAN NeedRetry;
1604 EFI_SCSI_SENSE_DATA *SenseData;
1605 UINTN NumberOfSenseKeys;
1606 UINT8 ScsiVersion;
1607
1608 SenseData = NULL;
1609 NumberOfSenseKeys = 0;
1610
1611 Status = EFI_SUCCESS;
1612
1613 BlocksRemaining = NumberOfBlocks;
1614 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
1615 ScsiVersion = (UINT8)(ScsiDiskDevice->InquiryData.Version & 0x03);
1616
1617 //
1618 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1619 //
1620 if (ScsiVersion < SCSI_COMMAND_VERSION_3) {
1621 MaxBlock = 0xFFFF;
1622 } else {
1623 MaxBlock = 0xFFFFFFFF;
1624 }
1625
1626 PtrBuffer = Buffer;
1627
1628 while (BlocksRemaining > 0) {
1629
1630 if (BlocksRemaining <= MaxBlock) {
1631 if (ScsiVersion < SCSI_COMMAND_VERSION_3) {
1632 SectorCount = (UINT16) BlocksRemaining;
1633 } else {
1634 SectorCount = (UINT32) BlocksRemaining;
1635 }
1636 } else {
1637 SectorCount = MaxBlock;
1638 }
1639
1640 ByteCount = SectorCount * BlockSize;
1641 Timeout = EFI_TIMER_PERIOD_SECONDS (2);
1642
1643 MaxRetry = 2;
1644 for (Index = 0; Index < MaxRetry; Index++) {
1645 if (ScsiVersion >= SCSI_COMMAND_VERSION_3) {
1646 Status = ScsiDiskRead16 (
1647 ScsiDiskDevice,
1648 &NeedRetry,
1649 &SenseData,
1650 &NumberOfSenseKeys,
1651 Timeout,
1652 PtrBuffer,
1653 &ByteCount,
1654 Lba,
1655 SectorCount
1656 );
1657 } else {
1658 Status = ScsiDiskRead10 (
1659 ScsiDiskDevice,
1660 &NeedRetry,
1661 &SenseData,
1662 &NumberOfSenseKeys,
1663 Timeout,
1664 PtrBuffer,
1665 &ByteCount,
1666 (UINT32) Lba,
1667 SectorCount
1668 );
1669 }
1670 if (!EFI_ERROR (Status)) {
1671 break;
1672 }
1673
1674 if (!NeedRetry) {
1675 return EFI_DEVICE_ERROR;
1676 }
1677
1678 }
1679
1680 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
1681 return EFI_DEVICE_ERROR;
1682 }
1683
1684 //
1685 // actual transferred sectors
1686 //
1687 SectorCount = ByteCount / BlockSize;
1688
1689 Lba += SectorCount;
1690 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
1691 BlocksRemaining -= SectorCount;
1692 }
1693
1694 return EFI_SUCCESS;
1695 }
1696
1697 /**
1698 Write sector to SCSI Disk.
1699
1700 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1701 @param Buffer The buffer of data to be written into SCSI Disk
1702 @param Lba Logic block address
1703 @param NumberOfBlocks The number of blocks to read
1704
1705 @retval EFI_DEVICE_ERROR Indicates a device error.
1706 @retval EFI_SUCCESS Operation is successful.
1707
1708 **/
1709 EFI_STATUS
1710 ScsiDiskWriteSectors (
1711 IN SCSI_DISK_DEV *ScsiDiskDevice,
1712 IN VOID *Buffer,
1713 IN EFI_LBA Lba,
1714 IN UINTN NumberOfBlocks
1715 )
1716 {
1717 UINTN BlocksRemaining;
1718 UINT8 *PtrBuffer;
1719 UINT32 BlockSize;
1720 UINT32 ByteCount;
1721 UINT32 MaxBlock;
1722 UINT32 SectorCount;
1723 UINT64 Timeout;
1724 EFI_STATUS Status;
1725 UINT8 Index;
1726 UINT8 MaxRetry;
1727 BOOLEAN NeedRetry;
1728 EFI_SCSI_SENSE_DATA *SenseData;
1729 UINTN NumberOfSenseKeys;
1730 UINT8 ScsiVersion;
1731
1732 SenseData = NULL;
1733 NumberOfSenseKeys = 0;
1734
1735 Status = EFI_SUCCESS;
1736
1737 BlocksRemaining = NumberOfBlocks;
1738 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
1739 ScsiVersion = (UINT8)(ScsiDiskDevice->InquiryData.Version & 0x03);
1740
1741 //
1742 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1743 //
1744 if (ScsiVersion < SCSI_COMMAND_VERSION_3) {
1745 MaxBlock = 0xFFFF;
1746 } else {
1747 MaxBlock = 0xFFFFFFFF;
1748 }
1749
1750 PtrBuffer = Buffer;
1751
1752 while (BlocksRemaining > 0) {
1753
1754 if (BlocksRemaining <= MaxBlock) {
1755 if (ScsiVersion < SCSI_COMMAND_VERSION_3) {
1756 SectorCount = (UINT16) BlocksRemaining;
1757 } else {
1758 SectorCount = (UINT32) BlocksRemaining;
1759 }
1760 } else {
1761 SectorCount = MaxBlock;
1762 }
1763
1764 ByteCount = SectorCount * BlockSize;
1765 Timeout = EFI_TIMER_PERIOD_SECONDS (2);
1766 MaxRetry = 2;
1767 for (Index = 0; Index < MaxRetry; Index++) {
1768 if (ScsiVersion >= SCSI_COMMAND_VERSION_3) {
1769 Status = ScsiDiskWrite16 (
1770 ScsiDiskDevice,
1771 &NeedRetry,
1772 &SenseData,
1773 &NumberOfSenseKeys,
1774 Timeout,
1775 PtrBuffer,
1776 &ByteCount,
1777 Lba,
1778 SectorCount
1779 );
1780 } else {
1781 Status = ScsiDiskWrite10 (
1782 ScsiDiskDevice,
1783 &NeedRetry,
1784 &SenseData,
1785 &NumberOfSenseKeys,
1786 Timeout,
1787 PtrBuffer,
1788 &ByteCount,
1789 (UINT32) Lba,
1790 SectorCount
1791 );
1792 }
1793 if (!EFI_ERROR (Status)) {
1794 break;
1795 }
1796
1797 if (!NeedRetry) {
1798 return EFI_DEVICE_ERROR;
1799 }
1800 }
1801
1802 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
1803 return EFI_DEVICE_ERROR;
1804 }
1805 //
1806 // actual transferred sectors
1807 //
1808 SectorCount = ByteCount / BlockSize;
1809
1810 Lba += SectorCount;
1811 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
1812 BlocksRemaining -= SectorCount;
1813 }
1814
1815 return EFI_SUCCESS;
1816 }
1817
1818
1819 /**
1820 Submit Read(10) command.
1821
1822 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1823 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1824 @param SenseDataArray NOT used yet in this function
1825 @param NumberOfSenseKeys The number of sense key
1826 @param Timeout The time to complete the command
1827 @param DataBuffer The buffer to fill with the read out data
1828 @param DataLength The length of buffer
1829 @param StartLba The start logic block address
1830 @param SectorSize The size of sector
1831
1832 @return EFI_STATUS is returned by calling ScsiRead10Command().
1833 **/
1834 EFI_STATUS
1835 ScsiDiskRead10 (
1836 IN SCSI_DISK_DEV *ScsiDiskDevice,
1837 OUT BOOLEAN *NeedRetry,
1838 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
1839 OUT UINTN *NumberOfSenseKeys,
1840 IN UINT64 Timeout,
1841 OUT UINT8 *DataBuffer,
1842 IN OUT UINT32 *DataLength,
1843 IN UINT32 StartLba,
1844 IN UINT32 SectorSize
1845 )
1846 {
1847 UINT8 SenseDataLength;
1848 EFI_STATUS Status;
1849 UINT8 HostAdapterStatus;
1850 UINT8 TargetStatus;
1851
1852 *NeedRetry = FALSE;
1853 *NumberOfSenseKeys = 0;
1854 SenseDataLength = 0;
1855 Status = ScsiRead10Command (
1856 ScsiDiskDevice->ScsiIo,
1857 Timeout,
1858 NULL,
1859 &SenseDataLength,
1860 &HostAdapterStatus,
1861 &TargetStatus,
1862 DataBuffer,
1863 DataLength,
1864 StartLba,
1865 SectorSize
1866 );
1867 return Status;
1868 }
1869
1870
1871 /**
1872 Submit Write(10) Command.
1873
1874 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1875 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1876 @param SenseDataArray NOT used yet in this function
1877 @param NumberOfSenseKeys The number of sense key
1878 @param Timeout The time to complete the command
1879 @param DataBuffer The buffer to fill with the read out data
1880 @param DataLength The length of buffer
1881 @param StartLba The start logic block address
1882 @param SectorSize The size of sector
1883
1884 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1885
1886 **/
1887 EFI_STATUS
1888 ScsiDiskWrite10 (
1889 IN SCSI_DISK_DEV *ScsiDiskDevice,
1890 OUT BOOLEAN *NeedRetry,
1891 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
1892 OUT UINTN *NumberOfSenseKeys,
1893 IN UINT64 Timeout,
1894 IN UINT8 *DataBuffer,
1895 IN OUT UINT32 *DataLength,
1896 IN UINT32 StartLba,
1897 IN UINT32 SectorSize
1898 )
1899 {
1900 EFI_STATUS Status;
1901 UINT8 SenseDataLength;
1902 UINT8 HostAdapterStatus;
1903 UINT8 TargetStatus;
1904
1905 *NeedRetry = FALSE;
1906 *NumberOfSenseKeys = 0;
1907 SenseDataLength = 0;
1908 Status = ScsiWrite10Command (
1909 ScsiDiskDevice->ScsiIo,
1910 Timeout,
1911 NULL,
1912 &SenseDataLength,
1913 &HostAdapterStatus,
1914 &TargetStatus,
1915 DataBuffer,
1916 DataLength,
1917 StartLba,
1918 SectorSize
1919 );
1920 return Status;
1921 }
1922
1923
1924 /**
1925 Submit Read(16) command.
1926
1927 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1928 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1929 @param SenseDataArray NOT used yet in this function
1930 @param NumberOfSenseKeys The number of sense key
1931 @param Timeout The time to complete the command
1932 @param DataBuffer The buffer to fill with the read out data
1933 @param DataLength The length of buffer
1934 @param StartLba The start logic block address
1935 @param SectorSize The size of sector
1936
1937 @return EFI_STATUS is returned by calling ScsiRead10Command().
1938 **/
1939 EFI_STATUS
1940 ScsiDiskRead16 (
1941 IN SCSI_DISK_DEV *ScsiDiskDevice,
1942 OUT BOOLEAN *NeedRetry,
1943 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
1944 OUT UINTN *NumberOfSenseKeys,
1945 IN UINT64 Timeout,
1946 OUT UINT8 *DataBuffer,
1947 IN OUT UINT32 *DataLength,
1948 IN UINT64 StartLba,
1949 IN UINT32 SectorSize
1950 )
1951 {
1952 UINT8 SenseDataLength;
1953 EFI_STATUS Status;
1954 UINT8 HostAdapterStatus;
1955 UINT8 TargetStatus;
1956
1957 *NeedRetry = FALSE;
1958 *NumberOfSenseKeys = 0;
1959 SenseDataLength = 0;
1960 Status = ScsiRead16Command (
1961 ScsiDiskDevice->ScsiIo,
1962 Timeout,
1963 NULL,
1964 &SenseDataLength,
1965 &HostAdapterStatus,
1966 &TargetStatus,
1967 DataBuffer,
1968 DataLength,
1969 StartLba,
1970 SectorSize
1971 );
1972 return Status;
1973 }
1974
1975
1976 /**
1977 Submit Write(16) Command.
1978
1979 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1980 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1981 @param SenseDataArray NOT used yet in this function
1982 @param NumberOfSenseKeys The number of sense key
1983 @param Timeout The time to complete the command
1984 @param DataBuffer The buffer to fill with the read out data
1985 @param DataLength The length of buffer
1986 @param StartLba The start logic block address
1987 @param SectorSize The size of sector
1988
1989 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1990
1991 **/
1992 EFI_STATUS
1993 ScsiDiskWrite16 (
1994 IN SCSI_DISK_DEV *ScsiDiskDevice,
1995 OUT BOOLEAN *NeedRetry,
1996 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
1997 OUT UINTN *NumberOfSenseKeys,
1998 IN UINT64 Timeout,
1999 IN UINT8 *DataBuffer,
2000 IN OUT UINT32 *DataLength,
2001 IN UINT64 StartLba,
2002 IN UINT32 SectorSize
2003 )
2004 {
2005 EFI_STATUS Status;
2006 UINT8 SenseDataLength;
2007 UINT8 HostAdapterStatus;
2008 UINT8 TargetStatus;
2009
2010 *NeedRetry = FALSE;
2011 *NumberOfSenseKeys = 0;
2012 SenseDataLength = 0;
2013 Status = ScsiWrite16Command (
2014 ScsiDiskDevice->ScsiIo,
2015 Timeout,
2016 NULL,
2017 &SenseDataLength,
2018 &HostAdapterStatus,
2019 &TargetStatus,
2020 DataBuffer,
2021 DataLength,
2022 StartLba,
2023 SectorSize
2024 );
2025 return Status;
2026 }
2027
2028
2029 /**
2030 Check sense key to find if media presents.
2031
2032 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2033 @param SenseCounts The number of sense key
2034
2035 @retval TRUE NOT any media
2036 @retval FALSE Media presents
2037 **/
2038 BOOLEAN
2039 ScsiDiskIsNoMedia (
2040 IN EFI_SCSI_SENSE_DATA *SenseData,
2041 IN UINTN SenseCounts
2042 )
2043 {
2044 EFI_SCSI_SENSE_DATA *SensePtr;
2045 UINTN Index;
2046 BOOLEAN IsNoMedia;
2047
2048 IsNoMedia = FALSE;
2049 SensePtr = SenseData;
2050
2051 for (Index = 0; Index < SenseCounts; Index++) {
2052 //
2053 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2054 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2055 //
2056 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
2057 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
2058 IsNoMedia = TRUE;
2059 }
2060 SensePtr++;
2061 }
2062
2063 return IsNoMedia;
2064 }
2065
2066
2067 /**
2068 Parse sense key.
2069
2070 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2071 @param SenseCounts The number of sense key
2072
2073 @retval TRUE Error
2074 @retval FALSE NOT error
2075
2076 **/
2077 BOOLEAN
2078 ScsiDiskIsMediaError (
2079 IN EFI_SCSI_SENSE_DATA *SenseData,
2080 IN UINTN SenseCounts
2081 )
2082 {
2083 EFI_SCSI_SENSE_DATA *SensePtr;
2084 UINTN Index;
2085 BOOLEAN IsError;
2086
2087 IsError = FALSE;
2088 SensePtr = SenseData;
2089
2090 for (Index = 0; Index < SenseCounts; Index++) {
2091
2092 switch (SensePtr->Sense_Key) {
2093
2094 case EFI_SCSI_SK_MEDIUM_ERROR:
2095 //
2096 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2097 //
2098 switch (SensePtr->Addnl_Sense_Code) {
2099
2100 //
2101 // fall through
2102 //
2103 case EFI_SCSI_ASC_MEDIA_ERR1:
2104
2105 //
2106 // fall through
2107 //
2108 case EFI_SCSI_ASC_MEDIA_ERR2:
2109
2110 //
2111 // fall through
2112 //
2113 case EFI_SCSI_ASC_MEDIA_ERR3:
2114 case EFI_SCSI_ASC_MEDIA_ERR4:
2115 IsError = TRUE;
2116 break;
2117
2118 default:
2119 break;
2120 }
2121
2122 break;
2123
2124 case EFI_SCSI_SK_NOT_READY:
2125 //
2126 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2127 //
2128 switch (SensePtr->Addnl_Sense_Code) {
2129 //
2130 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2131 //
2132 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
2133 IsError = TRUE;
2134 break;
2135
2136 default:
2137 break;
2138 }
2139 break;
2140
2141 default:
2142 break;
2143 }
2144
2145 SensePtr++;
2146 }
2147
2148 return IsError;
2149 }
2150
2151
2152 /**
2153 Check sense key to find if hardware error happens.
2154
2155 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2156 @param SenseCounts The number of sense key
2157
2158 @retval TRUE Hardware error exits.
2159 @retval FALSE NO error.
2160
2161 **/
2162 BOOLEAN
2163 ScsiDiskIsHardwareError (
2164 IN EFI_SCSI_SENSE_DATA *SenseData,
2165 IN UINTN SenseCounts
2166 )
2167 {
2168 EFI_SCSI_SENSE_DATA *SensePtr;
2169 UINTN Index;
2170 BOOLEAN IsError;
2171
2172 IsError = FALSE;
2173 SensePtr = SenseData;
2174
2175 for (Index = 0; Index < SenseCounts; Index++) {
2176
2177 //
2178 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2179 //
2180 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
2181 IsError = TRUE;
2182 }
2183
2184 SensePtr++;
2185 }
2186
2187 return IsError;
2188 }
2189
2190
2191 /**
2192 Check sense key to find if media has changed.
2193
2194 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2195 @param SenseCounts The number of sense key
2196
2197 @retval TRUE Media is changed.
2198 @retval FALSE Media is NOT changed.
2199 **/
2200 BOOLEAN
2201 ScsiDiskIsMediaChange (
2202 IN EFI_SCSI_SENSE_DATA *SenseData,
2203 IN UINTN SenseCounts
2204 )
2205 {
2206 EFI_SCSI_SENSE_DATA *SensePtr;
2207 UINTN Index;
2208 BOOLEAN IsMediaChanged;
2209
2210 IsMediaChanged = FALSE;
2211 SensePtr = SenseData;
2212
2213 for (Index = 0; Index < SenseCounts; Index++) {
2214 //
2215 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2216 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2217 //
2218 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
2219 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
2220 IsMediaChanged = TRUE;
2221 }
2222
2223 SensePtr++;
2224 }
2225
2226 return IsMediaChanged;
2227 }
2228
2229 /**
2230 Check sense key to find if reset happens.
2231
2232 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2233 @param SenseCounts The number of sense key
2234
2235 @retval TRUE It is reset before.
2236 @retval FALSE It is NOT reset before.
2237
2238 **/
2239 BOOLEAN
2240 ScsiDiskIsResetBefore (
2241 IN EFI_SCSI_SENSE_DATA *SenseData,
2242 IN UINTN SenseCounts
2243 )
2244 {
2245 EFI_SCSI_SENSE_DATA *SensePtr;
2246 UINTN Index;
2247 BOOLEAN IsResetBefore;
2248
2249 IsResetBefore = FALSE;
2250 SensePtr = SenseData;
2251
2252 for (Index = 0; Index < SenseCounts; Index++) {
2253
2254 //
2255 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2256 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2257 //
2258 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
2259 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
2260 IsResetBefore = TRUE;
2261 }
2262
2263 SensePtr++;
2264 }
2265
2266 return IsResetBefore;
2267 }
2268
2269 /**
2270 Check sense key to find if the drive is ready.
2271
2272 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2273 @param SenseCounts The number of sense key
2274 @param RetryLater The flag means if need a retry
2275
2276 @retval TRUE Drive is ready.
2277 @retval FALSE Drive is NOT ready.
2278
2279 **/
2280 BOOLEAN
2281 ScsiDiskIsDriveReady (
2282 IN EFI_SCSI_SENSE_DATA *SenseData,
2283 IN UINTN SenseCounts,
2284 OUT BOOLEAN *RetryLater
2285 )
2286 {
2287 EFI_SCSI_SENSE_DATA *SensePtr;
2288 UINTN Index;
2289 BOOLEAN IsReady;
2290
2291 IsReady = TRUE;
2292 *RetryLater = FALSE;
2293 SensePtr = SenseData;
2294
2295 for (Index = 0; Index < SenseCounts; Index++) {
2296
2297 switch (SensePtr->Sense_Key) {
2298
2299 case EFI_SCSI_SK_NOT_READY:
2300 //
2301 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2302 //
2303 switch (SensePtr->Addnl_Sense_Code) {
2304 case EFI_SCSI_ASC_NOT_READY:
2305 //
2306 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2307 //
2308 switch (SensePtr->Addnl_Sense_Code_Qualifier) {
2309 case EFI_SCSI_ASCQ_IN_PROGRESS:
2310 //
2311 // Additional Sense Code Qualifier is
2312 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2313 //
2314 IsReady = FALSE;
2315 *RetryLater = TRUE;
2316 break;
2317
2318 default:
2319 IsReady = FALSE;
2320 *RetryLater = FALSE;
2321 break;
2322 }
2323 break;
2324
2325 default:
2326 break;
2327 }
2328 break;
2329
2330 default:
2331 break;
2332 }
2333
2334 SensePtr++;
2335 }
2336
2337 return IsReady;
2338 }
2339
2340 /**
2341 Check sense key to find if it has sense key.
2342
2343 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2344 @param SenseCounts - The number of sense key
2345
2346 @retval TRUE It has sense key.
2347 @retval FALSE It has NOT any sense key.
2348
2349 **/
2350 BOOLEAN
2351 ScsiDiskHaveSenseKey (
2352 IN EFI_SCSI_SENSE_DATA *SenseData,
2353 IN UINTN SenseCounts
2354 )
2355 {
2356 EFI_SCSI_SENSE_DATA *SensePtr;
2357 UINTN Index;
2358 BOOLEAN HaveSenseKey;
2359
2360 if (SenseCounts == 0) {
2361 HaveSenseKey = FALSE;
2362 } else {
2363 HaveSenseKey = TRUE;
2364 }
2365
2366 SensePtr = SenseData;
2367
2368 for (Index = 0; Index < SenseCounts; Index++) {
2369
2370 //
2371 // Sense Key is SK_NO_SENSE (0x0)
2372 //
2373 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
2374 (Index == 0)) {
2375 HaveSenseKey = FALSE;
2376 }
2377
2378 SensePtr++;
2379 }
2380
2381 return HaveSenseKey;
2382 }
2383
2384 /**
2385 Release resource about disk device.
2386
2387 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2388
2389 **/
2390 VOID
2391 ReleaseScsiDiskDeviceResources (
2392 IN SCSI_DISK_DEV *ScsiDiskDevice
2393 )
2394 {
2395 if (ScsiDiskDevice == NULL) {
2396 return ;
2397 }
2398
2399 if (ScsiDiskDevice->SenseData != NULL) {
2400 FreePool (ScsiDiskDevice->SenseData);
2401 ScsiDiskDevice->SenseData = NULL;
2402 }
2403
2404 if (ScsiDiskDevice->ControllerNameTable != NULL) {
2405 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
2406 ScsiDiskDevice->ControllerNameTable = NULL;
2407 }
2408
2409 FreePool (ScsiDiskDevice);
2410
2411 ScsiDiskDevice = NULL;
2412 }
2413
2414 /**
2415 Determine if Block Io should be produced.
2416
2417
2418 @param ChildHandle Child Handle to retrieve Parent information.
2419
2420 @retval TRUE Should produce Block Io.
2421 @retval FALSE Should not produce Block Io.
2422
2423 **/
2424 BOOLEAN
2425 DetermineInstallBlockIo (
2426 IN EFI_HANDLE ChildHandle
2427 )
2428 {
2429 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
2430 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
2431
2432 //
2433 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2434 // check its attribute, logic or physical.
2435 //
2436 ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
2437 if (ExtScsiPassThru != NULL) {
2438 if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
2439 return TRUE;
2440 }
2441 }
2442
2443 //
2444 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2445 // check its attribute, logic or physical.
2446 //
2447 ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
2448 if (ScsiPassThru != NULL) {
2449 if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
2450 return TRUE;
2451 }
2452 }
2453
2454 return FALSE;
2455 }
2456
2457 /**
2458 Search protocol database and check to see if the protocol
2459 specified by ProtocolGuid is present on a ControllerHandle and opened by
2460 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2461 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2462 will be opened on it.
2463
2464
2465 @param ProtocolGuid ProtocolGuid pointer.
2466 @param ChildHandle Child Handle to retrieve Parent information.
2467
2468 **/
2469 VOID *
2470 EFIAPI
2471 GetParentProtocol (
2472 IN EFI_GUID *ProtocolGuid,
2473 IN EFI_HANDLE ChildHandle
2474 )
2475 {
2476 UINTN Index;
2477 UINTN HandleCount;
2478 VOID *Interface;
2479 EFI_STATUS Status;
2480 EFI_HANDLE *HandleBuffer;
2481
2482 //
2483 // Retrieve the list of all handles from the handle database
2484 //
2485 Status = gBS->LocateHandleBuffer (
2486 ByProtocol,
2487 ProtocolGuid,
2488 NULL,
2489 &HandleCount,
2490 &HandleBuffer
2491 );
2492
2493 if (EFI_ERROR (Status)) {
2494 return NULL;
2495 }
2496
2497 //
2498 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
2499 //
2500 for (Index = 0; Index < HandleCount; Index++) {
2501 Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
2502 if (!EFI_ERROR (Status)) {
2503 Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
2504 if (!EFI_ERROR (Status)) {
2505 gBS->FreePool (HandleBuffer);
2506 return Interface;
2507 }
2508 }
2509 }
2510
2511 gBS->FreePool (HandleBuffer);
2512 return NULL;
2513 }
2514
2515 /**
2516 Provides inquiry information for the controller type.
2517
2518 This function is used by the IDE bus driver to get inquiry data. Data format
2519 of Identify data is defined by the Interface GUID.
2520
2521 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2522 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
2523 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
2524
2525 @retval EFI_SUCCESS The command was accepted without any errors.
2526 @retval EFI_NOT_FOUND Device does not support this data class
2527 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
2528 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
2529
2530 **/
2531 EFI_STATUS
2532 EFIAPI
2533 ScsiDiskInfoInquiry (
2534 IN EFI_DISK_INFO_PROTOCOL *This,
2535 IN OUT VOID *InquiryData,
2536 IN OUT UINT32 *InquiryDataSize
2537 )
2538 {
2539 EFI_STATUS Status;
2540 SCSI_DISK_DEV *ScsiDiskDevice;
2541
2542 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
2543
2544 Status = EFI_BUFFER_TOO_SMALL;
2545 if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
2546 Status = EFI_SUCCESS;
2547 CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
2548 }
2549 *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
2550 return Status;
2551 }
2552
2553
2554 /**
2555 Provides identify information for the controller type.
2556
2557 This function is used by the IDE bus driver to get identify data. Data format
2558 of Identify data is defined by the Interface GUID.
2559
2560 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
2561 instance.
2562 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
2563 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
2564 size.
2565
2566 @retval EFI_SUCCESS The command was accepted without any errors.
2567 @retval EFI_NOT_FOUND Device does not support this data class
2568 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
2569 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
2570
2571 **/
2572 EFI_STATUS
2573 EFIAPI
2574 ScsiDiskInfoIdentify (
2575 IN EFI_DISK_INFO_PROTOCOL *This,
2576 IN OUT VOID *IdentifyData,
2577 IN OUT UINT32 *IdentifyDataSize
2578 )
2579 {
2580 EFI_STATUS Status;
2581 SCSI_DISK_DEV *ScsiDiskDevice;
2582
2583 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {
2584 //
2585 // Physical SCSI bus does not support this data class.
2586 //
2587 return EFI_NOT_FOUND;
2588 }
2589
2590 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
2591
2592 Status = EFI_BUFFER_TOO_SMALL;
2593 if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
2594 Status = EFI_SUCCESS;
2595 CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
2596 }
2597 *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
2598 return Status;
2599 }
2600
2601 /**
2602 Provides sense data information for the controller type.
2603
2604 This function is used by the IDE bus driver to get sense data.
2605 Data format of Sense data is defined by the Interface GUID.
2606
2607 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2608 @param[in, out] SenseData Pointer to the SenseData.
2609 @param[in, out] SenseDataSize Size of SenseData in bytes.
2610 @param[out] SenseDataNumber Pointer to the value for the sense data size.
2611
2612 @retval EFI_SUCCESS The command was accepted without any errors.
2613 @retval EFI_NOT_FOUND Device does not support this data class.
2614 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
2615 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
2616
2617 **/
2618 EFI_STATUS
2619 EFIAPI
2620 ScsiDiskInfoSenseData (
2621 IN EFI_DISK_INFO_PROTOCOL *This,
2622 IN OUT VOID *SenseData,
2623 IN OUT UINT32 *SenseDataSize,
2624 OUT UINT8 *SenseDataNumber
2625 )
2626 {
2627 return EFI_NOT_FOUND;
2628 }
2629
2630
2631 /**
2632 This function is used by the IDE bus driver to get controller information.
2633
2634 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2635 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
2636 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
2637
2638 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
2639 @retval EFI_UNSUPPORTED This is not an IDE device.
2640
2641 **/
2642 EFI_STATUS
2643 EFIAPI
2644 ScsiDiskInfoWhichIde (
2645 IN EFI_DISK_INFO_PROTOCOL *This,
2646 OUT UINT32 *IdeChannel,
2647 OUT UINT32 *IdeDevice
2648 )
2649 {
2650 SCSI_DISK_DEV *ScsiDiskDevice;
2651
2652 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {
2653 //
2654 // This is not an IDE physical device.
2655 //
2656 return EFI_UNSUPPORTED;
2657 }
2658
2659 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
2660 *IdeChannel = ScsiDiskDevice->Channel;
2661 *IdeDevice = ScsiDiskDevice->Device;
2662
2663 return EFI_SUCCESS;
2664 }
2665
2666
2667 /**
2668 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
2669
2670 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
2671 implement Identify() interface for DiskInfo protocol. The ATA command is sent
2672 via SCSI Request Packet.
2673
2674 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2675
2676 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
2677 @retval others Some error occurred during the identification that ATAPI device.
2678
2679 **/
2680 EFI_STATUS
2681 AtapiIdentifyDevice (
2682 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
2683 )
2684 {
2685 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
2686 UINT8 Cdb[6];
2687
2688 //
2689 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
2690 //
2691 ZeroMem (&CommandPacket, sizeof (CommandPacket));
2692 ZeroMem (Cdb, sizeof (Cdb));
2693
2694 Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
2695 CommandPacket.Timeout = EFI_TIMER_PERIOD_SECONDS (1);
2696 CommandPacket.Cdb = Cdb;
2697 CommandPacket.CdbLength = sizeof (Cdb);
2698 CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
2699 CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
2700
2701 return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
2702 }
2703
2704
2705 /**
2706 Initialize the installation of DiskInfo protocol.
2707
2708 This function prepares for the installation of DiskInfo protocol on the child handle.
2709 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
2710 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
2711 to be IDE/AHCI interface GUID.
2712
2713 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2714 @param ChildHandle Child handle to install DiskInfo protocol.
2715
2716 **/
2717 VOID
2718 InitializeInstallDiskInfo (
2719 IN SCSI_DISK_DEV *ScsiDiskDevice,
2720 IN EFI_HANDLE ChildHandle
2721 )
2722 {
2723 EFI_STATUS Status;
2724 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
2725 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;
2726 ATAPI_DEVICE_PATH *AtapiDevicePath;
2727 SATA_DEVICE_PATH *SataDevicePath;
2728 UINTN IdentifyRetry;
2729
2730 Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);
2731 //
2732 // Device Path protocol must be installed on the device handle.
2733 //
2734 ASSERT_EFI_ERROR (Status);
2735 //
2736 // Copy the DiskInfo protocol template.
2737 //
2738 CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
2739
2740 while (!IsDevicePathEnd (DevicePathNode)) {
2741 ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
2742 if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
2743 (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
2744 (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
2745 ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
2746 (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {
2747
2748 IdentifyRetry = 3;
2749 do {
2750 //
2751 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
2752 // with IDE/AHCI interface GUID.
2753 //
2754 Status = AtapiIdentifyDevice (ScsiDiskDevice);
2755 if (!EFI_ERROR (Status)) {
2756 if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {
2757 //
2758 // We find the valid ATAPI device path
2759 //
2760 AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;
2761 ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
2762 ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
2763 //
2764 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
2765 //
2766 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
2767 } else {
2768 //
2769 // We find the valid SATA device path
2770 //
2771 SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;
2772 ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
2773 ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
2774 //
2775 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
2776 //
2777 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
2778 }
2779 return;
2780 }
2781 } while (--IdentifyRetry > 0);
2782 }
2783 DevicePathNode = ChildDevicePathNode;
2784 }
2785
2786 return;
2787 }