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