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