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