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