]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
MdeModulePkg ScsiDiskDxe: Modify WriteBlocks(Ex)() to follow UEFI spec
[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->BlkIo2.Media = &ScsiDiskDevice->BlkIoMedia;
243 ScsiDiskDevice->BlkIo2.Reset = ScsiDiskResetEx;
244 ScsiDiskDevice->BlkIo2.ReadBlocksEx = ScsiDiskReadBlocksEx;
245 ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx;
246 ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx;
247 ScsiDiskDevice->Handle = Controller;
248 InitializeListHead (&ScsiDiskDevice->BlkIo2Queue);
249
250 ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
251 switch (ScsiDiskDevice->DeviceType) {
252 case EFI_SCSI_TYPE_DISK:
253 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
254 MustReadCapacity = TRUE;
255 break;
256
257 case EFI_SCSI_TYPE_CDROM:
258 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
259 ScsiDiskDevice->BlkIo.Media->ReadOnly = TRUE;
260 MustReadCapacity = FALSE;
261 break;
262 }
263 //
264 // The Sense Data Array's initial size is 6
265 //
266 ScsiDiskDevice->SenseDataNumber = 6;
267 ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool (
268 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
269 );
270 if (ScsiDiskDevice->SenseData == NULL) {
271 gBS->CloseProtocol (
272 Controller,
273 &gEfiScsiIoProtocolGuid,
274 This->DriverBindingHandle,
275 Controller
276 );
277 FreePool (ScsiDiskDevice);
278 return EFI_OUT_OF_RESOURCES;
279 }
280
281 //
282 // Retrieve device information
283 //
284 MaxRetry = 2;
285 for (Index = 0; Index < MaxRetry; Index++) {
286 Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
287 if (!EFI_ERROR (Status)) {
288 break;
289 }
290
291 if (!NeedRetry) {
292 FreePool (ScsiDiskDevice->SenseData);
293 gBS->CloseProtocol (
294 Controller,
295 &gEfiScsiIoProtocolGuid,
296 This->DriverBindingHandle,
297 Controller
298 );
299 FreePool (ScsiDiskDevice);
300 return EFI_DEVICE_ERROR;
301 }
302 }
303 //
304 // The second parameter "TRUE" means must
305 // retrieve media capacity
306 //
307 Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);
308 if (!EFI_ERROR (Status)) {
309 //
310 // Determine if Block IO & Block IO2 should be produced on this controller
311 // handle
312 //
313 if (DetermineInstallBlockIo(Controller)) {
314 InitializeInstallDiskInfo(ScsiDiskDevice, Controller);
315 Status = gBS->InstallMultipleProtocolInterfaces (
316 &Controller,
317 &gEfiBlockIoProtocolGuid,
318 &ScsiDiskDevice->BlkIo,
319 &gEfiBlockIo2ProtocolGuid,
320 &ScsiDiskDevice->BlkIo2,
321 &gEfiDiskInfoProtocolGuid,
322 &ScsiDiskDevice->DiskInfo,
323 NULL
324 );
325 if (!EFI_ERROR(Status)) {
326 ScsiDiskDevice->ControllerNameTable = NULL;
327 AddUnicodeString2 (
328 "eng",
329 gScsiDiskComponentName.SupportedLanguages,
330 &ScsiDiskDevice->ControllerNameTable,
331 L"SCSI Disk Device",
332 TRUE
333 );
334 AddUnicodeString2 (
335 "en",
336 gScsiDiskComponentName2.SupportedLanguages,
337 &ScsiDiskDevice->ControllerNameTable,
338 L"SCSI Disk Device",
339 FALSE
340 );
341 return EFI_SUCCESS;
342 }
343 }
344 }
345
346 gBS->FreePool (ScsiDiskDevice->SenseData);
347 gBS->FreePool (ScsiDiskDevice);
348 gBS->CloseProtocol (
349 Controller,
350 &gEfiScsiIoProtocolGuid,
351 This->DriverBindingHandle,
352 Controller
353 );
354 return Status;
355
356 }
357
358
359 /**
360 Stop this driver on ControllerHandle.
361
362 This service is called by the EFI boot service DisconnectController().
363 In order to make drivers as small as possible, there are a few calling
364 restrictions for this service. DisconnectController() must follow these
365 calling restrictions. If any other agent wishes to call Stop() it must
366 also follow these calling restrictions.
367
368 @param This Protocol instance pointer.
369 @param ControllerHandle Handle of device to stop driver on
370 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
371 children is zero stop the entire bus driver.
372 @param ChildHandleBuffer List of Child Handles to Stop.
373
374 @retval EFI_SUCCESS This driver is removed ControllerHandle
375 @retval other This driver was not removed from this device
376
377 **/
378 EFI_STATUS
379 EFIAPI
380 ScsiDiskDriverBindingStop (
381 IN EFI_DRIVER_BINDING_PROTOCOL *This,
382 IN EFI_HANDLE Controller,
383 IN UINTN NumberOfChildren,
384 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
385 )
386 {
387 EFI_BLOCK_IO_PROTOCOL *BlkIo;
388 SCSI_DISK_DEV *ScsiDiskDevice;
389 EFI_STATUS Status;
390
391 Status = gBS->OpenProtocol (
392 Controller,
393 &gEfiBlockIoProtocolGuid,
394 (VOID **) &BlkIo,
395 This->DriverBindingHandle,
396 Controller,
397 EFI_OPEN_PROTOCOL_GET_PROTOCOL
398 );
399 if (EFI_ERROR (Status)) {
400 return Status;
401 }
402
403 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo);
404
405 //
406 // Wait for the BlockIo2 requests queue to become empty
407 //
408 while (!IsListEmpty (&ScsiDiskDevice->BlkIo2Queue));
409
410 Status = gBS->UninstallMultipleProtocolInterfaces (
411 Controller,
412 &gEfiBlockIoProtocolGuid,
413 &ScsiDiskDevice->BlkIo,
414 &gEfiBlockIo2ProtocolGuid,
415 &ScsiDiskDevice->BlkIo2,
416 &gEfiDiskInfoProtocolGuid,
417 &ScsiDiskDevice->DiskInfo,
418 NULL
419 );
420 if (!EFI_ERROR (Status)) {
421 gBS->CloseProtocol (
422 Controller,
423 &gEfiScsiIoProtocolGuid,
424 This->DriverBindingHandle,
425 Controller
426 );
427
428 ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
429
430 return EFI_SUCCESS;
431 }
432 //
433 // errors met
434 //
435 return Status;
436 }
437
438 /**
439 Reset SCSI Disk.
440
441
442 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
443 @param ExtendedVerification The flag about if extend verificate
444
445 @retval EFI_SUCCESS The device was reset.
446 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
447 not be reset.
448 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
449
450 **/
451 EFI_STATUS
452 EFIAPI
453 ScsiDiskReset (
454 IN EFI_BLOCK_IO_PROTOCOL *This,
455 IN BOOLEAN ExtendedVerification
456 )
457 {
458 EFI_TPL OldTpl;
459 SCSI_DISK_DEV *ScsiDiskDevice;
460 EFI_STATUS Status;
461
462 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
463
464 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
465
466 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
467
468 if (EFI_ERROR (Status)) {
469 Status = EFI_DEVICE_ERROR;
470 goto Done;
471 }
472
473 if (!ExtendedVerification) {
474 goto Done;
475 }
476
477 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
478
479 if (EFI_ERROR (Status)) {
480 Status = EFI_DEVICE_ERROR;
481 goto Done;
482 }
483
484 Done:
485 gBS->RestoreTPL (OldTpl);
486 return Status;
487 }
488
489 /**
490 The function is to Read Block from SCSI Disk.
491
492 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
493 @param MediaId The Id of Media detected
494 @param Lba The logic block address
495 @param BufferSize The size of Buffer
496 @param Buffer The buffer to fill the read out data
497
498 @retval EFI_SUCCESS Successfully to read out block.
499 @retval EFI_DEVICE_ERROR Fail to detect media.
500 @retval EFI_NO_MEDIA Media is not present.
501 @retval EFI_MEDIA_CHANGED Media has changed.
502 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
503 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
504
505 **/
506 EFI_STATUS
507 EFIAPI
508 ScsiDiskReadBlocks (
509 IN EFI_BLOCK_IO_PROTOCOL *This,
510 IN UINT32 MediaId,
511 IN EFI_LBA Lba,
512 IN UINTN BufferSize,
513 OUT VOID *Buffer
514 )
515 {
516 SCSI_DISK_DEV *ScsiDiskDevice;
517 EFI_BLOCK_IO_MEDIA *Media;
518 EFI_STATUS Status;
519 UINTN BlockSize;
520 UINTN NumberOfBlocks;
521 BOOLEAN MediaChange;
522 EFI_TPL OldTpl;
523
524 MediaChange = FALSE;
525 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
526 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
527
528 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
529
530 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
531 if (EFI_ERROR (Status)) {
532 Status = EFI_DEVICE_ERROR;
533 goto Done;
534 }
535
536 if (MediaChange) {
537 gBS->ReinstallProtocolInterface (
538 ScsiDiskDevice->Handle,
539 &gEfiBlockIoProtocolGuid,
540 &ScsiDiskDevice->BlkIo,
541 &ScsiDiskDevice->BlkIo
542 );
543 gBS->ReinstallProtocolInterface (
544 ScsiDiskDevice->Handle,
545 &gEfiBlockIo2ProtocolGuid,
546 &ScsiDiskDevice->BlkIo2,
547 &ScsiDiskDevice->BlkIo2
548 );
549 Status = EFI_MEDIA_CHANGED;
550 goto Done;
551 }
552 }
553 //
554 // Get the intrinsic block size
555 //
556 Media = ScsiDiskDevice->BlkIo.Media;
557 BlockSize = Media->BlockSize;
558
559 NumberOfBlocks = BufferSize / BlockSize;
560
561 if (!(Media->MediaPresent)) {
562 Status = EFI_NO_MEDIA;
563 goto Done;
564 }
565
566 if (MediaId != Media->MediaId) {
567 Status = EFI_MEDIA_CHANGED;
568 goto Done;
569 }
570
571 if (Buffer == NULL) {
572 Status = EFI_INVALID_PARAMETER;
573 goto Done;
574 }
575
576 if (BufferSize == 0) {
577 Status = EFI_SUCCESS;
578 goto Done;
579 }
580
581 if (BufferSize % BlockSize != 0) {
582 Status = EFI_BAD_BUFFER_SIZE;
583 goto Done;
584 }
585
586 if (Lba > Media->LastBlock) {
587 Status = EFI_INVALID_PARAMETER;
588 goto Done;
589 }
590
591 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
592 Status = EFI_INVALID_PARAMETER;
593 goto Done;
594 }
595
596 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
597 Status = EFI_INVALID_PARAMETER;
598 goto Done;
599 }
600
601 //
602 // If all the parameters are valid, then perform read sectors command
603 // to transfer data from device to host.
604 //
605 Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
606
607 Done:
608 gBS->RestoreTPL (OldTpl);
609 return Status;
610 }
611
612 /**
613 The function is to Write Block to SCSI Disk.
614
615 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
616 @param MediaId The Id of Media detected
617 @param Lba The logic block address
618 @param BufferSize The size of Buffer
619 @param Buffer The buffer to fill the read out data
620
621 @retval EFI_SUCCESS Successfully to read out block.
622 @retval EFI_WRITE_PROTECTED The device can not be written to.
623 @retval EFI_DEVICE_ERROR Fail to detect media.
624 @retval EFI_NO_MEDIA Media is not present.
625 @retval EFI_MEDIA_CHNAGED Media has changed.
626 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
627 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
628
629 **/
630 EFI_STATUS
631 EFIAPI
632 ScsiDiskWriteBlocks (
633 IN EFI_BLOCK_IO_PROTOCOL *This,
634 IN UINT32 MediaId,
635 IN EFI_LBA Lba,
636 IN UINTN BufferSize,
637 IN VOID *Buffer
638 )
639 {
640 SCSI_DISK_DEV *ScsiDiskDevice;
641 EFI_BLOCK_IO_MEDIA *Media;
642 EFI_STATUS Status;
643 UINTN BlockSize;
644 UINTN NumberOfBlocks;
645 BOOLEAN MediaChange;
646 EFI_TPL OldTpl;
647
648 MediaChange = FALSE;
649 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
650 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
651
652 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
653
654 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
655 if (EFI_ERROR (Status)) {
656 Status = EFI_DEVICE_ERROR;
657 goto Done;
658 }
659
660 if (MediaChange) {
661 gBS->ReinstallProtocolInterface (
662 ScsiDiskDevice->Handle,
663 &gEfiBlockIoProtocolGuid,
664 &ScsiDiskDevice->BlkIo,
665 &ScsiDiskDevice->BlkIo
666 );
667 gBS->ReinstallProtocolInterface (
668 ScsiDiskDevice->Handle,
669 &gEfiBlockIo2ProtocolGuid,
670 &ScsiDiskDevice->BlkIo2,
671 &ScsiDiskDevice->BlkIo2
672 );
673 Status = EFI_MEDIA_CHANGED;
674 goto Done;
675 }
676 }
677 //
678 // Get the intrinsic block size
679 //
680 Media = ScsiDiskDevice->BlkIo.Media;
681 BlockSize = Media->BlockSize;
682
683 NumberOfBlocks = BufferSize / BlockSize;
684
685 if (!(Media->MediaPresent)) {
686 Status = EFI_NO_MEDIA;
687 goto Done;
688 }
689
690 if (MediaId != Media->MediaId) {
691 Status = EFI_MEDIA_CHANGED;
692 goto Done;
693 }
694
695 if (Media->ReadOnly) {
696 Status = EFI_WRITE_PROTECTED;
697 goto Done;
698 }
699
700 if (BufferSize == 0) {
701 Status = EFI_SUCCESS;
702 goto Done;
703 }
704
705 if (Buffer == NULL) {
706 Status = EFI_INVALID_PARAMETER;
707 goto Done;
708 }
709
710 if (BufferSize % BlockSize != 0) {
711 Status = EFI_BAD_BUFFER_SIZE;
712 goto Done;
713 }
714
715 if (Lba > Media->LastBlock) {
716 Status = EFI_INVALID_PARAMETER;
717 goto Done;
718 }
719
720 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
721 Status = EFI_INVALID_PARAMETER;
722 goto Done;
723 }
724
725 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
726 Status = EFI_INVALID_PARAMETER;
727 goto Done;
728 }
729 //
730 // if all the parameters are valid, then perform read sectors command
731 // to transfer data from device to host.
732 //
733 Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
734
735 Done:
736 gBS->RestoreTPL (OldTpl);
737 return Status;
738 }
739
740 /**
741 Flush Block to Disk.
742
743 EFI_SUCCESS is returned directly.
744
745 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
746
747 @retval EFI_SUCCESS All outstanding data was written to the device
748
749 **/
750 EFI_STATUS
751 EFIAPI
752 ScsiDiskFlushBlocks (
753 IN EFI_BLOCK_IO_PROTOCOL *This
754 )
755 {
756 //
757 // return directly
758 //
759 return EFI_SUCCESS;
760 }
761
762
763 /**
764 Reset SCSI Disk.
765
766 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
767 @param ExtendedVerification The flag about if extend verificate.
768
769 @retval EFI_SUCCESS The device was reset.
770 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
771 not be reset.
772 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
773
774 **/
775 EFI_STATUS
776 EFIAPI
777 ScsiDiskResetEx (
778 IN EFI_BLOCK_IO2_PROTOCOL *This,
779 IN BOOLEAN ExtendedVerification
780 )
781 {
782 EFI_TPL OldTpl;
783 SCSI_DISK_DEV *ScsiDiskDevice;
784 EFI_STATUS Status;
785
786 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
787
788 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
789
790 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
791
792 if (EFI_ERROR (Status)) {
793 Status = EFI_DEVICE_ERROR;
794 goto Done;
795 }
796
797 if (!ExtendedVerification) {
798 goto Done;
799 }
800
801 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
802
803 if (EFI_ERROR (Status)) {
804 Status = EFI_DEVICE_ERROR;
805 goto Done;
806 }
807
808 Done:
809 gBS->RestoreTPL (OldTpl);
810 return Status;
811 }
812
813 /**
814 The function is to Read Block from SCSI Disk.
815
816 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
817 @param MediaId The Id of Media detected.
818 @param Lba The logic block address.
819 @param Token A pointer to the token associated with the transaction.
820 @param BufferSize The size of Buffer.
821 @param Buffer The buffer to fill the read out data.
822
823 @retval EFI_SUCCESS The read request was queued if Token-> Event is
824 not NULL. The data was read correctly from the
825 device if theToken-> Event is NULL.
826 @retval EFI_DEVICE_ERROR The device reported an error while attempting
827 to perform the read operation.
828 @retval EFI_NO_MEDIA There is no media in the device.
829 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
830 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
831 the intrinsic block size of the device.
832 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
833 valid, or the buffer is not on proper
834 alignment.
835 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
836 lack of resources.
837
838 **/
839 EFI_STATUS
840 EFIAPI
841 ScsiDiskReadBlocksEx (
842 IN EFI_BLOCK_IO2_PROTOCOL *This,
843 IN UINT32 MediaId,
844 IN EFI_LBA Lba,
845 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
846 IN UINTN BufferSize,
847 OUT VOID *Buffer
848 )
849 {
850 SCSI_DISK_DEV *ScsiDiskDevice;
851 EFI_BLOCK_IO_MEDIA *Media;
852 EFI_STATUS Status;
853 UINTN BlockSize;
854 UINTN NumberOfBlocks;
855 BOOLEAN MediaChange;
856 EFI_TPL OldTpl;
857
858 MediaChange = FALSE;
859 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
860 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
861
862 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
863
864 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
865 if (EFI_ERROR (Status)) {
866 Status = EFI_DEVICE_ERROR;
867 goto Done;
868 }
869
870 if (MediaChange) {
871 gBS->ReinstallProtocolInterface (
872 ScsiDiskDevice->Handle,
873 &gEfiBlockIoProtocolGuid,
874 &ScsiDiskDevice->BlkIo,
875 &ScsiDiskDevice->BlkIo
876 );
877 gBS->ReinstallProtocolInterface (
878 ScsiDiskDevice->Handle,
879 &gEfiBlockIo2ProtocolGuid,
880 &ScsiDiskDevice->BlkIo2,
881 &ScsiDiskDevice->BlkIo2
882 );
883 Status = EFI_MEDIA_CHANGED;
884 goto Done;
885 }
886 }
887 //
888 // Get the intrinsic block size
889 //
890 Media = ScsiDiskDevice->BlkIo2.Media;
891 BlockSize = Media->BlockSize;
892
893 NumberOfBlocks = BufferSize / BlockSize;
894
895 if (!(Media->MediaPresent)) {
896 Status = EFI_NO_MEDIA;
897 goto Done;
898 }
899
900 if (MediaId != Media->MediaId) {
901 Status = EFI_MEDIA_CHANGED;
902 goto Done;
903 }
904
905 if (Buffer == NULL) {
906 Status = EFI_INVALID_PARAMETER;
907 goto Done;
908 }
909
910 if (BufferSize == 0) {
911 if ((Token != NULL) && (Token->Event != NULL)) {
912 Token->TransactionStatus = EFI_SUCCESS;
913 gBS->SignalEvent (Token->Event);
914 }
915
916 Status = EFI_SUCCESS;
917 goto Done;
918 }
919
920 if (BufferSize % BlockSize != 0) {
921 Status = EFI_BAD_BUFFER_SIZE;
922 goto Done;
923 }
924
925 if (Lba > Media->LastBlock) {
926 Status = EFI_INVALID_PARAMETER;
927 goto Done;
928 }
929
930 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
931 Status = EFI_INVALID_PARAMETER;
932 goto Done;
933 }
934
935 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
936 Status = EFI_INVALID_PARAMETER;
937 goto Done;
938 }
939
940 //
941 // If all the parameters are valid, then perform read sectors command
942 // to transfer data from device to host.
943 //
944 if ((Token != NULL) && (Token->Event != NULL)) {
945 Token->TransactionStatus = EFI_SUCCESS;
946 Status = ScsiDiskAsyncReadSectors (
947 ScsiDiskDevice,
948 Buffer,
949 Lba,
950 NumberOfBlocks,
951 Token
952 );
953 } else {
954 Status = ScsiDiskReadSectors (
955 ScsiDiskDevice,
956 Buffer,
957 Lba,
958 NumberOfBlocks
959 );
960 }
961
962 Done:
963 gBS->RestoreTPL (OldTpl);
964 return Status;
965 }
966
967 /**
968 The function is to Write Block to SCSI Disk.
969
970 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
971 @param MediaId The Id of Media detected.
972 @param Lba The logic block address.
973 @param Token A pointer to the token associated with the transaction.
974 @param BufferSize The size of Buffer.
975 @param Buffer The buffer to fill the read out data.
976
977 @retval EFI_SUCCESS The data were written correctly to the device.
978 @retval EFI_WRITE_PROTECTED The device cannot be written to.
979 @retval EFI_NO_MEDIA There is no media in the device.
980 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
981 @retval EFI_DEVICE_ERROR The device reported an error while attempting
982 to perform the write operation.
983 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
984 the intrinsic block size of the device.
985 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
986 valid, or the buffer is not on proper
987 alignment.
988
989 **/
990 EFI_STATUS
991 EFIAPI
992 ScsiDiskWriteBlocksEx (
993 IN EFI_BLOCK_IO2_PROTOCOL *This,
994 IN UINT32 MediaId,
995 IN EFI_LBA Lba,
996 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
997 IN UINTN BufferSize,
998 IN VOID *Buffer
999 )
1000 {
1001 SCSI_DISK_DEV *ScsiDiskDevice;
1002 EFI_BLOCK_IO_MEDIA *Media;
1003 EFI_STATUS Status;
1004 UINTN BlockSize;
1005 UINTN NumberOfBlocks;
1006 BOOLEAN MediaChange;
1007 EFI_TPL OldTpl;
1008
1009 MediaChange = FALSE;
1010 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1011 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
1012
1013 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
1014
1015 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1016 if (EFI_ERROR (Status)) {
1017 Status = EFI_DEVICE_ERROR;
1018 goto Done;
1019 }
1020
1021 if (MediaChange) {
1022 gBS->ReinstallProtocolInterface (
1023 ScsiDiskDevice->Handle,
1024 &gEfiBlockIoProtocolGuid,
1025 &ScsiDiskDevice->BlkIo,
1026 &ScsiDiskDevice->BlkIo
1027 );
1028 gBS->ReinstallProtocolInterface (
1029 ScsiDiskDevice->Handle,
1030 &gEfiBlockIo2ProtocolGuid,
1031 &ScsiDiskDevice->BlkIo2,
1032 &ScsiDiskDevice->BlkIo2
1033 );
1034 Status = EFI_MEDIA_CHANGED;
1035 goto Done;
1036 }
1037 }
1038 //
1039 // Get the intrinsic block size
1040 //
1041 Media = ScsiDiskDevice->BlkIo2.Media;
1042 BlockSize = Media->BlockSize;
1043
1044 NumberOfBlocks = BufferSize / BlockSize;
1045
1046 if (!(Media->MediaPresent)) {
1047 Status = EFI_NO_MEDIA;
1048 goto Done;
1049 }
1050
1051 if (MediaId != Media->MediaId) {
1052 Status = EFI_MEDIA_CHANGED;
1053 goto Done;
1054 }
1055
1056 if (Media->ReadOnly) {
1057 Status = EFI_WRITE_PROTECTED;
1058 goto Done;
1059 }
1060
1061 if (BufferSize == 0) {
1062 if ((Token != NULL) && (Token->Event != NULL)) {
1063 Token->TransactionStatus = EFI_SUCCESS;
1064 gBS->SignalEvent (Token->Event);
1065 }
1066
1067 Status = EFI_SUCCESS;
1068 goto Done;
1069 }
1070
1071 if (Buffer == NULL) {
1072 Status = EFI_INVALID_PARAMETER;
1073 goto Done;
1074 }
1075
1076 if (BufferSize % BlockSize != 0) {
1077 Status = EFI_BAD_BUFFER_SIZE;
1078 goto Done;
1079 }
1080
1081 if (Lba > Media->LastBlock) {
1082 Status = EFI_INVALID_PARAMETER;
1083 goto Done;
1084 }
1085
1086 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1087 Status = EFI_INVALID_PARAMETER;
1088 goto Done;
1089 }
1090
1091 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
1092 Status = EFI_INVALID_PARAMETER;
1093 goto Done;
1094 }
1095
1096 //
1097 // if all the parameters are valid, then perform write sectors command
1098 // to transfer data from device to host.
1099 //
1100 if ((Token != NULL) && (Token->Event != NULL)) {
1101 Token->TransactionStatus = EFI_SUCCESS;
1102 Status = ScsiDiskAsyncWriteSectors (
1103 ScsiDiskDevice,
1104 Buffer,
1105 Lba,
1106 NumberOfBlocks,
1107 Token
1108 );
1109 } else {
1110 Status = ScsiDiskWriteSectors (
1111 ScsiDiskDevice,
1112 Buffer,
1113 Lba,
1114 NumberOfBlocks
1115 );
1116 }
1117
1118 Done:
1119 gBS->RestoreTPL (OldTpl);
1120 return Status;
1121 }
1122
1123 /**
1124 Flush the Block Device.
1125
1126 @param This Indicates a pointer to the calling context.
1127 @param Token A pointer to the token associated with the transaction.
1128
1129 @retval EFI_SUCCESS All outstanding data was written to the device.
1130 @retval EFI_DEVICE_ERROR The device reported an error while attempting to
1131 write data.
1132 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1133 @retval EFI_NO_MEDIA There is no media in the device.
1134 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1135
1136 **/
1137 EFI_STATUS
1138 EFIAPI
1139 ScsiDiskFlushBlocksEx (
1140 IN EFI_BLOCK_IO2_PROTOCOL *This,
1141 IN OUT EFI_BLOCK_IO2_TOKEN *Token
1142 )
1143 {
1144 SCSI_DISK_DEV *ScsiDiskDevice;
1145 EFI_BLOCK_IO_MEDIA *Media;
1146 EFI_STATUS Status;
1147 BOOLEAN MediaChange;
1148 EFI_TPL OldTpl;
1149
1150 MediaChange = FALSE;
1151 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1152 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
1153
1154 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
1155
1156 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1157 if (EFI_ERROR (Status)) {
1158 Status = EFI_DEVICE_ERROR;
1159 goto Done;
1160 }
1161
1162 if (MediaChange) {
1163 gBS->ReinstallProtocolInterface (
1164 ScsiDiskDevice->Handle,
1165 &gEfiBlockIoProtocolGuid,
1166 &ScsiDiskDevice->BlkIo,
1167 &ScsiDiskDevice->BlkIo
1168 );
1169 gBS->ReinstallProtocolInterface (
1170 ScsiDiskDevice->Handle,
1171 &gEfiBlockIo2ProtocolGuid,
1172 &ScsiDiskDevice->BlkIo2,
1173 &ScsiDiskDevice->BlkIo2
1174 );
1175 Status = EFI_MEDIA_CHANGED;
1176 goto Done;
1177 }
1178 }
1179
1180 Media = ScsiDiskDevice->BlkIo2.Media;
1181
1182 if (!(Media->MediaPresent)) {
1183 Status = EFI_NO_MEDIA;
1184 goto Done;
1185 }
1186
1187 if (Media->ReadOnly) {
1188 Status = EFI_WRITE_PROTECTED;
1189 goto Done;
1190 }
1191
1192 //
1193 // Wait for the BlockIo2 requests queue to become empty
1194 //
1195 while (!IsListEmpty (&ScsiDiskDevice->BlkIo2Queue));
1196
1197 Status = EFI_SUCCESS;
1198
1199 //
1200 // Signal caller event
1201 //
1202 if ((Token != NULL) && (Token->Event != NULL)) {
1203 Token->TransactionStatus = EFI_SUCCESS;
1204 gBS->SignalEvent (Token->Event);
1205 }
1206
1207 Done:
1208 gBS->RestoreTPL (OldTpl);
1209 return Status;
1210 }
1211
1212
1213 /**
1214 Detect Device and read out capacity ,if error occurs, parse the sense key.
1215
1216 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1217 @param MustReadCapacity The flag about reading device capacity
1218 @param MediaChange The pointer of flag indicates if media has changed
1219
1220 @retval EFI_DEVICE_ERROR Indicates that error occurs
1221 @retval EFI_SUCCESS Successfully to detect media
1222
1223 **/
1224 EFI_STATUS
1225 ScsiDiskDetectMedia (
1226 IN SCSI_DISK_DEV *ScsiDiskDevice,
1227 IN BOOLEAN MustReadCapacity,
1228 OUT BOOLEAN *MediaChange
1229 )
1230 {
1231 EFI_STATUS Status;
1232 EFI_SCSI_SENSE_DATA *SenseData;
1233 UINTN NumberOfSenseKeys;
1234 BOOLEAN NeedRetry;
1235 BOOLEAN NeedReadCapacity;
1236 UINT8 Retry;
1237 UINT8 MaxRetry;
1238 EFI_BLOCK_IO_MEDIA OldMedia;
1239 UINTN Action;
1240 EFI_EVENT TimeoutEvt;
1241
1242 Status = EFI_SUCCESS;
1243 SenseData = NULL;
1244 NumberOfSenseKeys = 0;
1245 Retry = 0;
1246 MaxRetry = 3;
1247 Action = ACTION_NO_ACTION;
1248 NeedReadCapacity = FALSE;
1249 *MediaChange = FALSE;
1250 TimeoutEvt = NULL;
1251
1252 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
1253
1254 Status = gBS->CreateEvent (
1255 EVT_TIMER,
1256 TPL_CALLBACK,
1257 NULL,
1258 NULL,
1259 &TimeoutEvt
1260 );
1261 if (EFI_ERROR (Status)) {
1262 return Status;
1263 }
1264
1265 Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120));
1266 if (EFI_ERROR (Status)) {
1267 goto EXIT;
1268 }
1269
1270 //
1271 // Sending Test_Unit cmd to poll device status.
1272 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1273 // We limit the upper boundary to 120 seconds.
1274 //
1275 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
1276 Status = ScsiDiskTestUnitReady (
1277 ScsiDiskDevice,
1278 &NeedRetry,
1279 &SenseData,
1280 &NumberOfSenseKeys
1281 );
1282 if (!EFI_ERROR (Status)) {
1283 Status = DetectMediaParsingSenseKeys (
1284 ScsiDiskDevice,
1285 SenseData,
1286 NumberOfSenseKeys,
1287 &Action
1288 );
1289 if (EFI_ERROR (Status)) {
1290 goto EXIT;
1291 } else if (Action == ACTION_RETRY_COMMAND_LATER) {
1292 continue;
1293 } else {
1294 break;
1295 }
1296 } else {
1297 Retry++;
1298 if (!NeedRetry || (Retry >= MaxRetry)) {
1299 goto EXIT;
1300 }
1301 }
1302 }
1303
1304 if (EFI_ERROR (Status)) {
1305 goto EXIT;
1306 }
1307
1308 //
1309 // ACTION_NO_ACTION: need not read capacity
1310 // other action code: need read capacity
1311 //
1312 if (Action == ACTION_READ_CAPACITY) {
1313 NeedReadCapacity = TRUE;
1314 }
1315
1316 //
1317 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1318 // retrieve capacity via Read Capacity command
1319 //
1320 if (NeedReadCapacity || MustReadCapacity) {
1321 //
1322 // retrieve media information
1323 //
1324 for (Retry = 0; Retry < MaxRetry; Retry++) {
1325 Status = ScsiDiskReadCapacity (
1326 ScsiDiskDevice,
1327 &NeedRetry,
1328 &SenseData,
1329 &NumberOfSenseKeys
1330 );
1331 if (!EFI_ERROR (Status)) {
1332 //
1333 // analyze sense key to action
1334 //
1335 Status = DetectMediaParsingSenseKeys (
1336 ScsiDiskDevice,
1337 SenseData,
1338 NumberOfSenseKeys,
1339 &Action
1340 );
1341 if (EFI_ERROR (Status)) {
1342 //
1343 // if Status is error, it may indicate crisis error,
1344 // so return without retry.
1345 //
1346 goto EXIT;
1347 } else if (Action == ACTION_RETRY_COMMAND_LATER) {
1348 Retry = 0;
1349 continue;
1350 } else {
1351 break;
1352 }
1353 } else {
1354 Retry++;
1355 if (!NeedRetry || (Retry >= MaxRetry)) {
1356 goto EXIT;
1357 }
1358 }
1359 }
1360
1361 if (EFI_ERROR (Status)) {
1362 goto EXIT;
1363 }
1364 }
1365
1366 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
1367 //
1368 // Media change information got from the device
1369 //
1370 *MediaChange = TRUE;
1371 }
1372
1373 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
1374 *MediaChange = TRUE;
1375 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
1376 }
1377
1378 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
1379 *MediaChange = TRUE;
1380 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
1381 }
1382
1383 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
1384 *MediaChange = TRUE;
1385 ScsiDiskDevice->BlkIo.Media->MediaId += 1;
1386 }
1387
1388 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
1389 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
1390 //
1391 // when change from no media to media present, reset the MediaId to 1.
1392 //
1393 ScsiDiskDevice->BlkIo.Media->MediaId = 1;
1394 } else {
1395 //
1396 // when no media, reset the MediaId to zero.
1397 //
1398 ScsiDiskDevice->BlkIo.Media->MediaId = 0;
1399 }
1400
1401 *MediaChange = TRUE;
1402 }
1403
1404 EXIT:
1405 if (TimeoutEvt != NULL) {
1406 gBS->CloseEvent (TimeoutEvt);
1407 }
1408 return Status;
1409 }
1410
1411
1412 /**
1413 Send out Inquiry command to Device.
1414
1415 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1416 @param NeedRetry Indicates if needs try again when error happens
1417
1418 @retval EFI_DEVICE_ERROR Indicates that error occurs
1419 @retval EFI_SUCCESS Successfully to detect media
1420
1421 **/
1422 EFI_STATUS
1423 ScsiDiskInquiryDevice (
1424 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1425 OUT BOOLEAN *NeedRetry
1426 )
1427 {
1428 UINT32 InquiryDataLength;
1429 UINT8 SenseDataLength;
1430 UINT8 HostAdapterStatus;
1431 UINT8 TargetStatus;
1432 EFI_SCSI_SENSE_DATA *SenseDataArray;
1433 UINTN NumberOfSenseKeys;
1434 EFI_STATUS Status;
1435 UINT8 MaxRetry;
1436 UINT8 Index;
1437 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;
1438 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE *BlockLimits;
1439 UINTN PageLength;
1440
1441 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
1442 SenseDataLength = 0;
1443
1444 Status = ScsiInquiryCommand (
1445 ScsiDiskDevice->ScsiIo,
1446 SCSI_DISK_TIMEOUT,
1447 NULL,
1448 &SenseDataLength,
1449 &HostAdapterStatus,
1450 &TargetStatus,
1451 (VOID *) &(ScsiDiskDevice->InquiryData),
1452 &InquiryDataLength,
1453 FALSE
1454 );
1455 //
1456 // no need to check HostAdapterStatus and TargetStatus
1457 //
1458 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
1459 ParseInquiryData (ScsiDiskDevice);
1460
1461 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
1462 //
1463 // Check whether the device supports Block Limits VPD page (0xB0)
1464 //
1465 SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
1466 if (SupportedVpdPages == NULL) {
1467 *NeedRetry = FALSE;
1468 return EFI_DEVICE_ERROR;
1469 }
1470 ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
1471 InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);
1472 SenseDataLength = 0;
1473 Status = ScsiInquiryCommandEx (
1474 ScsiDiskDevice->ScsiIo,
1475 SCSI_DISK_TIMEOUT,
1476 NULL,
1477 &SenseDataLength,
1478 &HostAdapterStatus,
1479 &TargetStatus,
1480 (VOID *) SupportedVpdPages,
1481 &InquiryDataLength,
1482 TRUE,
1483 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1484 );
1485 if (!EFI_ERROR (Status)) {
1486 PageLength = (SupportedVpdPages->PageLength2 << 8)
1487 | SupportedVpdPages->PageLength1;
1488 for (Index = 0; Index < PageLength; Index++) {
1489 if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
1490 break;
1491 }
1492 }
1493
1494 //
1495 // Query the Block Limits VPD page
1496 //
1497 if (Index < PageLength) {
1498 BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
1499 if (BlockLimits == NULL) {
1500 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
1501 *NeedRetry = FALSE;
1502 return EFI_DEVICE_ERROR;
1503 }
1504 ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
1505 InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
1506 SenseDataLength = 0;
1507 Status = ScsiInquiryCommandEx (
1508 ScsiDiskDevice->ScsiIo,
1509 SCSI_DISK_TIMEOUT,
1510 NULL,
1511 &SenseDataLength,
1512 &HostAdapterStatus,
1513 &TargetStatus,
1514 (VOID *) BlockLimits,
1515 &InquiryDataLength,
1516 TRUE,
1517 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1518 );
1519 if (!EFI_ERROR (Status)) {
1520 ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
1521 (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
1522 BlockLimits->OptimalTransferLengthGranularity1;
1523 }
1524
1525 FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
1526 }
1527 }
1528
1529 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
1530 }
1531 }
1532
1533 if (!EFI_ERROR (Status)) {
1534 return EFI_SUCCESS;
1535
1536 } else if (Status == EFI_NOT_READY) {
1537 *NeedRetry = TRUE;
1538 return EFI_DEVICE_ERROR;
1539
1540 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1541 *NeedRetry = FALSE;
1542 return EFI_DEVICE_ERROR;
1543 }
1544 //
1545 // go ahead to check HostAdapterStatus and TargetStatus
1546 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1547 //
1548
1549 Status = CheckHostAdapterStatus (HostAdapterStatus);
1550 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1551 *NeedRetry = TRUE;
1552 return EFI_DEVICE_ERROR;
1553 } else if (Status == EFI_DEVICE_ERROR) {
1554 //
1555 // reset the scsi channel
1556 //
1557 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1558 *NeedRetry = FALSE;
1559 return EFI_DEVICE_ERROR;
1560 }
1561
1562 Status = CheckTargetStatus (TargetStatus);
1563 if (Status == EFI_NOT_READY) {
1564 //
1565 // reset the scsi device
1566 //
1567 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1568 *NeedRetry = TRUE;
1569 return EFI_DEVICE_ERROR;
1570
1571 } else if (Status == EFI_DEVICE_ERROR) {
1572 *NeedRetry = FALSE;
1573 return EFI_DEVICE_ERROR;
1574 }
1575
1576 //
1577 // if goes here, meant ScsiInquiryCommand() failed.
1578 // if ScsiDiskRequestSenseKeys() succeeds at last,
1579 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1580 //
1581 MaxRetry = 3;
1582 for (Index = 0; Index < MaxRetry; Index++) {
1583 Status = ScsiDiskRequestSenseKeys (
1584 ScsiDiskDevice,
1585 NeedRetry,
1586 &SenseDataArray,
1587 &NumberOfSenseKeys,
1588 TRUE
1589 );
1590 if (!EFI_ERROR (Status)) {
1591 *NeedRetry = TRUE;
1592 return EFI_DEVICE_ERROR;
1593 }
1594
1595 if (!*NeedRetry) {
1596 return EFI_DEVICE_ERROR;
1597 }
1598 }
1599 //
1600 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1601 // set *NeedRetry = FALSE to avoid the outside caller try again.
1602 //
1603 *NeedRetry = FALSE;
1604 return EFI_DEVICE_ERROR;
1605 }
1606
1607 /**
1608 To test device.
1609
1610 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1611 When Test Unit Ready command encounters any error caused by host adapter or
1612 target, return error without retrieving Sense Keys.
1613
1614 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1615 @param NeedRetry The pointer of flag indicates try again
1616 @param SenseDataArray The pointer of an array of sense data
1617 @param NumberOfSenseKeys The pointer of the number of sense data array
1618
1619 @retval EFI_DEVICE_ERROR Indicates that error occurs
1620 @retval EFI_SUCCESS Successfully to test unit
1621
1622 **/
1623 EFI_STATUS
1624 ScsiDiskTestUnitReady (
1625 IN SCSI_DISK_DEV *ScsiDiskDevice,
1626 OUT BOOLEAN *NeedRetry,
1627 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1628 OUT UINTN *NumberOfSenseKeys
1629 )
1630 {
1631 EFI_STATUS Status;
1632 UINT8 SenseDataLength;
1633 UINT8 HostAdapterStatus;
1634 UINT8 TargetStatus;
1635 UINT8 Index;
1636 UINT8 MaxRetry;
1637
1638 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
1639 *NumberOfSenseKeys = 0;
1640
1641 //
1642 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1643 //
1644 Status = ScsiTestUnitReadyCommand (
1645 ScsiDiskDevice->ScsiIo,
1646 SCSI_DISK_TIMEOUT,
1647 ScsiDiskDevice->SenseData,
1648 &SenseDataLength,
1649 &HostAdapterStatus,
1650 &TargetStatus
1651 );
1652 //
1653 // no need to check HostAdapterStatus and TargetStatus
1654 //
1655 if (Status == EFI_NOT_READY) {
1656 *NeedRetry = TRUE;
1657 return EFI_DEVICE_ERROR;
1658
1659 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
1660 *NeedRetry = FALSE;
1661 return EFI_DEVICE_ERROR;
1662 }
1663 //
1664 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1665 //
1666
1667 Status = CheckHostAdapterStatus (HostAdapterStatus);
1668 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1669 *NeedRetry = TRUE;
1670 return EFI_DEVICE_ERROR;
1671
1672 } else if (Status == EFI_DEVICE_ERROR) {
1673 //
1674 // reset the scsi channel
1675 //
1676 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1677 *NeedRetry = FALSE;
1678 return EFI_DEVICE_ERROR;
1679 }
1680
1681 Status = CheckTargetStatus (TargetStatus);
1682 if (Status == EFI_NOT_READY) {
1683 //
1684 // reset the scsi device
1685 //
1686 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1687 *NeedRetry = TRUE;
1688 return EFI_DEVICE_ERROR;
1689
1690 } else if (Status == EFI_DEVICE_ERROR) {
1691 *NeedRetry = FALSE;
1692 return EFI_DEVICE_ERROR;
1693 }
1694
1695 if (SenseDataLength != 0) {
1696 *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
1697 *SenseDataArray = ScsiDiskDevice->SenseData;
1698 return EFI_SUCCESS;
1699 }
1700
1701 MaxRetry = 3;
1702 for (Index = 0; Index < MaxRetry; Index++) {
1703 Status = ScsiDiskRequestSenseKeys (
1704 ScsiDiskDevice,
1705 NeedRetry,
1706 SenseDataArray,
1707 NumberOfSenseKeys,
1708 FALSE
1709 );
1710 if (!EFI_ERROR (Status)) {
1711 return EFI_SUCCESS;
1712 }
1713
1714 if (!*NeedRetry) {
1715 return EFI_DEVICE_ERROR;
1716 }
1717 }
1718 //
1719 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1720 // set *NeedRetry = FALSE to avoid the outside caller try again.
1721 //
1722 *NeedRetry = FALSE;
1723 return EFI_DEVICE_ERROR;
1724 }
1725
1726 /**
1727 Parsing Sense Keys which got from request sense command.
1728
1729 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1730 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1731 @param NumberOfSenseKeys The number of sense key
1732 @param Action The pointer of action which indicates what is need to do next
1733
1734 @retval EFI_DEVICE_ERROR Indicates that error occurs
1735 @retval EFI_SUCCESS Successfully to complete the parsing
1736
1737 **/
1738 EFI_STATUS
1739 DetectMediaParsingSenseKeys (
1740 OUT SCSI_DISK_DEV *ScsiDiskDevice,
1741 IN EFI_SCSI_SENSE_DATA *SenseData,
1742 IN UINTN NumberOfSenseKeys,
1743 OUT UINTN *Action
1744 )
1745 {
1746 BOOLEAN RetryLater;
1747
1748 //
1749 // Default is to read capacity, unless..
1750 //
1751 *Action = ACTION_READ_CAPACITY;
1752
1753 if (NumberOfSenseKeys == 0) {
1754 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
1755 *Action = ACTION_NO_ACTION;
1756 }
1757 return EFI_SUCCESS;
1758 }
1759
1760 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
1761 //
1762 // No Sense Key returned from last submitted command
1763 //
1764 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
1765 *Action = ACTION_NO_ACTION;
1766 }
1767 return EFI_SUCCESS;
1768 }
1769
1770 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
1771 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
1772 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
1773 *Action = ACTION_NO_ACTION;
1774 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1775 return EFI_SUCCESS;
1776 }
1777
1778 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
1779 ScsiDiskDevice->BlkIo.Media->MediaId++;
1780 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1781 return EFI_SUCCESS;
1782 }
1783
1784 if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
1785 *Action = ACTION_RETRY_COMMAND_LATER;
1786 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1787 return EFI_SUCCESS;
1788 }
1789
1790 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
1791 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
1792 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
1793 return EFI_DEVICE_ERROR;
1794 }
1795
1796 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
1797 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1798 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
1799 return EFI_DEVICE_ERROR;
1800 }
1801
1802 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
1803 if (RetryLater) {
1804 *Action = ACTION_RETRY_COMMAND_LATER;
1805 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1806 return EFI_SUCCESS;
1807 }
1808 *Action = ACTION_NO_ACTION;
1809 return EFI_DEVICE_ERROR;
1810 }
1811
1812 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
1813 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
1814 return EFI_SUCCESS;
1815 }
1816
1817
1818 /**
1819 Send read capacity command to device and get the device parameter.
1820
1821 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1822 @param NeedRetry The pointer of flag indicates if need a retry
1823 @param SenseDataArray The pointer of an array of sense data
1824 @param NumberOfSenseKeys The number of sense key
1825
1826 @retval EFI_DEVICE_ERROR Indicates that error occurs
1827 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1828
1829 **/
1830 EFI_STATUS
1831 ScsiDiskReadCapacity (
1832 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
1833 OUT BOOLEAN *NeedRetry,
1834 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
1835 OUT UINTN *NumberOfSenseKeys
1836 )
1837 {
1838 UINT8 HostAdapterStatus;
1839 UINT8 TargetStatus;
1840 EFI_STATUS CommandStatus;
1841 EFI_STATUS Status;
1842 UINT8 Index;
1843 UINT8 MaxRetry;
1844 UINT8 SenseDataLength;
1845 UINT32 DataLength10;
1846 UINT32 DataLength16;
1847 EFI_SCSI_DISK_CAPACITY_DATA *CapacityData10;
1848 EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
1849
1850 CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1851 if (CapacityData10 == NULL) {
1852 *NeedRetry = FALSE;
1853 return EFI_DEVICE_ERROR;
1854 }
1855 CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1856 if (CapacityData16 == NULL) {
1857 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1858 *NeedRetry = FALSE;
1859 return EFI_DEVICE_ERROR;
1860 }
1861
1862 SenseDataLength = 0;
1863 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
1864 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
1865 ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1866 ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1867
1868 *NumberOfSenseKeys = 0;
1869 *NeedRetry = FALSE;
1870
1871 //
1872 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1873 // 16 byte command should be used to access large hard disk >2TB
1874 //
1875 CommandStatus = ScsiReadCapacityCommand (
1876 ScsiDiskDevice->ScsiIo,
1877 SCSI_DISK_TIMEOUT,
1878 NULL,
1879 &SenseDataLength,
1880 &HostAdapterStatus,
1881 &TargetStatus,
1882 (VOID *) CapacityData10,
1883 &DataLength10,
1884 FALSE
1885 );
1886
1887 ScsiDiskDevice->Cdb16Byte = FALSE;
1888 if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
1889 (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff)) {
1890 //
1891 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1892 //
1893 ScsiDiskDevice->Cdb16Byte = TRUE;
1894 //
1895 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1896 // and LowestAlignedLba
1897 //
1898 CommandStatus = ScsiReadCapacity16Command (
1899 ScsiDiskDevice->ScsiIo,
1900 SCSI_DISK_TIMEOUT,
1901 NULL,
1902 &SenseDataLength,
1903 &HostAdapterStatus,
1904 &TargetStatus,
1905 (VOID *) CapacityData16,
1906 &DataLength16,
1907 FALSE
1908 );
1909 }
1910
1911 //
1912 // no need to check HostAdapterStatus and TargetStatus
1913 //
1914 if (CommandStatus == EFI_SUCCESS) {
1915 GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
1916 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1917 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1918 return EFI_SUCCESS;
1919 }
1920
1921 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
1922 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
1923
1924 if (CommandStatus == EFI_NOT_READY) {
1925 *NeedRetry = TRUE;
1926 return EFI_DEVICE_ERROR;
1927 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
1928 *NeedRetry = FALSE;
1929 return EFI_DEVICE_ERROR;
1930 }
1931
1932 //
1933 // go ahead to check HostAdapterStatus and TargetStatus
1934 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1935 //
1936
1937 Status = CheckHostAdapterStatus (HostAdapterStatus);
1938 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
1939 *NeedRetry = TRUE;
1940 return EFI_DEVICE_ERROR;
1941
1942 } else if (Status == EFI_DEVICE_ERROR) {
1943 //
1944 // reset the scsi channel
1945 //
1946 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
1947 *NeedRetry = FALSE;
1948 return EFI_DEVICE_ERROR;
1949 }
1950
1951 Status = CheckTargetStatus (TargetStatus);
1952 if (Status == EFI_NOT_READY) {
1953 //
1954 // reset the scsi device
1955 //
1956 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
1957 *NeedRetry = TRUE;
1958 return EFI_DEVICE_ERROR;
1959
1960 } else if (Status == EFI_DEVICE_ERROR) {
1961 *NeedRetry = FALSE;
1962 return EFI_DEVICE_ERROR;
1963 }
1964
1965 //
1966 // if goes here, meant ScsiReadCapacityCommand() failed.
1967 // if ScsiDiskRequestSenseKeys() succeeds at last,
1968 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1969 //
1970 MaxRetry = 3;
1971 for (Index = 0; Index < MaxRetry; Index++) {
1972
1973 Status = ScsiDiskRequestSenseKeys (
1974 ScsiDiskDevice,
1975 NeedRetry,
1976 SenseDataArray,
1977 NumberOfSenseKeys,
1978 TRUE
1979 );
1980 if (!EFI_ERROR (Status)) {
1981 return EFI_SUCCESS;
1982 }
1983
1984 if (!*NeedRetry) {
1985 return EFI_DEVICE_ERROR;
1986 }
1987 }
1988 //
1989 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1990 // set *NeedRetry = FALSE to avoid the outside caller try again.
1991 //
1992 *NeedRetry = FALSE;
1993 return EFI_DEVICE_ERROR;
1994 }
1995
1996 /**
1997 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1998
1999 @param HostAdapterStatus Host Adapter status
2000
2001 @retval EFI_SUCCESS Host adapter is OK.
2002 @retval EFI_TIMEOUT Timeout.
2003 @retval EFI_NOT_READY Adapter NOT ready.
2004 @retval EFI_DEVICE_ERROR Adapter device error.
2005
2006 **/
2007 EFI_STATUS
2008 CheckHostAdapterStatus (
2009 IN UINT8 HostAdapterStatus
2010 )
2011 {
2012 switch (HostAdapterStatus) {
2013 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
2014 return EFI_SUCCESS;
2015
2016 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
2017 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
2018 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
2019 return EFI_TIMEOUT;
2020
2021 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
2022 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
2023 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
2024 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
2025 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
2026 return EFI_NOT_READY;
2027
2028 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
2029 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
2030 return EFI_DEVICE_ERROR;
2031
2032 default:
2033 return EFI_SUCCESS;
2034 }
2035 }
2036
2037
2038 /**
2039 Check the target status and re-interpret it in EFI_STATUS.
2040
2041 @param TargetStatus Target status
2042
2043 @retval EFI_NOT_READY Device is NOT ready.
2044 @retval EFI_DEVICE_ERROR
2045 @retval EFI_SUCCESS
2046
2047 **/
2048 EFI_STATUS
2049 CheckTargetStatus (
2050 IN UINT8 TargetStatus
2051 )
2052 {
2053 switch (TargetStatus) {
2054 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
2055 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
2056 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
2057 return EFI_SUCCESS;
2058
2059 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
2060 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
2061 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
2062 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
2063 return EFI_NOT_READY;
2064
2065 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
2066 return EFI_DEVICE_ERROR;
2067
2068 default:
2069 return EFI_SUCCESS;
2070 }
2071 }
2072
2073
2074 /**
2075 Retrieve all sense keys from the device.
2076
2077 When encountering error during the process, if retrieve sense keys before
2078 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2079 and NeedRetry set to FALSE; otherwize, return the proper return status.
2080
2081 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2082 @param NeedRetry The pointer of flag indicates if need a retry
2083 @param SenseDataArray The pointer of an array of sense data
2084 @param NumberOfSenseKeys The number of sense key
2085 @param AskResetIfError The flag indicates if need reset when error occurs
2086
2087 @retval EFI_DEVICE_ERROR Indicates that error occurs
2088 @retval EFI_SUCCESS Successfully to request sense key
2089
2090 **/
2091 EFI_STATUS
2092 ScsiDiskRequestSenseKeys (
2093 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
2094 OUT BOOLEAN *NeedRetry,
2095 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
2096 OUT UINTN *NumberOfSenseKeys,
2097 IN BOOLEAN AskResetIfError
2098 )
2099 {
2100 EFI_SCSI_SENSE_DATA *PtrSenseData;
2101 UINT8 SenseDataLength;
2102 BOOLEAN SenseReq;
2103 EFI_STATUS Status;
2104 EFI_STATUS FallStatus;
2105 UINT8 HostAdapterStatus;
2106 UINT8 TargetStatus;
2107
2108 FallStatus = EFI_SUCCESS;
2109 SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);
2110
2111 ZeroMem (
2112 ScsiDiskDevice->SenseData,
2113 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
2114 );
2115
2116 *NumberOfSenseKeys = 0;
2117 *SenseDataArray = ScsiDiskDevice->SenseData;
2118 Status = EFI_SUCCESS;
2119 PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
2120 if (PtrSenseData == NULL) {
2121 return EFI_DEVICE_ERROR;
2122 }
2123
2124 for (SenseReq = TRUE; SenseReq;) {
2125 ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
2126 Status = ScsiRequestSenseCommand (
2127 ScsiDiskDevice->ScsiIo,
2128 SCSI_DISK_TIMEOUT,
2129 PtrSenseData,
2130 &SenseDataLength,
2131 &HostAdapterStatus,
2132 &TargetStatus
2133 );
2134 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
2135 FallStatus = EFI_SUCCESS;
2136
2137 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2138 *NeedRetry = TRUE;
2139 FallStatus = EFI_DEVICE_ERROR;
2140
2141 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2142 *NeedRetry = FALSE;
2143 FallStatus = EFI_DEVICE_ERROR;
2144
2145 } else if (Status == EFI_DEVICE_ERROR) {
2146 if (AskResetIfError) {
2147 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2148 }
2149
2150 FallStatus = EFI_DEVICE_ERROR;
2151 }
2152
2153 if (EFI_ERROR (FallStatus)) {
2154 if (*NumberOfSenseKeys != 0) {
2155 *NeedRetry = FALSE;
2156 Status = EFI_SUCCESS;
2157 goto EXIT;
2158 } else {
2159 Status = EFI_DEVICE_ERROR;
2160 goto EXIT;
2161 }
2162 }
2163
2164 CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
2165 (*NumberOfSenseKeys) += 1;
2166
2167 //
2168 // no more sense key or number of sense keys exceeds predefined,
2169 // skip the loop.
2170 //
2171 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
2172 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
2173 SenseReq = FALSE;
2174 }
2175 }
2176
2177 EXIT:
2178 FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
2179 return Status;
2180 }
2181
2182
2183 /**
2184 Get information from media read capacity command.
2185
2186 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2187 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2188 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2189
2190 **/
2191 VOID
2192 GetMediaInfo (
2193 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
2194 IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,
2195 IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16
2196 )
2197 {
2198 UINT8 *Ptr;
2199
2200 if (!ScsiDiskDevice->Cdb16Byte) {
2201 ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity10->LastLba3 << 24) |
2202 (Capacity10->LastLba2 << 16) |
2203 (Capacity10->LastLba1 << 8) |
2204 Capacity10->LastLba0;
2205
2206 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
2207 (Capacity10->BlockSize2 << 16) |
2208 (Capacity10->BlockSize1 << 8) |
2209 Capacity10->BlockSize0;
2210 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;
2211 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 0;
2212 } else {
2213 Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;
2214 *Ptr++ = Capacity16->LastLba0;
2215 *Ptr++ = Capacity16->LastLba1;
2216 *Ptr++ = Capacity16->LastLba2;
2217 *Ptr++ = Capacity16->LastLba3;
2218 *Ptr++ = Capacity16->LastLba4;
2219 *Ptr++ = Capacity16->LastLba5;
2220 *Ptr++ = Capacity16->LastLba6;
2221 *Ptr = Capacity16->LastLba7;
2222
2223 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
2224 (Capacity16->BlockSize2 << 16) |
2225 (Capacity16->BlockSize1 << 8) |
2226 Capacity16->BlockSize0;
2227
2228 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |
2229 Capacity16->LowestAlignLogic1;
2230 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = (1 << Capacity16->LogicPerPhysical);
2231 }
2232
2233 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
2234 }
2235
2236 /**
2237 Parse Inquiry data.
2238
2239 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2240
2241 **/
2242 VOID
2243 ParseInquiryData (
2244 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
2245 )
2246 {
2247 ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
2248 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
2249 }
2250
2251 /**
2252 Read sector from SCSI Disk.
2253
2254 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2255 @param Buffer The buffer to fill in the read out data
2256 @param Lba Logic block address
2257 @param NumberOfBlocks The number of blocks to read
2258
2259 @retval EFI_DEVICE_ERROR Indicates a device error.
2260 @retval EFI_SUCCESS Operation is successful.
2261
2262 **/
2263 EFI_STATUS
2264 ScsiDiskReadSectors (
2265 IN SCSI_DISK_DEV *ScsiDiskDevice,
2266 OUT VOID *Buffer,
2267 IN EFI_LBA Lba,
2268 IN UINTN NumberOfBlocks
2269 )
2270 {
2271 UINTN BlocksRemaining;
2272 UINT8 *PtrBuffer;
2273 UINT32 BlockSize;
2274 UINT32 ByteCount;
2275 UINT32 MaxBlock;
2276 UINT32 SectorCount;
2277 UINT32 NextSectorCount;
2278 UINT64 Timeout;
2279 EFI_STATUS Status;
2280 UINT8 Index;
2281 UINT8 MaxRetry;
2282 BOOLEAN NeedRetry;
2283
2284 Status = EFI_SUCCESS;
2285
2286 BlocksRemaining = NumberOfBlocks;
2287 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
2288
2289 //
2290 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2291 //
2292 if (!ScsiDiskDevice->Cdb16Byte) {
2293 MaxBlock = 0xFFFF;
2294 } else {
2295 MaxBlock = 0xFFFFFFFF;
2296 }
2297
2298 PtrBuffer = Buffer;
2299
2300 while (BlocksRemaining > 0) {
2301
2302 if (BlocksRemaining <= MaxBlock) {
2303 if (!ScsiDiskDevice->Cdb16Byte) {
2304 SectorCount = (UINT16) BlocksRemaining;
2305 } else {
2306 SectorCount = (UINT32) BlocksRemaining;
2307 }
2308 } else {
2309 SectorCount = MaxBlock;
2310 }
2311
2312 ByteCount = SectorCount * BlockSize;
2313 //
2314 // |------------------------|-----------------|------------------|-----------------|
2315 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2316 // |------------------------|-----------------|------------------|-----------------|
2317 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2318 // |------------------------|-----------------|------------------|-----------------|
2319 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2320 // |------------------------|-----------------|------------------|-----------------|
2321 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2322 // |------------------------|-----------------|------------------|-----------------|
2323 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2324 // |------------------------|-----------------|------------------|-----------------|
2325 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2326 // |------------------------|-----------------|------------------|-----------------|
2327 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2328 // |------------------------|-----------------|------------------|-----------------|
2329 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2330 // |------------------------|-----------------|------------------|-----------------|
2331 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2332 // |------------------------|-----------------|------------------|-----------------|
2333 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2334 // |------------------------|-----------------|------------------|-----------------|
2335 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2336 // |------------------------|-----------------|------------------|-----------------|
2337 //
2338 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2339 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2340 // From the above table, we could know 2.1Mbytes per second is lowest one.
2341 // The timout value is rounded up to nearest integar and here an additional 30s is added
2342 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2343 // commands in the Standby/Idle mode.
2344 //
2345 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
2346
2347 MaxRetry = 2;
2348 for (Index = 0; Index < MaxRetry; Index++) {
2349 if (!ScsiDiskDevice->Cdb16Byte) {
2350 Status = ScsiDiskRead10 (
2351 ScsiDiskDevice,
2352 &NeedRetry,
2353 Timeout,
2354 PtrBuffer,
2355 &ByteCount,
2356 (UINT32) Lba,
2357 SectorCount
2358 );
2359 } else {
2360 Status = ScsiDiskRead16 (
2361 ScsiDiskDevice,
2362 &NeedRetry,
2363 Timeout,
2364 PtrBuffer,
2365 &ByteCount,
2366 Lba,
2367 SectorCount
2368 );
2369 }
2370 if (!EFI_ERROR (Status)) {
2371 break;
2372 }
2373
2374 if (!NeedRetry) {
2375 return EFI_DEVICE_ERROR;
2376 }
2377
2378 //
2379 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2380 // lowered ByteCount on output, we must make sure that we lower
2381 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2382 // it is invalid to request more sectors in the CDB than the entire
2383 // transfer (ie. ByteCount) can carry.
2384 //
2385 // In addition, ByteCount is only expected to go down, or stay unchaged.
2386 // Therefore we don't need to update Timeout: the original timeout should
2387 // accommodate shorter transfers too.
2388 //
2389 NextSectorCount = ByteCount / BlockSize;
2390 if (NextSectorCount < SectorCount) {
2391 SectorCount = NextSectorCount;
2392 //
2393 // Account for any rounding down.
2394 //
2395 ByteCount = SectorCount * BlockSize;
2396 }
2397 }
2398
2399 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
2400 return EFI_DEVICE_ERROR;
2401 }
2402
2403 //
2404 // actual transferred sectors
2405 //
2406 SectorCount = ByteCount / BlockSize;
2407
2408 Lba += SectorCount;
2409 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
2410 BlocksRemaining -= SectorCount;
2411 }
2412
2413 return EFI_SUCCESS;
2414 }
2415
2416 /**
2417 Write sector to SCSI Disk.
2418
2419 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2420 @param Buffer The buffer of data to be written into SCSI Disk
2421 @param Lba Logic block address
2422 @param NumberOfBlocks The number of blocks to read
2423
2424 @retval EFI_DEVICE_ERROR Indicates a device error.
2425 @retval EFI_SUCCESS Operation is successful.
2426
2427 **/
2428 EFI_STATUS
2429 ScsiDiskWriteSectors (
2430 IN SCSI_DISK_DEV *ScsiDiskDevice,
2431 IN VOID *Buffer,
2432 IN EFI_LBA Lba,
2433 IN UINTN NumberOfBlocks
2434 )
2435 {
2436 UINTN BlocksRemaining;
2437 UINT8 *PtrBuffer;
2438 UINT32 BlockSize;
2439 UINT32 ByteCount;
2440 UINT32 MaxBlock;
2441 UINT32 SectorCount;
2442 UINT32 NextSectorCount;
2443 UINT64 Timeout;
2444 EFI_STATUS Status;
2445 UINT8 Index;
2446 UINT8 MaxRetry;
2447 BOOLEAN NeedRetry;
2448
2449 Status = EFI_SUCCESS;
2450
2451 BlocksRemaining = NumberOfBlocks;
2452 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
2453
2454 //
2455 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2456 //
2457 if (!ScsiDiskDevice->Cdb16Byte) {
2458 MaxBlock = 0xFFFF;
2459 } else {
2460 MaxBlock = 0xFFFFFFFF;
2461 }
2462
2463 PtrBuffer = Buffer;
2464
2465 while (BlocksRemaining > 0) {
2466
2467 if (BlocksRemaining <= MaxBlock) {
2468 if (!ScsiDiskDevice->Cdb16Byte) {
2469 SectorCount = (UINT16) BlocksRemaining;
2470 } else {
2471 SectorCount = (UINT32) BlocksRemaining;
2472 }
2473 } else {
2474 SectorCount = MaxBlock;
2475 }
2476
2477 ByteCount = SectorCount * BlockSize;
2478 //
2479 // |------------------------|-----------------|------------------|-----------------|
2480 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2481 // |------------------------|-----------------|------------------|-----------------|
2482 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2483 // |------------------------|-----------------|------------------|-----------------|
2484 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2485 // |------------------------|-----------------|------------------|-----------------|
2486 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2487 // |------------------------|-----------------|------------------|-----------------|
2488 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2489 // |------------------------|-----------------|------------------|-----------------|
2490 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2491 // |------------------------|-----------------|------------------|-----------------|
2492 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2493 // |------------------------|-----------------|------------------|-----------------|
2494 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2495 // |------------------------|-----------------|------------------|-----------------|
2496 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2497 // |------------------------|-----------------|------------------|-----------------|
2498 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2499 // |------------------------|-----------------|------------------|-----------------|
2500 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2501 // |------------------------|-----------------|------------------|-----------------|
2502 //
2503 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2504 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2505 // From the above table, we could know 2.1Mbytes per second is lowest one.
2506 // The timout value is rounded up to nearest integar and here an additional 30s is added
2507 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2508 // commands in the Standby/Idle mode.
2509 //
2510 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
2511 MaxRetry = 2;
2512 for (Index = 0; Index < MaxRetry; Index++) {
2513 if (!ScsiDiskDevice->Cdb16Byte) {
2514 Status = ScsiDiskWrite10 (
2515 ScsiDiskDevice,
2516 &NeedRetry,
2517 Timeout,
2518 PtrBuffer,
2519 &ByteCount,
2520 (UINT32) Lba,
2521 SectorCount
2522 );
2523 } else {
2524 Status = ScsiDiskWrite16 (
2525 ScsiDiskDevice,
2526 &NeedRetry,
2527 Timeout,
2528 PtrBuffer,
2529 &ByteCount,
2530 Lba,
2531 SectorCount
2532 );
2533 }
2534 if (!EFI_ERROR (Status)) {
2535 break;
2536 }
2537
2538 if (!NeedRetry) {
2539 return EFI_DEVICE_ERROR;
2540 }
2541
2542 //
2543 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
2544 // has lowered ByteCount on output, we must make sure that we lower
2545 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2546 // it is invalid to request more sectors in the CDB than the entire
2547 // transfer (ie. ByteCount) can carry.
2548 //
2549 // In addition, ByteCount is only expected to go down, or stay unchaged.
2550 // Therefore we don't need to update Timeout: the original timeout should
2551 // accommodate shorter transfers too.
2552 //
2553 NextSectorCount = ByteCount / BlockSize;
2554 if (NextSectorCount < SectorCount) {
2555 SectorCount = NextSectorCount;
2556 //
2557 // Account for any rounding down.
2558 //
2559 ByteCount = SectorCount * BlockSize;
2560 }
2561 }
2562
2563 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
2564 return EFI_DEVICE_ERROR;
2565 }
2566 //
2567 // actual transferred sectors
2568 //
2569 SectorCount = ByteCount / BlockSize;
2570
2571 Lba += SectorCount;
2572 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
2573 BlocksRemaining -= SectorCount;
2574 }
2575
2576 return EFI_SUCCESS;
2577 }
2578
2579 /**
2580 Asynchronously read sector from SCSI Disk.
2581
2582 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2583 @param Buffer The buffer to fill in the read out data.
2584 @param Lba Logic block address.
2585 @param NumberOfBlocks The number of blocks to read.
2586 @param Token A pointer to the token associated with the
2587 non-blocking read request.
2588
2589 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
2590 @retval EFI_DEVICE_ERROR Indicates a device error.
2591 @retval EFI_SUCCESS Operation is successful.
2592
2593 **/
2594 EFI_STATUS
2595 ScsiDiskAsyncReadSectors (
2596 IN SCSI_DISK_DEV *ScsiDiskDevice,
2597 OUT VOID *Buffer,
2598 IN EFI_LBA Lba,
2599 IN UINTN NumberOfBlocks,
2600 IN EFI_BLOCK_IO2_TOKEN *Token
2601 )
2602 {
2603 UINTN BlocksRemaining;
2604 UINT8 *PtrBuffer;
2605 UINT32 BlockSize;
2606 UINT32 ByteCount;
2607 UINT32 MaxBlock;
2608 UINT32 SectorCount;
2609 UINT64 Timeout;
2610 SCSI_BLKIO2_REQUEST *BlkIo2Req;
2611 EFI_STATUS Status;
2612
2613 if ((Token == NULL) || (Token->Event == NULL)) {
2614 return EFI_INVALID_PARAMETER;
2615 }
2616
2617 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
2618 if (BlkIo2Req == NULL) {
2619 return EFI_OUT_OF_RESOURCES;
2620 }
2621
2622 BlkIo2Req->Token = Token;
2623 InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link);
2624 InitializeListHead (&BlkIo2Req->ScsiRWQueue);
2625
2626 Status = EFI_SUCCESS;
2627
2628 BlocksRemaining = NumberOfBlocks;
2629 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
2630
2631 //
2632 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2633 // Command
2634 //
2635 if (!ScsiDiskDevice->Cdb16Byte) {
2636 MaxBlock = 0xFFFF;
2637 } else {
2638 MaxBlock = 0xFFFFFFFF;
2639 }
2640
2641 PtrBuffer = Buffer;
2642
2643 while (BlocksRemaining > 0) {
2644
2645 if (BlocksRemaining <= MaxBlock) {
2646 if (!ScsiDiskDevice->Cdb16Byte) {
2647 SectorCount = (UINT16) BlocksRemaining;
2648 } else {
2649 SectorCount = (UINT32) BlocksRemaining;
2650 }
2651 } else {
2652 SectorCount = MaxBlock;
2653 }
2654
2655 ByteCount = SectorCount * BlockSize;
2656 //
2657 // |------------------------|-----------------|------------------|-----------------|
2658 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2659 // |------------------------|-----------------|------------------|-----------------|
2660 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2661 // |------------------------|-----------------|------------------|-----------------|
2662 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2663 // |------------------------|-----------------|------------------|-----------------|
2664 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2665 // |------------------------|-----------------|------------------|-----------------|
2666 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2667 // |------------------------|-----------------|------------------|-----------------|
2668 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2669 // |------------------------|-----------------|------------------|-----------------|
2670 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2671 // |------------------------|-----------------|------------------|-----------------|
2672 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2673 // |------------------------|-----------------|------------------|-----------------|
2674 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2675 // |------------------------|-----------------|------------------|-----------------|
2676 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2677 // |------------------------|-----------------|------------------|-----------------|
2678 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2679 // |------------------------|-----------------|------------------|-----------------|
2680 //
2681 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2682 // we have to use the lowest transfer rate to calculate the possible
2683 // maximum timeout value for each operation.
2684 // From the above table, we could know 2.1Mbytes per second is lowest one.
2685 // The timout value is rounded up to nearest integar and here an additional
2686 // 30s is added to follow ATA spec in which it mentioned that the device
2687 // may take up to 30s to respond commands in the Standby/Idle mode.
2688 //
2689 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
2690
2691 if (!ScsiDiskDevice->Cdb16Byte) {
2692 Status = ScsiDiskAsyncRead10 (
2693 ScsiDiskDevice,
2694 Timeout,
2695 PtrBuffer,
2696 ByteCount,
2697 (UINT32) Lba,
2698 SectorCount,
2699 BlkIo2Req,
2700 Token
2701 );
2702 } else {
2703 Status = ScsiDiskAsyncRead16 (
2704 ScsiDiskDevice,
2705 Timeout,
2706 PtrBuffer,
2707 ByteCount,
2708 Lba,
2709 SectorCount,
2710 BlkIo2Req,
2711 Token
2712 );
2713 }
2714 if (EFI_ERROR (Status)) {
2715 //
2716 // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI
2717 // command fails. Otherwise, it will be freed in the callback function
2718 // ScsiDiskNotify().
2719 //
2720 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
2721 RemoveEntryList (&BlkIo2Req->Link);
2722 FreePool (BlkIo2Req);
2723 }
2724 return EFI_DEVICE_ERROR;
2725 }
2726
2727 //
2728 // Sectors submitted for transfer
2729 //
2730 SectorCount = ByteCount / BlockSize;
2731
2732 Lba += SectorCount;
2733 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
2734 BlocksRemaining -= SectorCount;
2735 }
2736
2737 return EFI_SUCCESS;
2738 }
2739
2740 /**
2741 Asynchronously write sector to SCSI Disk.
2742
2743 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2744 @param Buffer The buffer of data to be written into SCSI Disk.
2745 @param Lba Logic block address.
2746 @param NumberOfBlocks The number of blocks to read.
2747 @param Token A pointer to the token associated with the
2748 non-blocking read request.
2749
2750 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
2751 @retval EFI_DEVICE_ERROR Indicates a device error.
2752 @retval EFI_SUCCESS Operation is successful.
2753
2754 **/
2755 EFI_STATUS
2756 ScsiDiskAsyncWriteSectors (
2757 IN SCSI_DISK_DEV *ScsiDiskDevice,
2758 IN VOID *Buffer,
2759 IN EFI_LBA Lba,
2760 IN UINTN NumberOfBlocks,
2761 IN EFI_BLOCK_IO2_TOKEN *Token
2762 )
2763 {
2764 UINTN BlocksRemaining;
2765 UINT8 *PtrBuffer;
2766 UINT32 BlockSize;
2767 UINT32 ByteCount;
2768 UINT32 MaxBlock;
2769 UINT32 SectorCount;
2770 UINT64 Timeout;
2771 SCSI_BLKIO2_REQUEST *BlkIo2Req;
2772 EFI_STATUS Status;
2773
2774 if ((Token == NULL) || (Token->Event == NULL)) {
2775 return EFI_INVALID_PARAMETER;
2776 }
2777
2778 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
2779 if (BlkIo2Req == NULL) {
2780 return EFI_OUT_OF_RESOURCES;
2781 }
2782
2783 BlkIo2Req->Token = Token;
2784 InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link);
2785 InitializeListHead (&BlkIo2Req->ScsiRWQueue);
2786
2787 Status = EFI_SUCCESS;
2788
2789 BlocksRemaining = NumberOfBlocks;
2790 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
2791
2792 //
2793 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2794 // Command
2795 //
2796 if (!ScsiDiskDevice->Cdb16Byte) {
2797 MaxBlock = 0xFFFF;
2798 } else {
2799 MaxBlock = 0xFFFFFFFF;
2800 }
2801
2802 PtrBuffer = Buffer;
2803
2804 while (BlocksRemaining > 0) {
2805
2806 if (BlocksRemaining <= MaxBlock) {
2807 if (!ScsiDiskDevice->Cdb16Byte) {
2808 SectorCount = (UINT16) BlocksRemaining;
2809 } else {
2810 SectorCount = (UINT32) BlocksRemaining;
2811 }
2812 } else {
2813 SectorCount = MaxBlock;
2814 }
2815
2816 ByteCount = SectorCount * BlockSize;
2817 //
2818 // |------------------------|-----------------|------------------|-----------------|
2819 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2820 // |------------------------|-----------------|------------------|-----------------|
2821 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2822 // |------------------------|-----------------|------------------|-----------------|
2823 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2824 // |------------------------|-----------------|------------------|-----------------|
2825 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2826 // |------------------------|-----------------|------------------|-----------------|
2827 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2828 // |------------------------|-----------------|------------------|-----------------|
2829 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2830 // |------------------------|-----------------|------------------|-----------------|
2831 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2832 // |------------------------|-----------------|------------------|-----------------|
2833 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2834 // |------------------------|-----------------|------------------|-----------------|
2835 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2836 // |------------------------|-----------------|------------------|-----------------|
2837 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2838 // |------------------------|-----------------|------------------|-----------------|
2839 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2840 // |------------------------|-----------------|------------------|-----------------|
2841 //
2842 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2843 // we have to use the lowest transfer rate to calculate the possible
2844 // maximum timeout value for each operation.
2845 // From the above table, we could know 2.1Mbytes per second is lowest one.
2846 // The timout value is rounded up to nearest integar and here an additional
2847 // 30s is added to follow ATA spec in which it mentioned that the device
2848 // may take up to 30s to respond commands in the Standby/Idle mode.
2849 //
2850 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
2851
2852 if (!ScsiDiskDevice->Cdb16Byte) {
2853 Status = ScsiDiskAsyncWrite10 (
2854 ScsiDiskDevice,
2855 Timeout,
2856 PtrBuffer,
2857 ByteCount,
2858 (UINT32) Lba,
2859 SectorCount,
2860 BlkIo2Req,
2861 Token
2862 );
2863 } else {
2864 Status = ScsiDiskAsyncWrite16 (
2865 ScsiDiskDevice,
2866 Timeout,
2867 PtrBuffer,
2868 ByteCount,
2869 Lba,
2870 SectorCount,
2871 BlkIo2Req,
2872 Token
2873 );
2874 }
2875 if (EFI_ERROR (Status)) {
2876 //
2877 // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI
2878 // command fails. Otherwise, it will be freed in the callback function
2879 // ScsiDiskNotify().
2880 //
2881 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
2882 RemoveEntryList (&BlkIo2Req->Link);
2883 FreePool (BlkIo2Req);
2884 }
2885 return EFI_DEVICE_ERROR;
2886 }
2887
2888 //
2889 // Sectors submitted for transfer
2890 //
2891 SectorCount = ByteCount / BlockSize;
2892
2893 Lba += SectorCount;
2894 PtrBuffer = PtrBuffer + SectorCount * BlockSize;
2895 BlocksRemaining -= SectorCount;
2896 }
2897
2898 return EFI_SUCCESS;
2899 }
2900
2901
2902 /**
2903 Submit Read(10) command.
2904
2905 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2906 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2907 @param Timeout The time to complete the command
2908 @param DataBuffer The buffer to fill with the read out data
2909 @param DataLength The length of buffer
2910 @param StartLba The start logic block address
2911 @param SectorCount The number of blocks to read
2912
2913 @return EFI_STATUS is returned by calling ScsiRead10Command().
2914 **/
2915 EFI_STATUS
2916 ScsiDiskRead10 (
2917 IN SCSI_DISK_DEV *ScsiDiskDevice,
2918 OUT BOOLEAN *NeedRetry,
2919 IN UINT64 Timeout,
2920 OUT UINT8 *DataBuffer,
2921 IN OUT UINT32 *DataLength,
2922 IN UINT32 StartLba,
2923 IN UINT32 SectorCount
2924 )
2925 {
2926 UINT8 SenseDataLength;
2927 EFI_STATUS Status;
2928 EFI_STATUS ReturnStatus;
2929 UINT8 HostAdapterStatus;
2930 UINT8 TargetStatus;
2931 UINTN Action;
2932
2933 //
2934 // Implement a backoff algorithem to resolve some compatibility issues that
2935 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2936 // big data in a single operation.
2937 // This algorithem will at first try to execute original request. If the request fails
2938 // with media error sense data or else, it will reduce the transfer length to half and
2939 // try again till the operation succeeds or fails with one sector transfer length.
2940 //
2941 BackOff:
2942 *NeedRetry = FALSE;
2943 Action = ACTION_NO_ACTION;
2944 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2945 ReturnStatus = ScsiRead10Command (
2946 ScsiDiskDevice->ScsiIo,
2947 Timeout,
2948 ScsiDiskDevice->SenseData,
2949 &SenseDataLength,
2950 &HostAdapterStatus,
2951 &TargetStatus,
2952 DataBuffer,
2953 DataLength,
2954 StartLba,
2955 SectorCount
2956 );
2957
2958 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
2959 *NeedRetry = TRUE;
2960 return EFI_DEVICE_ERROR;
2961 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
2962 *NeedRetry = FALSE;
2963 return ReturnStatus;
2964 }
2965
2966 //
2967 // go ahead to check HostAdapterStatus and TargetStatus
2968 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2969 //
2970 Status = CheckHostAdapterStatus (HostAdapterStatus);
2971 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2972 *NeedRetry = TRUE;
2973 return EFI_DEVICE_ERROR;
2974 } else if (Status == EFI_DEVICE_ERROR) {
2975 //
2976 // reset the scsi channel
2977 //
2978 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2979 *NeedRetry = FALSE;
2980 return EFI_DEVICE_ERROR;
2981 }
2982
2983 Status = CheckTargetStatus (TargetStatus);
2984 if (Status == EFI_NOT_READY) {
2985 //
2986 // reset the scsi device
2987 //
2988 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2989 *NeedRetry = TRUE;
2990 return EFI_DEVICE_ERROR;
2991 } else if (Status == EFI_DEVICE_ERROR) {
2992 *NeedRetry = FALSE;
2993 return EFI_DEVICE_ERROR;
2994 }
2995
2996 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
2997 DEBUG ((EFI_D_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
2998 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
2999 if (Action == ACTION_RETRY_COMMAND_LATER) {
3000 *NeedRetry = TRUE;
3001 return EFI_DEVICE_ERROR;
3002 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3003 if (SectorCount <= 1) {
3004 //
3005 // Jump out if the operation still fails with one sector transfer length.
3006 //
3007 *NeedRetry = FALSE;
3008 return EFI_DEVICE_ERROR;
3009 }
3010 //
3011 // Try again with half length if the sense data shows we need to retry.
3012 //
3013 SectorCount >>= 1;
3014 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3015 goto BackOff;
3016 } else {
3017 *NeedRetry = FALSE;
3018 return EFI_DEVICE_ERROR;
3019 }
3020 }
3021
3022 return ReturnStatus;
3023 }
3024
3025
3026 /**
3027 Submit Write(10) Command.
3028
3029 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3030 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3031 @param Timeout The time to complete the command
3032 @param DataBuffer The buffer to fill with the read out data
3033 @param DataLength The length of buffer
3034 @param StartLba The start logic block address
3035 @param SectorCount The number of blocks to write
3036
3037 @return EFI_STATUS is returned by calling ScsiWrite10Command().
3038
3039 **/
3040 EFI_STATUS
3041 ScsiDiskWrite10 (
3042 IN SCSI_DISK_DEV *ScsiDiskDevice,
3043 OUT BOOLEAN *NeedRetry,
3044 IN UINT64 Timeout,
3045 IN UINT8 *DataBuffer,
3046 IN OUT UINT32 *DataLength,
3047 IN UINT32 StartLba,
3048 IN UINT32 SectorCount
3049 )
3050 {
3051 EFI_STATUS Status;
3052 EFI_STATUS ReturnStatus;
3053 UINT8 SenseDataLength;
3054 UINT8 HostAdapterStatus;
3055 UINT8 TargetStatus;
3056 UINTN Action;
3057
3058 //
3059 // Implement a backoff algorithem to resolve some compatibility issues that
3060 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3061 // big data in a single operation.
3062 // This algorithem will at first try to execute original request. If the request fails
3063 // with media error sense data or else, it will reduce the transfer length to half and
3064 // try again till the operation succeeds or fails with one sector transfer length.
3065 //
3066 BackOff:
3067 *NeedRetry = FALSE;
3068 Action = ACTION_NO_ACTION;
3069 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
3070 ReturnStatus = ScsiWrite10Command (
3071 ScsiDiskDevice->ScsiIo,
3072 Timeout,
3073 ScsiDiskDevice->SenseData,
3074 &SenseDataLength,
3075 &HostAdapterStatus,
3076 &TargetStatus,
3077 DataBuffer,
3078 DataLength,
3079 StartLba,
3080 SectorCount
3081 );
3082 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
3083 *NeedRetry = TRUE;
3084 return EFI_DEVICE_ERROR;
3085 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
3086 *NeedRetry = FALSE;
3087 return ReturnStatus;
3088 }
3089
3090 //
3091 // go ahead to check HostAdapterStatus and TargetStatus
3092 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3093 //
3094 Status = CheckHostAdapterStatus (HostAdapterStatus);
3095 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3096 *NeedRetry = TRUE;
3097 return EFI_DEVICE_ERROR;
3098 } else if (Status == EFI_DEVICE_ERROR) {
3099 //
3100 // reset the scsi channel
3101 //
3102 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3103 *NeedRetry = FALSE;
3104 return EFI_DEVICE_ERROR;
3105 }
3106
3107 Status = CheckTargetStatus (TargetStatus);
3108 if (Status == EFI_NOT_READY) {
3109 //
3110 // reset the scsi device
3111 //
3112 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3113 *NeedRetry = TRUE;
3114 return EFI_DEVICE_ERROR;
3115 } else if (Status == EFI_DEVICE_ERROR) {
3116 *NeedRetry = FALSE;
3117 return EFI_DEVICE_ERROR;
3118 }
3119
3120 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
3121 DEBUG ((EFI_D_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
3122 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
3123 if (Action == ACTION_RETRY_COMMAND_LATER) {
3124 *NeedRetry = TRUE;
3125 return EFI_DEVICE_ERROR;
3126 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3127 if (SectorCount <= 1) {
3128 //
3129 // Jump out if the operation still fails with one sector transfer length.
3130 //
3131 *NeedRetry = FALSE;
3132 return EFI_DEVICE_ERROR;
3133 }
3134 //
3135 // Try again with half length if the sense data shows we need to retry.
3136 //
3137 SectorCount >>= 1;
3138 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3139 goto BackOff;
3140 } else {
3141 *NeedRetry = FALSE;
3142 return EFI_DEVICE_ERROR;
3143 }
3144 }
3145
3146 return ReturnStatus;
3147 }
3148
3149
3150 /**
3151 Submit Read(16) command.
3152
3153 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3154 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3155 @param Timeout The time to complete the command
3156 @param DataBuffer The buffer to fill with the read out data
3157 @param DataLength The length of buffer
3158 @param StartLba The start logic block address
3159 @param SectorCount The number of blocks to read
3160
3161 @return EFI_STATUS is returned by calling ScsiRead16Command().
3162 **/
3163 EFI_STATUS
3164 ScsiDiskRead16 (
3165 IN SCSI_DISK_DEV *ScsiDiskDevice,
3166 OUT BOOLEAN *NeedRetry,
3167 IN UINT64 Timeout,
3168 OUT UINT8 *DataBuffer,
3169 IN OUT UINT32 *DataLength,
3170 IN UINT64 StartLba,
3171 IN UINT32 SectorCount
3172 )
3173 {
3174 UINT8 SenseDataLength;
3175 EFI_STATUS Status;
3176 EFI_STATUS ReturnStatus;
3177 UINT8 HostAdapterStatus;
3178 UINT8 TargetStatus;
3179 UINTN Action;
3180
3181 //
3182 // Implement a backoff algorithem to resolve some compatibility issues that
3183 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3184 // big data in a single operation.
3185 // This algorithem will at first try to execute original request. If the request fails
3186 // with media error sense data or else, it will reduce the transfer length to half and
3187 // try again till the operation succeeds or fails with one sector transfer length.
3188 //
3189 BackOff:
3190 *NeedRetry = FALSE;
3191 Action = ACTION_NO_ACTION;
3192 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
3193 ReturnStatus = ScsiRead16Command (
3194 ScsiDiskDevice->ScsiIo,
3195 Timeout,
3196 ScsiDiskDevice->SenseData,
3197 &SenseDataLength,
3198 &HostAdapterStatus,
3199 &TargetStatus,
3200 DataBuffer,
3201 DataLength,
3202 StartLba,
3203 SectorCount
3204 );
3205 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
3206 *NeedRetry = TRUE;
3207 return EFI_DEVICE_ERROR;
3208 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
3209 *NeedRetry = FALSE;
3210 return ReturnStatus;
3211 }
3212
3213 //
3214 // go ahead to check HostAdapterStatus and TargetStatus
3215 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3216 //
3217 Status = CheckHostAdapterStatus (HostAdapterStatus);
3218 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3219 *NeedRetry = TRUE;
3220 return EFI_DEVICE_ERROR;
3221 } else if (Status == EFI_DEVICE_ERROR) {
3222 //
3223 // reset the scsi channel
3224 //
3225 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3226 *NeedRetry = FALSE;
3227 return EFI_DEVICE_ERROR;
3228 }
3229
3230 Status = CheckTargetStatus (TargetStatus);
3231 if (Status == EFI_NOT_READY) {
3232 //
3233 // reset the scsi device
3234 //
3235 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3236 *NeedRetry = TRUE;
3237 return EFI_DEVICE_ERROR;
3238 } else if (Status == EFI_DEVICE_ERROR) {
3239 *NeedRetry = FALSE;
3240 return EFI_DEVICE_ERROR;
3241 }
3242
3243 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
3244 DEBUG ((EFI_D_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
3245 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
3246 if (Action == ACTION_RETRY_COMMAND_LATER) {
3247 *NeedRetry = TRUE;
3248 return EFI_DEVICE_ERROR;
3249 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3250 if (SectorCount <= 1) {
3251 //
3252 // Jump out if the operation still fails with one sector transfer length.
3253 //
3254 *NeedRetry = FALSE;
3255 return EFI_DEVICE_ERROR;
3256 }
3257 //
3258 // Try again with half length if the sense data shows we need to retry.
3259 //
3260 SectorCount >>= 1;
3261 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3262 goto BackOff;
3263 } else {
3264 *NeedRetry = FALSE;
3265 return EFI_DEVICE_ERROR;
3266 }
3267 }
3268
3269 return ReturnStatus;
3270 }
3271
3272
3273 /**
3274 Submit Write(16) Command.
3275
3276 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3277 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3278 @param Timeout The time to complete the command
3279 @param DataBuffer The buffer to fill with the read out data
3280 @param DataLength The length of buffer
3281 @param StartLba The start logic block address
3282 @param SectorCount The number of blocks to write
3283
3284 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3285
3286 **/
3287 EFI_STATUS
3288 ScsiDiskWrite16 (
3289 IN SCSI_DISK_DEV *ScsiDiskDevice,
3290 OUT BOOLEAN *NeedRetry,
3291 IN UINT64 Timeout,
3292 IN UINT8 *DataBuffer,
3293 IN OUT UINT32 *DataLength,
3294 IN UINT64 StartLba,
3295 IN UINT32 SectorCount
3296 )
3297 {
3298 EFI_STATUS Status;
3299 EFI_STATUS ReturnStatus;
3300 UINT8 SenseDataLength;
3301 UINT8 HostAdapterStatus;
3302 UINT8 TargetStatus;
3303 UINTN Action;
3304
3305 //
3306 // Implement a backoff algorithem to resolve some compatibility issues that
3307 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3308 // big data in a single operation.
3309 // This algorithem will at first try to execute original request. If the request fails
3310 // with media error sense data or else, it will reduce the transfer length to half and
3311 // try again till the operation succeeds or fails with one sector transfer length.
3312 //
3313 BackOff:
3314 *NeedRetry = FALSE;
3315 Action = ACTION_NO_ACTION;
3316 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
3317 ReturnStatus = ScsiWrite16Command (
3318 ScsiDiskDevice->ScsiIo,
3319 Timeout,
3320 ScsiDiskDevice->SenseData,
3321 &SenseDataLength,
3322 &HostAdapterStatus,
3323 &TargetStatus,
3324 DataBuffer,
3325 DataLength,
3326 StartLba,
3327 SectorCount
3328 );
3329 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
3330 *NeedRetry = TRUE;
3331 return EFI_DEVICE_ERROR;
3332 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
3333 *NeedRetry = FALSE;
3334 return ReturnStatus;
3335 }
3336
3337 //
3338 // go ahead to check HostAdapterStatus and TargetStatus
3339 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3340 //
3341 Status = CheckHostAdapterStatus (HostAdapterStatus);
3342 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3343 *NeedRetry = TRUE;
3344 return EFI_DEVICE_ERROR;
3345 } else if (Status == EFI_DEVICE_ERROR) {
3346 //
3347 // reset the scsi channel
3348 //
3349 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3350 *NeedRetry = FALSE;
3351 return EFI_DEVICE_ERROR;
3352 }
3353
3354 Status = CheckTargetStatus (TargetStatus);
3355 if (Status == EFI_NOT_READY) {
3356 //
3357 // reset the scsi device
3358 //
3359 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3360 *NeedRetry = TRUE;
3361 return EFI_DEVICE_ERROR;
3362 } else if (Status == EFI_DEVICE_ERROR) {
3363 *NeedRetry = FALSE;
3364 return EFI_DEVICE_ERROR;
3365 }
3366
3367 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
3368 DEBUG ((EFI_D_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
3369 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
3370 if (Action == ACTION_RETRY_COMMAND_LATER) {
3371 *NeedRetry = TRUE;
3372 return EFI_DEVICE_ERROR;
3373 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3374 if (SectorCount <= 1) {
3375 //
3376 // Jump out if the operation still fails with one sector transfer length.
3377 //
3378 *NeedRetry = FALSE;
3379 return EFI_DEVICE_ERROR;
3380 }
3381 //
3382 // Try again with half length if the sense data shows we need to retry.
3383 //
3384 SectorCount >>= 1;
3385 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3386 goto BackOff;
3387 } else {
3388 *NeedRetry = FALSE;
3389 return EFI_DEVICE_ERROR;
3390 }
3391 }
3392
3393 return ReturnStatus;
3394 }
3395
3396
3397 /**
3398 Internal helper notify function in which determine whether retry of a SCSI
3399 Read/Write command is needed and signal the event passed from Block I/O(2) if
3400 the SCSI I/O operation completes.
3401
3402 @param Event The instance of EFI_EVENT.
3403 @param Context The parameter passed in.
3404
3405 **/
3406 VOID
3407 EFIAPI
3408 ScsiDiskNotify (
3409 IN EFI_EVENT Event,
3410 IN VOID *Context
3411 )
3412 {
3413 EFI_STATUS Status;
3414 SCSI_ASYNC_RW_REQUEST *Request;
3415 SCSI_DISK_DEV *ScsiDiskDevice;
3416 EFI_BLOCK_IO2_TOKEN *Token;
3417 UINTN Action;
3418 UINT32 OldDataLength;
3419 UINT32 OldSectorCount;
3420 UINT8 MaxRetry;
3421
3422 gBS->CloseEvent (Event);
3423
3424 Request = (SCSI_ASYNC_RW_REQUEST *) Context;
3425 ScsiDiskDevice = Request->ScsiDiskDevice;
3426 Token = Request->BlkIo2Req->Token;
3427 OldDataLength = Request->DataLength;
3428 OldSectorCount = Request->SectorCount;
3429 MaxRetry = 2;
3430
3431 //
3432 // If previous sub-tasks already fails, no need to process this sub-task.
3433 //
3434 if (Token->TransactionStatus != EFI_SUCCESS) {
3435 goto Exit;
3436 }
3437
3438 //
3439 // Check HostAdapterStatus and TargetStatus
3440 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3441 //
3442 Status = CheckHostAdapterStatus (Request->HostAdapterStatus);
3443 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3444 if (++Request->TimesRetry > MaxRetry) {
3445 Token->TransactionStatus = EFI_DEVICE_ERROR;
3446 goto Exit;
3447 } else {
3448 goto Retry;
3449 }
3450 } else if (Status == EFI_DEVICE_ERROR) {
3451 //
3452 // reset the scsi channel
3453 //
3454 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3455 Token->TransactionStatus = EFI_DEVICE_ERROR;
3456 goto Exit;
3457 }
3458
3459 Status = CheckTargetStatus (Request->TargetStatus);
3460 if (Status == EFI_NOT_READY) {
3461 //
3462 // reset the scsi device
3463 //
3464 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3465 if (++Request->TimesRetry > MaxRetry) {
3466 Token->TransactionStatus = EFI_DEVICE_ERROR;
3467 goto Exit;
3468 } else {
3469 goto Retry;
3470 }
3471 } else if (Status == EFI_DEVICE_ERROR) {
3472 Token->TransactionStatus = EFI_DEVICE_ERROR;
3473 goto Exit;
3474 }
3475
3476 if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
3477 DEBUG ((EFI_D_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));
3478
3479 Status = DetectMediaParsingSenseKeys (
3480 ScsiDiskDevice,
3481 Request->SenseData,
3482 Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),
3483 &Action
3484 );
3485 if (Action == ACTION_RETRY_COMMAND_LATER) {
3486 if (++Request->TimesRetry > MaxRetry) {
3487 Token->TransactionStatus = EFI_DEVICE_ERROR;
3488 goto Exit;
3489 } else {
3490 goto Retry;
3491 }
3492 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
3493 if (Request->SectorCount <= 1) {
3494 //
3495 // Jump out if the operation still fails with one sector transfer
3496 // length.
3497 //
3498 Token->TransactionStatus = EFI_DEVICE_ERROR;
3499 goto Exit;
3500 }
3501 //
3502 // Try again with two half length request if the sense data shows we need
3503 // to retry.
3504 //
3505 Request->SectorCount >>= 1;
3506 Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
3507 Request->TimesRetry = 0;
3508
3509 goto Retry;
3510 } else {
3511 Token->TransactionStatus = EFI_DEVICE_ERROR;
3512 goto Exit;
3513 }
3514 }
3515
3516 //
3517 // This sub-task succeeds, no need to retry.
3518 //
3519 goto Exit;
3520
3521 Retry:
3522 if (Request->InBuffer != NULL) {
3523 //
3524 // SCSI read command
3525 //
3526 if (!ScsiDiskDevice->Cdb16Byte) {
3527 Status = ScsiDiskAsyncRead10 (
3528 ScsiDiskDevice,
3529 Request->Timeout,
3530 Request->InBuffer,
3531 Request->DataLength,
3532 (UINT32) Request->StartLba,
3533 Request->SectorCount,
3534 Request->BlkIo2Req,
3535 Token
3536 );
3537 } else {
3538 Status = ScsiDiskAsyncRead16 (
3539 ScsiDiskDevice,
3540 Request->Timeout,
3541 Request->InBuffer,
3542 Request->DataLength,
3543 Request->StartLba,
3544 Request->SectorCount,
3545 Request->BlkIo2Req,
3546 Token
3547 );
3548 }
3549
3550 if (EFI_ERROR (Status)) {
3551 Token->TransactionStatus = EFI_DEVICE_ERROR;
3552 goto Exit;
3553 } else if (OldSectorCount != Request->SectorCount) {
3554 //
3555 // Original sub-task will be split into two new sub-tasks with smaller
3556 // DataLength
3557 //
3558 if (!ScsiDiskDevice->Cdb16Byte) {
3559 Status = ScsiDiskAsyncRead10 (
3560 ScsiDiskDevice,
3561 Request->Timeout,
3562 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
3563 OldDataLength - Request->DataLength,
3564 (UINT32) Request->StartLba + Request->SectorCount,
3565 OldSectorCount - Request->SectorCount,
3566 Request->BlkIo2Req,
3567 Token
3568 );
3569 } else {
3570 Status = ScsiDiskAsyncRead16 (
3571 ScsiDiskDevice,
3572 Request->Timeout,
3573 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
3574 OldDataLength - Request->DataLength,
3575 Request->StartLba + Request->SectorCount,
3576 OldSectorCount - Request->SectorCount,
3577 Request->BlkIo2Req,
3578 Token
3579 );
3580 }
3581 if (EFI_ERROR (Status)) {
3582 Token->TransactionStatus = EFI_DEVICE_ERROR;
3583 goto Exit;
3584 }
3585 }
3586 } else {
3587 //
3588 // SCSI write command
3589 //
3590 if (!ScsiDiskDevice->Cdb16Byte) {
3591 Status = ScsiDiskAsyncWrite10 (
3592 ScsiDiskDevice,
3593 Request->Timeout,
3594 Request->OutBuffer,
3595 Request->DataLength,
3596 (UINT32) Request->StartLba,
3597 Request->SectorCount,
3598 Request->BlkIo2Req,
3599 Token
3600 );
3601 } else {
3602 Status = ScsiDiskAsyncWrite16 (
3603 ScsiDiskDevice,
3604 Request->Timeout,
3605 Request->OutBuffer,
3606 Request->DataLength,
3607 Request->StartLba,
3608 Request->SectorCount,
3609 Request->BlkIo2Req,
3610 Token
3611 );
3612 }
3613
3614 if (EFI_ERROR (Status)) {
3615 Token->TransactionStatus = EFI_DEVICE_ERROR;
3616 goto Exit;
3617 } else if (OldSectorCount != Request->SectorCount) {
3618 //
3619 // Original sub-task will be split into two new sub-tasks with smaller
3620 // DataLength
3621 //
3622 if (!ScsiDiskDevice->Cdb16Byte) {
3623 Status = ScsiDiskAsyncWrite10 (
3624 ScsiDiskDevice,
3625 Request->Timeout,
3626 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
3627 OldDataLength - Request->DataLength,
3628 (UINT32) Request->StartLba + Request->SectorCount,
3629 OldSectorCount - Request->SectorCount,
3630 Request->BlkIo2Req,
3631 Token
3632 );
3633 } else {
3634 Status = ScsiDiskAsyncWrite16 (
3635 ScsiDiskDevice,
3636 Request->Timeout,
3637 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
3638 OldDataLength - Request->DataLength,
3639 Request->StartLba + Request->SectorCount,
3640 OldSectorCount - Request->SectorCount,
3641 Request->BlkIo2Req,
3642 Token
3643 );
3644 }
3645 if (EFI_ERROR (Status)) {
3646 Token->TransactionStatus = EFI_DEVICE_ERROR;
3647 goto Exit;
3648 }
3649 }
3650 }
3651
3652 Exit:
3653 RemoveEntryList (&Request->Link);
3654 if (IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) {
3655 //
3656 // The last SCSI R/W command of a BlockIo2 request completes
3657 //
3658 RemoveEntryList (&Request->BlkIo2Req->Link);
3659 FreePool (Request->BlkIo2Req); // Should be freed only once
3660 gBS->SignalEvent (Token->Event);
3661 }
3662
3663 FreePool (Request->SenseData);
3664 FreePool (Request);
3665 }
3666
3667
3668 /**
3669 Submit Async Read(10) command.
3670
3671 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3672 @param Timeout The time to complete the command.
3673 @param DataBuffer The buffer to fill with the read out data.
3674 @param DataLength The length of buffer.
3675 @param StartLba The start logic block address.
3676 @param SectorCount The number of blocks to read.
3677 @param BlkIo2Req The upstream BlockIo2 request.
3678 @param Token The pointer to the token associated with the
3679 non-blocking read request.
3680
3681 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3682 lack of resources.
3683 @return others Status returned by calling
3684 ScsiRead10CommandEx().
3685
3686 **/
3687 EFI_STATUS
3688 ScsiDiskAsyncRead10 (
3689 IN SCSI_DISK_DEV *ScsiDiskDevice,
3690 IN UINT64 Timeout,
3691 OUT UINT8 *DataBuffer,
3692 IN UINT32 DataLength,
3693 IN UINT32 StartLba,
3694 IN UINT32 SectorCount,
3695 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
3696 IN EFI_BLOCK_IO2_TOKEN *Token
3697 )
3698 {
3699 EFI_STATUS Status;
3700 SCSI_ASYNC_RW_REQUEST *Request;
3701 EFI_EVENT AsyncIoEvent;
3702
3703 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
3704 if (Request == NULL) {
3705 return EFI_OUT_OF_RESOURCES;
3706 }
3707 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
3708
3709 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
3710 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
3711 if (Request->SenseData == NULL) {
3712 Status = EFI_OUT_OF_RESOURCES;
3713 goto ErrorExit;
3714 }
3715
3716 Request->ScsiDiskDevice = ScsiDiskDevice;
3717 Request->Timeout = Timeout;
3718 Request->InBuffer = DataBuffer;
3719 Request->DataLength = DataLength;
3720 Request->StartLba = StartLba;
3721 Request->SectorCount = SectorCount;
3722 Request->BlkIo2Req = BlkIo2Req;
3723
3724 //
3725 // Create Event
3726 //
3727 Status = gBS->CreateEvent (
3728 EVT_NOTIFY_SIGNAL,
3729 TPL_CALLBACK,
3730 ScsiDiskNotify,
3731 Request,
3732 &AsyncIoEvent
3733 );
3734 if (EFI_ERROR(Status)) {
3735 goto ErrorExit;
3736 }
3737
3738 Status = ScsiRead10CommandEx (
3739 ScsiDiskDevice->ScsiIo,
3740 Request->Timeout,
3741 Request->SenseData,
3742 &Request->SenseDataLength,
3743 &Request->HostAdapterStatus,
3744 &Request->TargetStatus,
3745 Request->InBuffer,
3746 &Request->DataLength,
3747 (UINT32) Request->StartLba,
3748 Request->SectorCount,
3749 AsyncIoEvent
3750 );
3751 if (EFI_ERROR(Status)) {
3752 goto ErrorExit;
3753 }
3754
3755 return EFI_SUCCESS;
3756
3757 ErrorExit:
3758 if (Request != NULL) {
3759 if (Request->SenseData != NULL) {
3760 FreePool (Request->SenseData);
3761 }
3762
3763 RemoveEntryList (&Request->Link);
3764 FreePool (Request);
3765 }
3766
3767 return Status;
3768 }
3769
3770
3771 /**
3772 Submit Async Write(10) command.
3773
3774 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3775 @param Timeout The time to complete the command.
3776 @param DataBuffer The buffer contains the data to write.
3777 @param DataLength The length of buffer.
3778 @param StartLba The start logic block address.
3779 @param SectorCount The number of blocks to write.
3780 @param BlkIo2Req The upstream BlockIo2 request.
3781 @param Token The pointer to the token associated with the
3782 non-blocking read request.
3783
3784 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3785 lack of resources.
3786 @return others Status returned by calling
3787 ScsiWrite10CommandEx().
3788
3789 **/
3790 EFI_STATUS
3791 ScsiDiskAsyncWrite10 (
3792 IN SCSI_DISK_DEV *ScsiDiskDevice,
3793 IN UINT64 Timeout,
3794 IN UINT8 *DataBuffer,
3795 IN UINT32 DataLength,
3796 IN UINT32 StartLba,
3797 IN UINT32 SectorCount,
3798 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
3799 IN EFI_BLOCK_IO2_TOKEN *Token
3800 )
3801 {
3802 EFI_STATUS Status;
3803 SCSI_ASYNC_RW_REQUEST *Request;
3804 EFI_EVENT AsyncIoEvent;
3805
3806 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
3807 if (Request == NULL) {
3808 return EFI_OUT_OF_RESOURCES;
3809 }
3810 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
3811
3812 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
3813 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
3814 if (Request->SenseData == NULL) {
3815 Status = EFI_OUT_OF_RESOURCES;
3816 goto ErrorExit;
3817 }
3818
3819 Request->ScsiDiskDevice = ScsiDiskDevice;
3820 Request->Timeout = Timeout;
3821 Request->OutBuffer = DataBuffer;
3822 Request->DataLength = DataLength;
3823 Request->StartLba = StartLba;
3824 Request->SectorCount = SectorCount;
3825 Request->BlkIo2Req = BlkIo2Req;
3826
3827 //
3828 // Create Event
3829 //
3830 Status = gBS->CreateEvent (
3831 EVT_NOTIFY_SIGNAL,
3832 TPL_CALLBACK,
3833 ScsiDiskNotify,
3834 Request,
3835 &AsyncIoEvent
3836 );
3837 if (EFI_ERROR(Status)) {
3838 goto ErrorExit;
3839 }
3840
3841 Status = ScsiWrite10CommandEx (
3842 ScsiDiskDevice->ScsiIo,
3843 Request->Timeout,
3844 Request->SenseData,
3845 &Request->SenseDataLength,
3846 &Request->HostAdapterStatus,
3847 &Request->TargetStatus,
3848 Request->OutBuffer,
3849 &Request->DataLength,
3850 (UINT32) Request->StartLba,
3851 Request->SectorCount,
3852 AsyncIoEvent
3853 );
3854 if (EFI_ERROR(Status)) {
3855 goto ErrorExit;
3856 }
3857
3858 return EFI_SUCCESS;
3859
3860 ErrorExit:
3861 if (Request != NULL) {
3862 if (Request->SenseData != NULL) {
3863 FreePool (Request->SenseData);
3864 }
3865
3866 RemoveEntryList (&Request->Link);
3867 FreePool (Request);
3868 }
3869
3870 return Status;
3871 }
3872
3873
3874 /**
3875 Submit Async Read(16) command.
3876
3877 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3878 @param Timeout The time to complete the command.
3879 @param DataBuffer The buffer to fill with the read out data.
3880 @param DataLength The length of buffer.
3881 @param StartLba The start logic block address.
3882 @param SectorCount The number of blocks to read.
3883 @param BlkIo2Req The upstream BlockIo2 request.
3884 @param Token The pointer to the token associated with the
3885 non-blocking read request.
3886
3887 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3888 lack of resources.
3889 @return others Status returned by calling
3890 ScsiRead16CommandEx().
3891
3892 **/
3893 EFI_STATUS
3894 ScsiDiskAsyncRead16 (
3895 IN SCSI_DISK_DEV *ScsiDiskDevice,
3896 IN UINT64 Timeout,
3897 OUT UINT8 *DataBuffer,
3898 IN UINT32 DataLength,
3899 IN UINT64 StartLba,
3900 IN UINT32 SectorCount,
3901 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
3902 IN EFI_BLOCK_IO2_TOKEN *Token
3903 )
3904 {
3905 EFI_STATUS Status;
3906 SCSI_ASYNC_RW_REQUEST *Request;
3907 EFI_EVENT AsyncIoEvent;
3908
3909 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
3910 if (Request == NULL) {
3911 return EFI_OUT_OF_RESOURCES;
3912 }
3913 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
3914
3915 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
3916 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
3917 if (Request->SenseData == NULL) {
3918 Status = EFI_OUT_OF_RESOURCES;
3919 goto ErrorExit;
3920 }
3921
3922 Request->ScsiDiskDevice = ScsiDiskDevice;
3923 Request->Timeout = Timeout;
3924 Request->InBuffer = DataBuffer;
3925 Request->DataLength = DataLength;
3926 Request->StartLba = StartLba;
3927 Request->SectorCount = SectorCount;
3928 Request->BlkIo2Req = BlkIo2Req;
3929
3930 //
3931 // Create Event
3932 //
3933 Status = gBS->CreateEvent (
3934 EVT_NOTIFY_SIGNAL,
3935 TPL_CALLBACK,
3936 ScsiDiskNotify,
3937 Request,
3938 &AsyncIoEvent
3939 );
3940 if (EFI_ERROR(Status)) {
3941 goto ErrorExit;
3942 }
3943
3944 Status = ScsiRead16CommandEx (
3945 ScsiDiskDevice->ScsiIo,
3946 Request->Timeout,
3947 Request->SenseData,
3948 &Request->SenseDataLength,
3949 &Request->HostAdapterStatus,
3950 &Request->TargetStatus,
3951 Request->InBuffer,
3952 &Request->DataLength,
3953 Request->StartLba,
3954 Request->SectorCount,
3955 AsyncIoEvent
3956 );
3957 if (EFI_ERROR(Status)) {
3958 goto ErrorExit;
3959 }
3960
3961 return EFI_SUCCESS;
3962
3963 ErrorExit:
3964 if (Request != NULL) {
3965 if (Request->SenseData != NULL) {
3966 FreePool (Request->SenseData);
3967 }
3968
3969 RemoveEntryList (&Request->Link);
3970 FreePool (Request);
3971 }
3972
3973 return Status;
3974 }
3975
3976
3977 /**
3978 Submit Async Write(16) command.
3979
3980 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3981 @param Timeout The time to complete the command.
3982 @param DataBuffer The buffer contains the data to write.
3983 @param DataLength The length of buffer.
3984 @param StartLba The start logic block address.
3985 @param SectorCount The number of blocks to write.
3986 @param BlkIo2Req The upstream BlockIo2 request.
3987 @param Token The pointer to the token associated with the
3988 non-blocking read request.
3989
3990 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3991 lack of resources.
3992 @return others Status returned by calling
3993 ScsiWrite16CommandEx().
3994
3995 **/
3996 EFI_STATUS
3997 ScsiDiskAsyncWrite16 (
3998 IN SCSI_DISK_DEV *ScsiDiskDevice,
3999 IN UINT64 Timeout,
4000 IN UINT8 *DataBuffer,
4001 IN UINT32 DataLength,
4002 IN UINT64 StartLba,
4003 IN UINT32 SectorCount,
4004 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
4005 IN EFI_BLOCK_IO2_TOKEN *Token
4006 )
4007 {
4008 EFI_STATUS Status;
4009 SCSI_ASYNC_RW_REQUEST *Request;
4010 EFI_EVENT AsyncIoEvent;
4011
4012 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
4013 if (Request == NULL) {
4014 return EFI_OUT_OF_RESOURCES;
4015 }
4016 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
4017
4018 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
4019 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
4020 if (Request->SenseData == NULL) {
4021 Status = EFI_OUT_OF_RESOURCES;
4022 goto ErrorExit;
4023 }
4024
4025 Request->ScsiDiskDevice = ScsiDiskDevice;
4026 Request->Timeout = Timeout;
4027 Request->OutBuffer = DataBuffer;
4028 Request->DataLength = DataLength;
4029 Request->StartLba = StartLba;
4030 Request->SectorCount = SectorCount;
4031 Request->BlkIo2Req = BlkIo2Req;
4032
4033 //
4034 // Create Event
4035 //
4036 Status = gBS->CreateEvent (
4037 EVT_NOTIFY_SIGNAL,
4038 TPL_CALLBACK,
4039 ScsiDiskNotify,
4040 Request,
4041 &AsyncIoEvent
4042 );
4043 if (EFI_ERROR(Status)) {
4044 goto ErrorExit;
4045 }
4046
4047 Status = ScsiWrite16CommandEx (
4048 ScsiDiskDevice->ScsiIo,
4049 Request->Timeout,
4050 Request->SenseData,
4051 &Request->SenseDataLength,
4052 &Request->HostAdapterStatus,
4053 &Request->TargetStatus,
4054 Request->OutBuffer,
4055 &Request->DataLength,
4056 Request->StartLba,
4057 Request->SectorCount,
4058 AsyncIoEvent
4059 );
4060 if (EFI_ERROR(Status)) {
4061 goto ErrorExit;
4062 }
4063
4064 return EFI_SUCCESS;
4065
4066 ErrorExit:
4067 if (Request != NULL) {
4068 if (Request->SenseData != NULL) {
4069 FreePool (Request->SenseData);
4070 }
4071
4072 RemoveEntryList (&Request->Link);
4073 FreePool (Request);
4074 }
4075
4076 return Status;
4077 }
4078
4079
4080 /**
4081 Check sense key to find if media presents.
4082
4083 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4084 @param SenseCounts The number of sense key
4085
4086 @retval TRUE NOT any media
4087 @retval FALSE Media presents
4088 **/
4089 BOOLEAN
4090 ScsiDiskIsNoMedia (
4091 IN EFI_SCSI_SENSE_DATA *SenseData,
4092 IN UINTN SenseCounts
4093 )
4094 {
4095 EFI_SCSI_SENSE_DATA *SensePtr;
4096 UINTN Index;
4097 BOOLEAN IsNoMedia;
4098
4099 IsNoMedia = FALSE;
4100 SensePtr = SenseData;
4101
4102 for (Index = 0; Index < SenseCounts; Index++) {
4103 //
4104 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4105 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4106 //
4107 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
4108 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
4109 IsNoMedia = TRUE;
4110 }
4111 SensePtr++;
4112 }
4113
4114 return IsNoMedia;
4115 }
4116
4117
4118 /**
4119 Parse sense key.
4120
4121 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4122 @param SenseCounts The number of sense key
4123
4124 @retval TRUE Error
4125 @retval FALSE NOT error
4126
4127 **/
4128 BOOLEAN
4129 ScsiDiskIsMediaError (
4130 IN EFI_SCSI_SENSE_DATA *SenseData,
4131 IN UINTN SenseCounts
4132 )
4133 {
4134 EFI_SCSI_SENSE_DATA *SensePtr;
4135 UINTN Index;
4136 BOOLEAN IsError;
4137
4138 IsError = FALSE;
4139 SensePtr = SenseData;
4140
4141 for (Index = 0; Index < SenseCounts; Index++) {
4142
4143 switch (SensePtr->Sense_Key) {
4144
4145 case EFI_SCSI_SK_MEDIUM_ERROR:
4146 //
4147 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4148 //
4149 switch (SensePtr->Addnl_Sense_Code) {
4150
4151 //
4152 // fall through
4153 //
4154 case EFI_SCSI_ASC_MEDIA_ERR1:
4155
4156 //
4157 // fall through
4158 //
4159 case EFI_SCSI_ASC_MEDIA_ERR2:
4160
4161 //
4162 // fall through
4163 //
4164 case EFI_SCSI_ASC_MEDIA_ERR3:
4165 case EFI_SCSI_ASC_MEDIA_ERR4:
4166 IsError = TRUE;
4167 break;
4168
4169 default:
4170 break;
4171 }
4172
4173 break;
4174
4175 case EFI_SCSI_SK_NOT_READY:
4176 //
4177 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4178 //
4179 switch (SensePtr->Addnl_Sense_Code) {
4180 //
4181 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4182 //
4183 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
4184 IsError = TRUE;
4185 break;
4186
4187 default:
4188 break;
4189 }
4190 break;
4191
4192 default:
4193 break;
4194 }
4195
4196 SensePtr++;
4197 }
4198
4199 return IsError;
4200 }
4201
4202
4203 /**
4204 Check sense key to find if hardware error happens.
4205
4206 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4207 @param SenseCounts The number of sense key
4208
4209 @retval TRUE Hardware error exits.
4210 @retval FALSE NO error.
4211
4212 **/
4213 BOOLEAN
4214 ScsiDiskIsHardwareError (
4215 IN EFI_SCSI_SENSE_DATA *SenseData,
4216 IN UINTN SenseCounts
4217 )
4218 {
4219 EFI_SCSI_SENSE_DATA *SensePtr;
4220 UINTN Index;
4221 BOOLEAN IsError;
4222
4223 IsError = FALSE;
4224 SensePtr = SenseData;
4225
4226 for (Index = 0; Index < SenseCounts; Index++) {
4227
4228 //
4229 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4230 //
4231 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
4232 IsError = TRUE;
4233 }
4234
4235 SensePtr++;
4236 }
4237
4238 return IsError;
4239 }
4240
4241
4242 /**
4243 Check sense key to find if media has changed.
4244
4245 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4246 @param SenseCounts The number of sense key
4247
4248 @retval TRUE Media is changed.
4249 @retval FALSE Media is NOT changed.
4250 **/
4251 BOOLEAN
4252 ScsiDiskIsMediaChange (
4253 IN EFI_SCSI_SENSE_DATA *SenseData,
4254 IN UINTN SenseCounts
4255 )
4256 {
4257 EFI_SCSI_SENSE_DATA *SensePtr;
4258 UINTN Index;
4259 BOOLEAN IsMediaChanged;
4260
4261 IsMediaChanged = FALSE;
4262 SensePtr = SenseData;
4263
4264 for (Index = 0; Index < SenseCounts; Index++) {
4265 //
4266 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
4267 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
4268 //
4269 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
4270 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
4271 IsMediaChanged = TRUE;
4272 }
4273
4274 SensePtr++;
4275 }
4276
4277 return IsMediaChanged;
4278 }
4279
4280 /**
4281 Check sense key to find if reset happens.
4282
4283 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4284 @param SenseCounts The number of sense key
4285
4286 @retval TRUE It is reset before.
4287 @retval FALSE It is NOT reset before.
4288
4289 **/
4290 BOOLEAN
4291 ScsiDiskIsResetBefore (
4292 IN EFI_SCSI_SENSE_DATA *SenseData,
4293 IN UINTN SenseCounts
4294 )
4295 {
4296 EFI_SCSI_SENSE_DATA *SensePtr;
4297 UINTN Index;
4298 BOOLEAN IsResetBefore;
4299
4300 IsResetBefore = FALSE;
4301 SensePtr = SenseData;
4302
4303 for (Index = 0; Index < SenseCounts; Index++) {
4304
4305 //
4306 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
4307 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
4308 //
4309 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
4310 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
4311 IsResetBefore = TRUE;
4312 }
4313
4314 SensePtr++;
4315 }
4316
4317 return IsResetBefore;
4318 }
4319
4320 /**
4321 Check sense key to find if the drive is ready.
4322
4323 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4324 @param SenseCounts The number of sense key
4325 @param RetryLater The flag means if need a retry
4326
4327 @retval TRUE Drive is ready.
4328 @retval FALSE Drive is NOT ready.
4329
4330 **/
4331 BOOLEAN
4332 ScsiDiskIsDriveReady (
4333 IN EFI_SCSI_SENSE_DATA *SenseData,
4334 IN UINTN SenseCounts,
4335 OUT BOOLEAN *RetryLater
4336 )
4337 {
4338 EFI_SCSI_SENSE_DATA *SensePtr;
4339 UINTN Index;
4340 BOOLEAN IsReady;
4341
4342 IsReady = TRUE;
4343 *RetryLater = FALSE;
4344 SensePtr = SenseData;
4345
4346 for (Index = 0; Index < SenseCounts; Index++) {
4347
4348 switch (SensePtr->Sense_Key) {
4349
4350 case EFI_SCSI_SK_NOT_READY:
4351 //
4352 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4353 //
4354 switch (SensePtr->Addnl_Sense_Code) {
4355 case EFI_SCSI_ASC_NOT_READY:
4356 //
4357 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
4358 //
4359 switch (SensePtr->Addnl_Sense_Code_Qualifier) {
4360 case EFI_SCSI_ASCQ_IN_PROGRESS:
4361 //
4362 // Additional Sense Code Qualifier is
4363 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
4364 //
4365 IsReady = FALSE;
4366 *RetryLater = TRUE;
4367 break;
4368
4369 default:
4370 IsReady = FALSE;
4371 *RetryLater = FALSE;
4372 break;
4373 }
4374 break;
4375
4376 default:
4377 break;
4378 }
4379 break;
4380
4381 default:
4382 break;
4383 }
4384
4385 SensePtr++;
4386 }
4387
4388 return IsReady;
4389 }
4390
4391 /**
4392 Check sense key to find if it has sense key.
4393
4394 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
4395 @param SenseCounts - The number of sense key
4396
4397 @retval TRUE It has sense key.
4398 @retval FALSE It has NOT any sense key.
4399
4400 **/
4401 BOOLEAN
4402 ScsiDiskHaveSenseKey (
4403 IN EFI_SCSI_SENSE_DATA *SenseData,
4404 IN UINTN SenseCounts
4405 )
4406 {
4407 EFI_SCSI_SENSE_DATA *SensePtr;
4408 UINTN Index;
4409 BOOLEAN HaveSenseKey;
4410
4411 if (SenseCounts == 0) {
4412 HaveSenseKey = FALSE;
4413 } else {
4414 HaveSenseKey = TRUE;
4415 }
4416
4417 SensePtr = SenseData;
4418
4419 for (Index = 0; Index < SenseCounts; Index++) {
4420
4421 //
4422 // Sense Key is SK_NO_SENSE (0x0)
4423 //
4424 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
4425 (Index == 0)) {
4426 HaveSenseKey = FALSE;
4427 }
4428
4429 SensePtr++;
4430 }
4431
4432 return HaveSenseKey;
4433 }
4434
4435 /**
4436 Release resource about disk device.
4437
4438 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4439
4440 **/
4441 VOID
4442 ReleaseScsiDiskDeviceResources (
4443 IN SCSI_DISK_DEV *ScsiDiskDevice
4444 )
4445 {
4446 if (ScsiDiskDevice == NULL) {
4447 return ;
4448 }
4449
4450 if (ScsiDiskDevice->SenseData != NULL) {
4451 FreePool (ScsiDiskDevice->SenseData);
4452 ScsiDiskDevice->SenseData = NULL;
4453 }
4454
4455 if (ScsiDiskDevice->ControllerNameTable != NULL) {
4456 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
4457 ScsiDiskDevice->ControllerNameTable = NULL;
4458 }
4459
4460 FreePool (ScsiDiskDevice);
4461
4462 ScsiDiskDevice = NULL;
4463 }
4464
4465 /**
4466 Determine if Block Io & Block Io2 should be produced.
4467
4468
4469 @param ChildHandle Child Handle to retrieve Parent information.
4470
4471 @retval TRUE Should produce Block Io & Block Io2.
4472 @retval FALSE Should not produce Block Io & Block Io2.
4473
4474 **/
4475 BOOLEAN
4476 DetermineInstallBlockIo (
4477 IN EFI_HANDLE ChildHandle
4478 )
4479 {
4480 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
4481 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
4482
4483 //
4484 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
4485 // check its attribute, logic or physical.
4486 //
4487 ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
4488 if (ExtScsiPassThru != NULL) {
4489 if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
4490 return TRUE;
4491 }
4492 }
4493
4494 //
4495 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
4496 // check its attribute, logic or physical.
4497 //
4498 ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
4499 if (ScsiPassThru != NULL) {
4500 if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
4501 return TRUE;
4502 }
4503 }
4504
4505 return FALSE;
4506 }
4507
4508 /**
4509 Search protocol database and check to see if the protocol
4510 specified by ProtocolGuid is present on a ControllerHandle and opened by
4511 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
4512 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
4513 will be opened on it.
4514
4515
4516 @param ProtocolGuid ProtocolGuid pointer.
4517 @param ChildHandle Child Handle to retrieve Parent information.
4518
4519 **/
4520 VOID *
4521 EFIAPI
4522 GetParentProtocol (
4523 IN EFI_GUID *ProtocolGuid,
4524 IN EFI_HANDLE ChildHandle
4525 )
4526 {
4527 UINTN Index;
4528 UINTN HandleCount;
4529 VOID *Interface;
4530 EFI_STATUS Status;
4531 EFI_HANDLE *HandleBuffer;
4532
4533 //
4534 // Retrieve the list of all handles from the handle database
4535 //
4536 Status = gBS->LocateHandleBuffer (
4537 ByProtocol,
4538 ProtocolGuid,
4539 NULL,
4540 &HandleCount,
4541 &HandleBuffer
4542 );
4543
4544 if (EFI_ERROR (Status)) {
4545 return NULL;
4546 }
4547
4548 //
4549 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
4550 //
4551 for (Index = 0; Index < HandleCount; Index++) {
4552 Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
4553 if (!EFI_ERROR (Status)) {
4554 Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
4555 if (!EFI_ERROR (Status)) {
4556 gBS->FreePool (HandleBuffer);
4557 return Interface;
4558 }
4559 }
4560 }
4561
4562 gBS->FreePool (HandleBuffer);
4563 return NULL;
4564 }
4565
4566 /**
4567 Provides inquiry information for the controller type.
4568
4569 This function is used by the IDE bus driver to get inquiry data. Data format
4570 of Identify data is defined by the Interface GUID.
4571
4572 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4573 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
4574 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
4575
4576 @retval EFI_SUCCESS The command was accepted without any errors.
4577 @retval EFI_NOT_FOUND Device does not support this data class
4578 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
4579 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
4580
4581 **/
4582 EFI_STATUS
4583 EFIAPI
4584 ScsiDiskInfoInquiry (
4585 IN EFI_DISK_INFO_PROTOCOL *This,
4586 IN OUT VOID *InquiryData,
4587 IN OUT UINT32 *InquiryDataSize
4588 )
4589 {
4590 EFI_STATUS Status;
4591 SCSI_DISK_DEV *ScsiDiskDevice;
4592
4593 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
4594
4595 Status = EFI_BUFFER_TOO_SMALL;
4596 if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
4597 Status = EFI_SUCCESS;
4598 CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
4599 }
4600 *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
4601 return Status;
4602 }
4603
4604
4605 /**
4606 Provides identify information for the controller type.
4607
4608 This function is used by the IDE bus driver to get identify data. Data format
4609 of Identify data is defined by the Interface GUID.
4610
4611 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
4612 instance.
4613 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
4614 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
4615 size.
4616
4617 @retval EFI_SUCCESS The command was accepted without any errors.
4618 @retval EFI_NOT_FOUND Device does not support this data class
4619 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
4620 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
4621
4622 **/
4623 EFI_STATUS
4624 EFIAPI
4625 ScsiDiskInfoIdentify (
4626 IN EFI_DISK_INFO_PROTOCOL *This,
4627 IN OUT VOID *IdentifyData,
4628 IN OUT UINT32 *IdentifyDataSize
4629 )
4630 {
4631 EFI_STATUS Status;
4632 SCSI_DISK_DEV *ScsiDiskDevice;
4633
4634 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
4635 //
4636 // Physical SCSI bus does not support this data class.
4637 //
4638 return EFI_NOT_FOUND;
4639 }
4640
4641 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
4642
4643 Status = EFI_BUFFER_TOO_SMALL;
4644 if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
4645 Status = EFI_SUCCESS;
4646 CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
4647 }
4648 *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
4649 return Status;
4650 }
4651
4652 /**
4653 Provides sense data information for the controller type.
4654
4655 This function is used by the IDE bus driver to get sense data.
4656 Data format of Sense data is defined by the Interface GUID.
4657
4658 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4659 @param[in, out] SenseData Pointer to the SenseData.
4660 @param[in, out] SenseDataSize Size of SenseData in bytes.
4661 @param[out] SenseDataNumber Pointer to the value for the sense data size.
4662
4663 @retval EFI_SUCCESS The command was accepted without any errors.
4664 @retval EFI_NOT_FOUND Device does not support this data class.
4665 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
4666 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
4667
4668 **/
4669 EFI_STATUS
4670 EFIAPI
4671 ScsiDiskInfoSenseData (
4672 IN EFI_DISK_INFO_PROTOCOL *This,
4673 IN OUT VOID *SenseData,
4674 IN OUT UINT32 *SenseDataSize,
4675 OUT UINT8 *SenseDataNumber
4676 )
4677 {
4678 return EFI_NOT_FOUND;
4679 }
4680
4681
4682 /**
4683 This function is used by the IDE bus driver to get controller information.
4684
4685 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4686 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
4687 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
4688
4689 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
4690 @retval EFI_UNSUPPORTED This is not an IDE device.
4691
4692 **/
4693 EFI_STATUS
4694 EFIAPI
4695 ScsiDiskInfoWhichIde (
4696 IN EFI_DISK_INFO_PROTOCOL *This,
4697 OUT UINT32 *IdeChannel,
4698 OUT UINT32 *IdeDevice
4699 )
4700 {
4701 SCSI_DISK_DEV *ScsiDiskDevice;
4702
4703 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
4704 //
4705 // This is not an IDE physical device.
4706 //
4707 return EFI_UNSUPPORTED;
4708 }
4709
4710 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
4711 *IdeChannel = ScsiDiskDevice->Channel;
4712 *IdeDevice = ScsiDiskDevice->Device;
4713
4714 return EFI_SUCCESS;
4715 }
4716
4717
4718 /**
4719 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
4720
4721 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
4722 implement Identify() interface for DiskInfo protocol. The ATA command is sent
4723 via SCSI Request Packet.
4724
4725 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4726
4727 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
4728 @retval others Some error occurred during the identification that ATAPI device.
4729
4730 **/
4731 EFI_STATUS
4732 AtapiIdentifyDevice (
4733 IN OUT SCSI_DISK_DEV *ScsiDiskDevice
4734 )
4735 {
4736 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
4737 UINT8 Cdb[6];
4738
4739 //
4740 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
4741 //
4742 ZeroMem (&CommandPacket, sizeof (CommandPacket));
4743 ZeroMem (Cdb, sizeof (Cdb));
4744
4745 Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
4746 CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
4747 CommandPacket.Cdb = Cdb;
4748 CommandPacket.CdbLength = (UINT8) sizeof (Cdb);
4749 CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
4750 CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
4751
4752 return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
4753 }
4754
4755
4756 /**
4757 Initialize the installation of DiskInfo protocol.
4758
4759 This function prepares for the installation of DiskInfo protocol on the child handle.
4760 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
4761 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
4762 to be IDE/AHCI interface GUID.
4763
4764 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
4765 @param ChildHandle Child handle to install DiskInfo protocol.
4766
4767 **/
4768 VOID
4769 InitializeInstallDiskInfo (
4770 IN SCSI_DISK_DEV *ScsiDiskDevice,
4771 IN EFI_HANDLE ChildHandle
4772 )
4773 {
4774 EFI_STATUS Status;
4775 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
4776 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;
4777 ATAPI_DEVICE_PATH *AtapiDevicePath;
4778 SATA_DEVICE_PATH *SataDevicePath;
4779 UINTN IdentifyRetry;
4780
4781 Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);
4782 //
4783 // Device Path protocol must be installed on the device handle.
4784 //
4785 ASSERT_EFI_ERROR (Status);
4786 //
4787 // Copy the DiskInfo protocol template.
4788 //
4789 CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
4790
4791 while (!IsDevicePathEnd (DevicePathNode)) {
4792 ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
4793 if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
4794 (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
4795 (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
4796 ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
4797 (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {
4798
4799 IdentifyRetry = 3;
4800 do {
4801 //
4802 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
4803 // with IDE/AHCI interface GUID.
4804 //
4805 Status = AtapiIdentifyDevice (ScsiDiskDevice);
4806 if (!EFI_ERROR (Status)) {
4807 if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {
4808 //
4809 // We find the valid ATAPI device path
4810 //
4811 AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;
4812 ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
4813 ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
4814 //
4815 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
4816 //
4817 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
4818 } else {
4819 //
4820 // We find the valid SATA device path
4821 //
4822 SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;
4823 ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
4824 ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
4825 //
4826 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
4827 //
4828 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
4829 }
4830 return;
4831 }
4832 } while (--IdentifyRetry > 0);
4833 } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
4834 (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP)) {
4835 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);
4836 break;
4837 }
4838 DevicePathNode = ChildDevicePathNode;
4839 }
4840
4841 return;
4842 }