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