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