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