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