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