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