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