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