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