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