2 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
3 SPDX-License-Identifier: BSD-2-Clause-Patent
7 #include "AtapiPassThru.h"
10 SCSI_COMMAND_SET gEndTable
= { 0xff, (DATA_DIRECTION
) 0xff };
13 /// This table contains all the supported ATAPI commands.
15 SCSI_COMMAND_SET gSupportedATAPICommands
[] = {
16 { OP_INQUIRY
, DataIn
},
17 { OP_LOAD_UNLOAD_CD
, NoData
},
18 { OP_MECHANISM_STATUS
, DataIn
},
19 { OP_MODE_SELECT_10
, DataOut
},
20 { OP_MODE_SENSE_10
, DataIn
},
21 { OP_PAUSE_RESUME
, NoData
},
22 { OP_PLAY_AUDIO_10
, DataIn
},
23 { OP_PLAY_AUDIO_MSF
, DataIn
},
24 { OP_PLAY_CD
, DataIn
},
25 { OP_PLAY_CD_MSF
, DataIn
},
26 { OP_PREVENT_ALLOW_MEDIUM_REMOVAL
,NoData
},
27 { OP_READ_10
, DataIn
},
28 { OP_READ_12
, DataIn
},
29 { OP_READ_CAPACITY
, DataIn
},
30 { OP_READ_CD
, DataIn
},
31 { OP_READ_CD_MSF
, DataIn
},
32 { OP_READ_HEADER
, DataIn
},
33 { OP_READ_SUB_CHANNEL
, DataIn
},
34 { OP_READ_TOC
, DataIn
},
35 { OP_REQUEST_SENSE
, DataIn
},
37 { OP_SEEK_10
, NoData
},
38 { OP_SET_CD_SPEED
, DataOut
},
39 { OP_STOPPLAY_SCAN
, NoData
},
40 { OP_START_STOP_UNIT
, NoData
},
41 { OP_TEST_UNIT_READY
, NoData
},
42 { OP_FORMAT_UNIT
, DataOut
},
43 { OP_READ_FORMAT_CAPACITIES
, DataIn
},
44 { OP_VERIFY
, DataOut
},
45 { OP_WRITE_10
, DataOut
},
46 { OP_WRITE_12
, DataOut
},
47 { OP_WRITE_AND_VERIFY
, DataOut
},
48 { 0xff, (DATA_DIRECTION
) 0xff }
51 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_MODE gScsiPassThruMode
= {
55 EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
,
59 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_PROTOCOL gScsiPassThruProtocolTemplate
= {
61 AtapiScsiPassThruFunction
,
62 AtapiScsiPassThruGetNextDevice
,
63 AtapiScsiPassThruBuildDevicePath
,
64 AtapiScsiPassThruGetTargetLun
,
65 AtapiScsiPassThruResetChannel
,
66 AtapiScsiPassThruResetTarget
69 GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_MODE gExtScsiPassThruMode
= {
71 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
,
75 GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_PROTOCOL gExtScsiPassThruProtocolTemplate
= {
76 &gExtScsiPassThruMode
,
77 AtapiExtScsiPassThruFunction
,
78 AtapiExtScsiPassThruGetNextTargetLun
,
79 AtapiExtScsiPassThruBuildDevicePath
,
80 AtapiExtScsiPassThruGetTargetLun
,
81 AtapiExtScsiPassThruResetChannel
,
82 AtapiExtScsiPassThruResetTarget
,
83 AtapiExtScsiPassThruGetNextTarget
86 EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding
= {
87 AtapiScsiPassThruDriverBindingSupported
,
88 AtapiScsiPassThruDriverBindingStart
,
89 AtapiScsiPassThruDriverBindingStop
,
97 AtapiScsiPassThruDriverBindingSupported (
98 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
99 IN EFI_HANDLE Controller
,
100 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
105 Test to see if this driver supports ControllerHandle. Any ControllerHandle
106 that has gEfiPciIoProtocolGuid installed and is IDE Controller it will be supported.
110 This - Protocol instance pointer.
111 Controller - Handle of device to test
112 RemainingDevicePath - Not used
120 EFI_PCI_IO_PROTOCOL
*PciIo
;
125 // Open the IO Abstraction(s) needed to perform the supported test
127 Status
= gBS
->OpenProtocol (
129 &gEfiPciIoProtocolGuid
,
131 This
->DriverBindingHandle
,
133 EFI_OPEN_PROTOCOL_BY_DRIVER
135 if (EFI_ERROR (Status
)) {
139 // Use the PCI I/O Protocol to see if Controller is a IDE Controller that
140 // can be managed by this driver. Read the PCI Configuration Header
143 Status
= PciIo
->Pci
.Read (
147 sizeof (Pci
) / sizeof (UINT32
),
150 if (EFI_ERROR (Status
)) {
153 &gEfiPciIoProtocolGuid
,
154 This
->DriverBindingHandle
,
157 return EFI_UNSUPPORTED
;
160 if (Pci
.Hdr
.ClassCode
[2] != PCI_CLASS_MASS_STORAGE
|| Pci
.Hdr
.ClassCode
[1] != PCI_CLASS_MASS_STORAGE_IDE
) {
162 Status
= EFI_UNSUPPORTED
;
167 &gEfiPciIoProtocolGuid
,
168 This
->DriverBindingHandle
,
177 AtapiScsiPassThruDriverBindingStart (
178 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
179 IN EFI_HANDLE Controller
,
180 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
185 Create handles for IDE channels specified by RemainingDevicePath.
186 Install SCSI Pass Thru Protocol onto each created handle.
190 This - Protocol instance pointer.
191 Controller - Handle of device to test
192 RemainingDevicePath - Not used
200 EFI_PCI_IO_PROTOCOL
*PciIo
;
202 UINT64 OriginalPciAttributes
;
203 BOOLEAN PciAttributesSaved
;
206 Status
= gBS
->OpenProtocol (
208 &gEfiPciIoProtocolGuid
,
210 This
->DriverBindingHandle
,
212 EFI_OPEN_PROTOCOL_BY_DRIVER
214 if (EFI_ERROR (Status
)) {
218 PciAttributesSaved
= FALSE
;
220 // Save original PCI attributes
222 Status
= PciIo
->Attributes (
224 EfiPciIoAttributeOperationGet
,
226 &OriginalPciAttributes
229 if (EFI_ERROR (Status
)) {
232 PciAttributesSaved
= TRUE
;
234 Status
= PciIo
->Attributes (
236 EfiPciIoAttributeOperationSupported
,
240 if (!EFI_ERROR (Status
)) {
241 Supports
&= (EFI_PCI_DEVICE_ENABLE
|
242 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
|
243 EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
);
244 Status
= PciIo
->Attributes (
246 EfiPciIoAttributeOperationEnable
,
251 if (EFI_ERROR (Status
)) {
256 // Create SCSI Pass Thru instance for the IDE channel.
258 Status
= RegisterAtapiScsiPassThru (This
, Controller
, PciIo
, OriginalPciAttributes
);
261 if (EFI_ERROR (Status
)) {
262 if (PciAttributesSaved
== TRUE
) {
264 // Restore original PCI attributes
268 EfiPciIoAttributeOperationSet
,
269 OriginalPciAttributes
,
276 &gEfiPciIoProtocolGuid
,
277 This
->DriverBindingHandle
,
287 AtapiScsiPassThruDriverBindingStop (
288 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
289 IN EFI_HANDLE Controller
,
290 IN UINTN NumberOfChildren
,
291 IN EFI_HANDLE
*ChildHandleBuffer
297 Stop this driver on ControllerHandle. Support stopping any child handles
298 created by this driver.
302 This - Protocol instance pointer.
303 Controller - Handle of device to stop driver on
304 NumberOfChildren - Number of Children in the ChildHandleBuffer
305 ChildHandleBuffer - List of handles for the children we need to stop.
314 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
315 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
316 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
318 if (FeaturePcdGet (PcdSupportScsiPassThru
)) {
319 Status
= gBS
->OpenProtocol (
321 &gEfiScsiPassThruProtocolGuid
,
322 (VOID
**) &ScsiPassThru
,
323 This
->DriverBindingHandle
,
325 EFI_OPEN_PROTOCOL_GET_PROTOCOL
327 if (EFI_ERROR (Status
)) {
330 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru
);
331 if (FeaturePcdGet (PcdSupportExtScsiPassThru
)) {
332 Status
= gBS
->UninstallMultipleProtocolInterfaces (
334 &gEfiScsiPassThruProtocolGuid
,
335 &AtapiScsiPrivate
->ScsiPassThru
,
336 &gEfiExtScsiPassThruProtocolGuid
,
337 &AtapiScsiPrivate
->ExtScsiPassThru
,
341 Status
= gBS
->UninstallMultipleProtocolInterfaces (
343 &gEfiScsiPassThruProtocolGuid
,
344 &AtapiScsiPrivate
->ScsiPassThru
,
349 Status
= gBS
->OpenProtocol (
351 &gEfiExtScsiPassThruProtocolGuid
,
352 (VOID
**) &ExtScsiPassThru
,
353 This
->DriverBindingHandle
,
355 EFI_OPEN_PROTOCOL_GET_PROTOCOL
357 if (EFI_ERROR (Status
)) {
360 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (ExtScsiPassThru
);
361 Status
= gBS
->UninstallMultipleProtocolInterfaces (
363 &gEfiExtScsiPassThruProtocolGuid
,
364 &AtapiScsiPrivate
->ExtScsiPassThru
,
368 if (EFI_ERROR (Status
)) {
373 // Restore original PCI attributes
375 AtapiScsiPrivate
->PciIo
->Attributes (
376 AtapiScsiPrivate
->PciIo
,
377 EfiPciIoAttributeOperationSet
,
378 AtapiScsiPrivate
->OriginalPciAttributes
,
384 &gEfiPciIoProtocolGuid
,
385 This
->DriverBindingHandle
,
389 gBS
->FreePool (AtapiScsiPrivate
);
395 RegisterAtapiScsiPassThru (
396 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
397 IN EFI_HANDLE Controller
,
398 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
399 IN UINT64 OriginalPciAttributes
404 Attaches SCSI Pass Thru Protocol for specified IDE channel.
407 This - Protocol instance pointer.
408 Controller - Parent device handle to the IDE channel.
409 PciIo - PCI I/O protocol attached on the "Controller".
412 Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.
417 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
418 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[ATAPI_MAX_CHANNEL
];
420 AtapiScsiPrivate
= AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV
));
421 if (AtapiScsiPrivate
== NULL
) {
422 return EFI_OUT_OF_RESOURCES
;
425 AtapiScsiPrivate
->Signature
= ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE
;
426 AtapiScsiPrivate
->Handle
= Controller
;
429 // will reset the IoPort inside each API function.
431 AtapiScsiPrivate
->IoPort
= NULL
;
432 AtapiScsiPrivate
->PciIo
= PciIo
;
433 AtapiScsiPrivate
->OriginalPciAttributes
= OriginalPciAttributes
;
436 // Obtain IDE IO port registers' base addresses
438 Status
= GetIdeRegistersBaseAddr (PciIo
, IdeRegsBaseAddr
);
439 if (EFI_ERROR (Status
)) {
443 InitAtapiIoPortRegisters(AtapiScsiPrivate
, IdeRegsBaseAddr
);
446 // Initialize the LatestTargetId to MAX_TARGET_ID.
448 AtapiScsiPrivate
->LatestTargetId
= MAX_TARGET_ID
;
449 AtapiScsiPrivate
->LatestLun
= 0;
451 Status
= InstallScsiPassThruProtocols (&Controller
, AtapiScsiPrivate
);
458 AtapiScsiPassThruFunction (
459 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
462 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
463 IN EFI_EVENT Event OPTIONAL
469 Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
473 This: The EFI_SCSI_PASS_THRU_PROTOCOL instance.
474 Target: The Target ID of the ATAPI device to send the SCSI
475 Request Packet. To ATAPI devices attached on an IDE
476 Channel, Target ID 0 indicates Master device;Target
477 ID 1 indicates Slave device.
478 Lun: The LUN of the ATAPI device to send the SCSI Request
479 Packet. To the ATAPI device, Lun is always 0.
480 Packet: The SCSI Request Packet to send to the ATAPI device
481 specified by Target and Lun.
482 Event: If non-blocking I/O is not supported then Event is ignored,
483 and blocking I/O is performed.
484 If Event is NULL, then blocking I/O is performed.
485 If Event is not NULL and non blocking I/O is supported,
486 then non-blocking I/O is performed, and Event will be signaled
487 when the SCSI Request Packet completes.
495 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
498 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
501 // Target is not allowed beyond MAX_TARGET_ID
503 if ((Target
> MAX_TARGET_ID
) || (Lun
!= 0)) {
504 return EFI_INVALID_PARAMETER
;
508 // check the data fields in Packet parameter.
510 Status
= CheckSCSIRequestPacket (Packet
);
511 if (EFI_ERROR (Status
)) {
516 // If Request Packet targets at the IDE channel itself,
519 if (Target
== This
->Mode
->AdapterId
) {
520 Packet
->TransferLength
= 0;
525 // According to Target ID, reset the Atapi I/O Register mapping
526 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
527 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
529 if ((Target
/ 2) == 0) {
531 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
534 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
538 // the ATAPI SCSI interface does not support non-blocking I/O
539 // ignore the Event parameter
541 // Performs blocking I/O.
543 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, Packet
);
549 AtapiScsiPassThruGetNextDevice (
550 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
551 IN OUT UINT32
*Target
,
558 Used to retrieve the list of legal Target IDs for SCSI devices
563 This - Protocol instance pointer.
564 Target - On input, a pointer to the Target ID of a SCSI
565 device present on the SCSI channel. On output,
566 a pointer to the Target ID of the next SCSI device
567 present on a SCSI channel. An input value of
568 0xFFFFFFFF retrieves the Target ID of the first
569 SCSI device present on a SCSI channel.
570 Lun - On input, a pointer to the LUN of a SCSI device
571 present on the SCSI channel. On output, a pointer
572 to the LUN of the next SCSI device present on
576 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
577 on the SCSI channel was returned in Target and Lun.
578 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
579 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
580 returned on a previous call to GetNextDevice().
583 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
586 // Retrieve Device Private Data Structure.
588 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
591 // Check whether Target is valid.
593 if (Target
== NULL
|| Lun
== NULL
) {
594 return EFI_INVALID_PARAMETER
;
597 if ((*Target
!= 0xFFFFFFFF) &&
598 ((*Target
!= AtapiScsiPrivate
->LatestTargetId
) ||
599 (*Lun
!= AtapiScsiPrivate
->LatestLun
))) {
600 return EFI_INVALID_PARAMETER
;
603 if (*Target
== MAX_TARGET_ID
) {
604 return EFI_NOT_FOUND
;
607 if (*Target
== 0xFFFFFFFF) {
610 *Target
= AtapiScsiPrivate
->LatestTargetId
+ 1;
616 // Update the LatestTargetId.
618 AtapiScsiPrivate
->LatestTargetId
= *Target
;
619 AtapiScsiPrivate
->LatestLun
= *Lun
;
627 AtapiScsiPassThruBuildDevicePath (
628 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
631 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
637 Used to allocate and build a device path node for a SCSI device
638 on a SCSI channel. Would not build device path for a SCSI Host Controller.
642 This - Protocol instance pointer.
643 Target - The Target ID of the SCSI device for which
644 a device path node is to be allocated and built.
645 Lun - The LUN of the SCSI device for which a device
646 path node is to be allocated and built.
647 DevicePath - A pointer to a single device path node that
648 describes the SCSI device specified by
649 Target and Lun. This function is responsible
650 for allocating the buffer DevicePath with the boot
651 service AllocatePool(). It is the caller's
652 responsibility to free DevicePath when the caller
653 is finished with DevicePath.
655 EFI_SUCCESS - The device path node that describes the SCSI device
656 specified by Target and Lun was allocated and
657 returned in DevicePath.
658 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
659 not exist on the SCSI channel.
660 EFI_INVALID_PARAMETER - DevicePath is NULL.
661 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
669 // Validate parameters passed in.
672 if (DevicePath
== NULL
) {
673 return EFI_INVALID_PARAMETER
;
677 // can not build device path for the SCSI Host Controller.
679 if ((Target
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
680 return EFI_NOT_FOUND
;
683 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
685 return EFI_OUT_OF_RESOURCES
;
688 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
689 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
690 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
692 Node
->Atapi
.PrimarySecondary
= (UINT8
) (Target
/ 2);
693 Node
->Atapi
.SlaveMaster
= (UINT8
) (Target
% 2);
694 Node
->Atapi
.Lun
= (UINT16
) Lun
;
696 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
703 AtapiScsiPassThruGetTargetLun (
704 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
705 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
713 Used to translate a device path node to a Target ID and LUN.
717 This - Protocol instance pointer.
718 DevicePath - A pointer to the device path node that
719 describes a SCSI device on the SCSI channel.
720 Target - A pointer to the Target ID of a SCSI device
722 Lun - A pointer to the LUN of a SCSI device on
726 EFI_SUCCESS - DevicePath was successfully translated to a
727 Target ID and LUN, and they were returned
729 EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
730 EFI_UNSUPPORTED - This driver does not support the device path
731 node type in DevicePath.
732 EFI_NOT_FOUND - A valid translation from DevicePath to a
733 Target ID and LUN does not exist.
739 // Validate parameters passed in.
741 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
742 return EFI_INVALID_PARAMETER
;
746 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
748 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
749 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
750 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
751 return EFI_UNSUPPORTED
;
754 Node
= (EFI_DEV_PATH
*) DevicePath
;
756 *Target
= Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
;
757 *Lun
= Node
->Atapi
.Lun
;
759 if (*Target
> (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
760 return EFI_NOT_FOUND
;
768 AtapiScsiPassThruResetChannel (
769 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
775 Resets a SCSI channel.This operation resets all the
776 SCSI devices connected to the SCSI channel.
780 This - Protocol instance pointer.
784 EFI_SUCCESS - The SCSI channel was reset.
785 EFI_UNSUPPORTED - The SCSI channel does not support
786 a channel reset operation.
787 EFI_DEVICE_ERROR - A device error occurred while
788 attempting to reset the SCSI channel.
789 EFI_TIMEOUT - A timeout occurred while attempting
790 to reset the SCSI channel.
793 UINT8 DeviceControlValue
;
794 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
798 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
802 // Reset both Primary channel and Secondary channel.
803 // so, the IoPort pointer must point to the right I/O Register group
805 for (Index
= 0; Index
< 2; Index
++) {
809 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[Index
];
811 DeviceControlValue
= 0;
813 // set SRST bit to initiate soft reset
815 DeviceControlValue
|= SRST
;
819 DeviceControlValue
|= BIT1
;
821 AtapiScsiPrivate
->PciIo
,
822 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
835 DeviceControlValue
&= 0xfb;
837 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
840 // slave device needs at most 31s to clear BSY
842 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000) != EFI_TIMEOUT
) {
856 AtapiScsiPassThruResetTarget (
857 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
865 Resets a SCSI device that is connected to a SCSI channel.
869 This - Protocol instance pointer.
870 Target - The Target ID of the SCSI device to reset.
871 Lun - The LUN of the SCSI device to reset.
875 EFI_SUCCESS - The SCSI device specified by Target and
877 EFI_UNSUPPORTED - The SCSI channel does not support a target
879 EFI_INVALID_PARAMETER - Target or Lun are invalid.
880 EFI_DEVICE_ERROR - A device error occurred while attempting
881 to reset the SCSI device specified by Target
883 EFI_TIMEOUT - A timeout occurred while attempting to reset
884 the SCSI device specified by Target and Lun.
887 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
891 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
893 if ((Target
> MAX_TARGET_ID
) || (Lun
!= 0)) {
894 return EFI_INVALID_PARAMETER
;
897 // Directly return EFI_SUCCESS if want to reset the host controller
899 if (Target
== This
->Mode
->AdapterId
) {
904 // According to Target ID, reset the Atapi I/O Register mapping
905 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
906 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
908 if ((Target
/ 2) == 0) {
909 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
911 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
915 // for ATAPI device, no need to wait DRDY ready after device selecting.
917 // bit7 and bit5 are both set to 1 for backward compatibility
919 DeviceSelect
= (UINT8
) (((BIT7
| BIT5
) | (Target
<< 4)));
920 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
922 Command
= ATAPI_SOFT_RESET_CMD
;
923 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
926 // BSY clear is the only status return to the host by the device
927 // when reset is complete.
928 // slave device needs at most 31s to clear BSY
930 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000))) {
935 // stall 5 seconds to make the device status stable
937 gBS
->Stall (5000000);
944 AtapiExtScsiPassThruFunction (
945 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
948 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
949 IN EFI_EVENT Event OPTIONAL
955 Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
959 This: The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
960 Target: The Target ID of the ATAPI device to send the SCSI
961 Request Packet. To ATAPI devices attached on an IDE
962 Channel, Target ID 0 indicates Master device;Target
963 ID 1 indicates Slave device.
964 Lun: The LUN of the ATAPI device to send the SCSI Request
965 Packet. To the ATAPI device, Lun is always 0.
966 Packet: The SCSI Request Packet to send to the ATAPI device
967 specified by Target and Lun.
968 Event: If non-blocking I/O is not supported then Event is ignored,
969 and blocking I/O is performed.
970 If Event is NULL, then blocking I/O is performed.
971 If Event is not NULL and non blocking I/O is supported,
972 then non-blocking I/O is performed, and Event will be signaled
973 when the SCSI Request Packet completes.
982 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
985 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
988 // For ATAPI device, UINT8 is enough to represent the SCSI ID on channel.
990 TargetId
= Target
[0];
993 // Target is not allowed beyond MAX_TARGET_ID
995 if ((TargetId
> MAX_TARGET_ID
) || (Lun
!= 0)) {
996 return EFI_INVALID_PARAMETER
;
1000 // check the data fields in Packet parameter.
1002 Status
= CheckExtSCSIRequestPacket (Packet
);
1003 if (EFI_ERROR (Status
)) {
1008 // If Request Packet targets at the IDE channel itself,
1011 if (TargetId
== (UINT8
)This
->Mode
->AdapterId
) {
1012 Packet
->InTransferLength
= Packet
->OutTransferLength
= 0;
1017 // According to Target ID, reset the Atapi I/O Register mapping
1018 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
1019 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
1021 if ((TargetId
/ 2) == 0) {
1022 TargetId
= (UINT8
) (TargetId
% 2);
1023 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
1025 TargetId
= (UINT8
) (TargetId
% 2);
1026 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
1030 // the ATAPI SCSI interface does not support non-blocking I/O
1031 // ignore the Event parameter
1033 // Performs blocking I/O.
1035 Status
= SubmitExtBlockingIoCommand (AtapiScsiPrivate
, TargetId
, Packet
);
1041 AtapiExtScsiPassThruGetNextTargetLun (
1042 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1043 IN OUT UINT8
**Target
,
1048 Routine Description:
1050 Used to retrieve the list of legal Target IDs for SCSI devices
1055 This - Protocol instance pointer.
1056 Target - On input, a pointer to the Target ID of a SCSI
1057 device present on the SCSI channel. On output,
1058 a pointer to the Target ID of the next SCSI device
1059 present on a SCSI channel. An input value of
1060 0xFFFFFFFF retrieves the Target ID of the first
1061 SCSI device present on a SCSI channel.
1062 Lun - On input, a pointer to the LUN of a SCSI device
1063 present on the SCSI channel. On output, a pointer
1064 to the LUN of the next SCSI device present on
1068 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
1069 on the SCSI channel was returned in Target and Lun.
1070 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
1071 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
1072 returned on a previous call to GetNextDevice().
1077 UINT8 ScsiId
[TARGET_MAX_BYTES
];
1078 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1081 // Retrieve Device Private Data Structure.
1083 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1086 // Check whether Target is valid.
1088 if (*Target
== NULL
|| Lun
== NULL
) {
1089 return EFI_INVALID_PARAMETER
;
1092 SetMem (ScsiId
, TARGET_MAX_BYTES
, 0xFF);
1094 TargetId
= (*Target
)[0];
1097 // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
1099 if (CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) {
1100 for (ByteIndex
= 1; ByteIndex
< TARGET_MAX_BYTES
; ByteIndex
++) {
1101 if ((*Target
)[ByteIndex
] != 0) {
1102 return EFI_INVALID_PARAMETER
;
1107 if ((CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) &&
1108 ((TargetId
!= AtapiScsiPrivate
->LatestTargetId
) ||
1109 (*Lun
!= AtapiScsiPrivate
->LatestLun
))) {
1110 return EFI_INVALID_PARAMETER
;
1113 if (TargetId
== MAX_TARGET_ID
) {
1114 return EFI_NOT_FOUND
;
1117 if (CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) == 0) {
1118 SetMem (*Target
, TARGET_MAX_BYTES
,0);
1120 (*Target
)[0] = (UINT8
) (AtapiScsiPrivate
->LatestTargetId
+ 1);
1126 // Update the LatestTargetId.
1128 AtapiScsiPrivate
->LatestTargetId
= (*Target
)[0];
1129 AtapiScsiPrivate
->LatestLun
= *Lun
;
1137 AtapiExtScsiPassThruBuildDevicePath (
1138 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1141 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
1145 Routine Description:
1147 Used to allocate and build a device path node for a SCSI device
1148 on a SCSI channel. Would not build device path for a SCSI Host Controller.
1152 This - Protocol instance pointer.
1153 Target - The Target ID of the SCSI device for which
1154 a device path node is to be allocated and built.
1155 Lun - The LUN of the SCSI device for which a device
1156 path node is to be allocated and built.
1157 DevicePath - A pointer to a single device path node that
1158 describes the SCSI device specified by
1159 Target and Lun. This function is responsible
1160 for allocating the buffer DevicePath with the boot
1161 service AllocatePool(). It is the caller's
1162 responsibility to free DevicePath when the caller
1163 is finished with DevicePath.
1165 EFI_SUCCESS - The device path node that describes the SCSI device
1166 specified by Target and Lun was allocated and
1167 returned in DevicePath.
1168 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
1169 not exist on the SCSI channel.
1170 EFI_INVALID_PARAMETER - DevicePath is NULL.
1171 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
1178 TargetId
= Target
[0];
1181 // Validate parameters passed in.
1184 if (DevicePath
== NULL
) {
1185 return EFI_INVALID_PARAMETER
;
1189 // can not build device path for the SCSI Host Controller.
1191 if ((TargetId
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
1192 return EFI_NOT_FOUND
;
1195 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
1197 return EFI_OUT_OF_RESOURCES
;
1200 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
1201 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
1202 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
1204 Node
->Atapi
.PrimarySecondary
= (UINT8
) (TargetId
/ 2);
1205 Node
->Atapi
.SlaveMaster
= (UINT8
) (TargetId
% 2);
1206 Node
->Atapi
.Lun
= (UINT16
) Lun
;
1208 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
1215 AtapiExtScsiPassThruGetTargetLun (
1216 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1217 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1223 Routine Description:
1225 Used to translate a device path node to a Target ID and LUN.
1229 This - Protocol instance pointer.
1230 DevicePath - A pointer to the device path node that
1231 describes a SCSI device on the SCSI channel.
1232 Target - A pointer to the Target ID of a SCSI device
1233 on the SCSI channel.
1234 Lun - A pointer to the LUN of a SCSI device on
1238 EFI_SUCCESS - DevicePath was successfully translated to a
1239 Target ID and LUN, and they were returned
1241 EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
1242 EFI_UNSUPPORTED - This driver does not support the device path
1243 node type in DevicePath.
1244 EFI_NOT_FOUND - A valid translation from DevicePath to a
1245 Target ID and LUN does not exist.
1251 // Validate parameters passed in.
1253 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
1254 return EFI_INVALID_PARAMETER
;
1258 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
1260 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
1261 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
1262 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
1263 return EFI_UNSUPPORTED
;
1266 ZeroMem (*Target
, TARGET_MAX_BYTES
);
1268 Node
= (EFI_DEV_PATH
*) DevicePath
;
1270 (*Target
)[0] = (UINT8
) (Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
);
1271 *Lun
= Node
->Atapi
.Lun
;
1273 if ((*Target
)[0] > (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
1274 return EFI_NOT_FOUND
;
1282 AtapiExtScsiPassThruResetChannel (
1283 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
1287 Routine Description:
1289 Resets a SCSI channel.This operation resets all the
1290 SCSI devices connected to the SCSI channel.
1294 This - Protocol instance pointer.
1298 EFI_SUCCESS - The SCSI channel was reset.
1299 EFI_UNSUPPORTED - The SCSI channel does not support
1300 a channel reset operation.
1301 EFI_DEVICE_ERROR - A device error occurred while
1302 attempting to reset the SCSI channel.
1303 EFI_TIMEOUT - A timeout occurred while attempting
1304 to reset the SCSI channel.
1307 UINT8 DeviceControlValue
;
1309 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1312 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1315 // Reset both Primary channel and Secondary channel.
1316 // so, the IoPort pointer must point to the right I/O Register group
1317 // And if there is a channel reset successfully, return EFI_SUCCESS.
1319 for (Index
= 0; Index
< 2; Index
++) {
1323 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[Index
];
1325 DeviceControlValue
= 0;
1327 // set SRST bit to initiate soft reset
1329 DeviceControlValue
|= SRST
;
1331 // disable Interrupt
1333 DeviceControlValue
|= BIT1
;
1335 AtapiScsiPrivate
->PciIo
,
1336 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
1349 DeviceControlValue
&= 0xfb;
1351 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
1354 // slave device needs at most 31s to clear BSY
1356 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000) != EFI_TIMEOUT
) {
1370 AtapiExtScsiPassThruResetTarget (
1371 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1377 Routine Description:
1379 Resets a SCSI device that is connected to a SCSI channel.
1383 This - Protocol instance pointer.
1384 Target - The Target ID of the SCSI device to reset.
1385 Lun - The LUN of the SCSI device to reset.
1389 EFI_SUCCESS - The SCSI device specified by Target and
1391 EFI_UNSUPPORTED - The SCSI channel does not support a target
1393 EFI_INVALID_PARAMETER - Target or Lun are invalid.
1394 EFI_DEVICE_ERROR - A device error occurred while attempting
1395 to reset the SCSI device specified by Target
1397 EFI_TIMEOUT - A timeout occurred while attempting to reset
1398 the SCSI device specified by Target and Lun.
1404 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1406 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1407 TargetId
= Target
[0];
1409 if ((TargetId
> MAX_TARGET_ID
) || (Lun
!= 0)) {
1410 return EFI_INVALID_PARAMETER
;
1413 // Directly return EFI_SUCCESS if want to reset the host controller
1415 if (TargetId
== This
->Mode
->AdapterId
) {
1420 // According to Target ID, reset the Atapi I/O Register mapping
1421 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
1422 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
1424 if ((TargetId
/ 2) == 0) {
1425 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
1427 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
1431 // for ATAPI device, no need to wait DRDY ready after device selecting.
1433 // bit7 and bit5 are both set to 1 for backward compatibility
1435 DeviceSelect
= (UINT8
) ((BIT7
| BIT5
) | (TargetId
<< 4));
1436 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
1438 Command
= ATAPI_SOFT_RESET_CMD
;
1439 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
1442 // BSY clear is the only status return to the host by the device
1443 // when reset is complete.
1444 // slave device needs at most 31s to clear BSY
1446 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000))) {
1451 // stall 5 seconds to make the device status stable
1453 gBS
->Stall (5000000);
1461 AtapiExtScsiPassThruGetNextTarget (
1462 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1463 IN OUT UINT8
**Target
1467 Routine Description:
1468 Used to retrieve the list of legal Target IDs for SCSI devices
1472 This - Protocol instance pointer.
1473 Target - On input, a pointer to the Target ID of a SCSI
1474 device present on the SCSI channel. On output,
1475 a pointer to the Target ID of the next SCSI device
1476 present on a SCSI channel. An input value of
1477 0xFFFFFFFF retrieves the Target ID of the first
1478 SCSI device present on a SCSI channel.
1479 Lun - On input, a pointer to the LUN of a SCSI device
1480 present on the SCSI channel. On output, a pointer
1481 to the LUN of the next SCSI device present on
1485 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
1486 on the SCSI channel was returned in Target and Lun.
1487 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
1488 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
1489 returned on a previous call to GetNextDevice().
1493 UINT8 ScsiId
[TARGET_MAX_BYTES
];
1494 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1498 // Retrieve Device Private Data Structure.
1500 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1503 // Check whether Target is valid.
1505 if (*Target
== NULL
) {
1506 return EFI_INVALID_PARAMETER
;
1509 TargetId
= (*Target
)[0];
1510 SetMem (ScsiId
, TARGET_MAX_BYTES
, 0xFF);
1513 // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
1515 if (CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) {
1516 for (ByteIndex
= 1; ByteIndex
< TARGET_MAX_BYTES
; ByteIndex
++) {
1517 if ((*Target
)[ByteIndex
] != 0) {
1518 return EFI_INVALID_PARAMETER
;
1523 if ((CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) &&(TargetId
!= AtapiScsiPrivate
->LatestTargetId
)) {
1524 return EFI_INVALID_PARAMETER
;
1527 if (TargetId
== MAX_TARGET_ID
) {
1528 return EFI_NOT_FOUND
;
1531 if ((CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) == 0)) {
1532 SetMem (*Target
, TARGET_MAX_BYTES
, 0);
1534 (*Target
)[0] = (UINT8
) (AtapiScsiPrivate
->LatestTargetId
+ 1);
1538 // Update the LatestTargetId.
1540 AtapiScsiPrivate
->LatestTargetId
= (*Target
)[0];
1541 AtapiScsiPrivate
->LatestLun
= 0;
1547 GetIdeRegistersBaseAddr (
1548 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1549 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
1553 Routine Description:
1554 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
1555 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
1556 the PCI IDE controller's Configuration Space.
1559 PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance
1560 IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to
1561 receive IDE IO port registers' base addresses
1572 Status
= PciIo
->Pci
.Read (
1580 if (EFI_ERROR (Status
)) {
1584 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
1585 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
1586 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
1589 // The BARs should be of IO type
1591 if ((PciData
.Device
.Bar
[0] & BIT0
) == 0 ||
1592 (PciData
.Device
.Bar
[1] & BIT0
) == 0) {
1593 return EFI_UNSUPPORTED
;
1596 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
1597 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
1598 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
1599 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
1602 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
1603 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
1604 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
1607 // The BARs should be of IO type
1609 if ((PciData
.Device
.Bar
[2] & BIT0
) == 0 ||
1610 (PciData
.Device
.Bar
[3] & BIT0
) == 0) {
1611 return EFI_UNSUPPORTED
;
1614 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
1615 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
1616 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
1617 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
1624 InitAtapiIoPortRegisters (
1625 IN ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1626 IN IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
1630 Routine Description:
1632 Initialize each Channel's Base Address of CommandBlock and ControlBlock.
1636 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
1637 IdeRegsBaseAddr - The pointer of IDE_REGISTERS_BASE_ADDR
1647 UINT16 CommandBlockBaseAddr
;
1648 UINT16 ControlBlockBaseAddr
;
1649 IDE_BASE_REGISTERS
*RegisterPointer
;
1652 for (IdeChannel
= 0; IdeChannel
< ATAPI_MAX_CHANNEL
; IdeChannel
++) {
1654 RegisterPointer
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[IdeChannel
];
1657 // Initialize IDE IO port addresses, including Command Block registers
1658 // and Control Block registers
1660 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeChannel
].CommandBlockBaseAddr
;
1661 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeChannel
].ControlBlockBaseAddr
;
1663 RegisterPointer
->Data
= CommandBlockBaseAddr
;
1664 (*(UINT16
*) &RegisterPointer
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
1665 RegisterPointer
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
1666 RegisterPointer
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
1667 RegisterPointer
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
1668 RegisterPointer
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
1669 RegisterPointer
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
1670 (*(UINT16
*) &RegisterPointer
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
1672 (*(UINT16
*) &RegisterPointer
->Alt
) = ControlBlockBaseAddr
;
1673 RegisterPointer
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
1680 CheckSCSIRequestPacket (
1681 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1685 Routine Description:
1687 Checks the parameters in the SCSI Request Packet to make sure
1688 they are valid for a SCSI Pass Thru request.
1692 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1700 if (Packet
== NULL
) {
1701 return EFI_INVALID_PARAMETER
;
1704 if (!ValidCdbLength (Packet
->CdbLength
)) {
1705 return EFI_INVALID_PARAMETER
;
1708 if (Packet
->Cdb
== NULL
) {
1709 return EFI_INVALID_PARAMETER
;
1713 // Checks whether the request command is supported.
1715 if (!IsCommandValid (Packet
)) {
1716 return EFI_UNSUPPORTED
;
1724 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1728 Routine Description:
1730 Checks the requested SCSI command:
1731 Is it supported by this driver?
1732 Is the Data transfer direction reasonable?
1736 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1748 OpCode
= (UINT8
*) (Packet
->Cdb
);
1749 ArrayLen
= (UINT8
) (ARRAY_SIZE (gSupportedATAPICommands
));
1751 for (Index
= 0; (Index
< ArrayLen
) && (CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)) != 0); Index
++) {
1753 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
1755 // Check whether the requested Command is supported by this driver
1757 if (Packet
->DataDirection
== DataIn
) {
1759 // Check whether the requested data direction conforms to
1760 // what it should be.
1762 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
1767 if (Packet
->DataDirection
== DataOut
) {
1769 // Check whether the requested data direction conforms to
1770 // what it should be.
1772 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
1785 SubmitBlockingIoCommand (
1786 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1788 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1792 Routine Description:
1794 Performs blocking I/O request.
1798 AtapiScsiPrivate: Private data structure for the specified channel.
1799 Target: The Target ID of the ATAPI device to send the SCSI
1800 Request Packet. To ATAPI devices attached on an IDE
1801 Channel, Target ID 0 indicates Master device;Target
1802 ID 1 indicates Slave device.
1803 Packet: The SCSI Request Packet to send to the ATAPI device
1804 specified by Target.
1810 UINT8 PacketCommand
[12];
1811 UINT64 TimeoutInMicroSeconds
;
1812 EFI_STATUS PacketCommandStatus
;
1815 // Fill ATAPI Command Packet according to CDB
1817 ZeroMem (&PacketCommand
, 12);
1818 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
1821 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
1823 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
1826 // Submit ATAPI Command Packet
1828 PacketCommandStatus
= AtapiPacketCommand (
1833 &(Packet
->TransferLength
),
1834 (DATA_DIRECTION
) Packet
->DataDirection
,
1835 TimeoutInMicroSeconds
1837 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
1838 Packet
->SenseDataLength
= 0;
1839 return PacketCommandStatus
;
1843 // Return SenseData if PacketCommandStatus matches
1844 // the following return codes.
1846 if ((PacketCommandStatus
== EFI_BAD_BUFFER_SIZE
) ||
1847 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
1848 (PacketCommandStatus
== EFI_TIMEOUT
)) {
1851 // avoid submit request sense command continuously.
1853 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
1854 Packet
->SenseDataLength
= 0;
1855 return PacketCommandStatus
;
1858 RequestSenseCommand (
1863 &Packet
->SenseDataLength
1867 return PacketCommandStatus
;
1871 RequestSenseCommand (
1872 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1876 UINT8
*SenseDataLength
1880 Routine Description:
1882 Submit request sense command
1886 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
1887 Target - The target ID
1888 Timeout - The time to complete the command
1889 SenseData - The buffer to fill in sense data
1890 SenseDataLength - The length of buffer
1898 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet
;
1902 ZeroMem (&Packet
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1905 Cdb
[0] = OP_REQUEST_SENSE
;
1906 Cdb
[4] = (UINT8
) (*SenseDataLength
);
1908 Packet
.Timeout
= Timeout
;
1909 Packet
.DataBuffer
= SenseData
;
1910 Packet
.SenseData
= NULL
;
1912 Packet
.TransferLength
= *SenseDataLength
;
1913 Packet
.CdbLength
= 12;
1914 Packet
.DataDirection
= DataIn
;
1916 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, &Packet
);
1917 *SenseDataLength
= (UINT8
) (Packet
.TransferLength
);
1922 CheckExtSCSIRequestPacket (
1923 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1927 Routine Description:
1929 Checks the parameters in the SCSI Request Packet to make sure
1930 they are valid for a SCSI Pass Thru request.
1934 Packet - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1942 if (Packet
== NULL
) {
1943 return EFI_INVALID_PARAMETER
;
1946 if (!ValidCdbLength (Packet
->CdbLength
)) {
1947 return EFI_INVALID_PARAMETER
;
1950 if (Packet
->Cdb
== NULL
) {
1951 return EFI_INVALID_PARAMETER
;
1955 // Checks whether the request command is supported.
1957 if (!IsExtCommandValid (Packet
)) {
1958 return EFI_UNSUPPORTED
;
1967 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1971 Routine Description:
1973 Checks the requested SCSI command:
1974 Is it supported by this driver?
1975 Is the Data transfer direction reasonable?
1979 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1991 OpCode
= (UINT8
*) (Packet
->Cdb
);
1992 ArrayLen
= (UINT8
) (ARRAY_SIZE (gSupportedATAPICommands
));
1994 for (Index
= 0; (Index
< ArrayLen
) && (CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)) != 0); Index
++) {
1996 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
1998 // Check whether the requested Command is supported by this driver
2000 if (Packet
->DataDirection
== DataIn
) {
2002 // Check whether the requested data direction conforms to
2003 // what it should be.
2005 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
2010 if (Packet
->DataDirection
== DataOut
) {
2012 // Check whether the requested data direction conforms to
2013 // what it should be.
2015 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
2028 SubmitExtBlockingIoCommand (
2029 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2031 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
2035 Routine Description:
2037 Performs blocking I/O request.
2041 AtapiScsiPrivate: Private data structure for the specified channel.
2042 Target: The Target ID of the ATAPI device to send the SCSI
2043 Request Packet. To ATAPI devices attached on an IDE
2044 Channel, Target ID 0 indicates Master device;Target
2045 ID 1 indicates Slave device.
2046 Packet: The SCSI Request Packet to send to the ATAPI device
2047 specified by Target.
2053 UINT8 PacketCommand
[12];
2054 UINT64 TimeoutInMicroSeconds
;
2055 EFI_STATUS PacketCommandStatus
;
2058 // Fill ATAPI Command Packet according to CDB
2060 ZeroMem (&PacketCommand
, 12);
2061 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
2064 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
2066 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
2069 // Submit ATAPI Command Packet
2071 if (Packet
->DataDirection
== DataIn
) {
2072 PacketCommandStatus
= AtapiPacketCommand (
2076 Packet
->InDataBuffer
,
2077 &(Packet
->InTransferLength
),
2079 TimeoutInMicroSeconds
2083 PacketCommandStatus
= AtapiPacketCommand (
2087 Packet
->OutDataBuffer
,
2088 &(Packet
->OutTransferLength
),
2090 TimeoutInMicroSeconds
2094 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
2095 Packet
->SenseDataLength
= 0;
2096 return PacketCommandStatus
;
2100 // Return SenseData if PacketCommandStatus matches
2101 // the following return codes.
2103 if ((PacketCommandStatus
== EFI_BAD_BUFFER_SIZE
) ||
2104 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
2105 (PacketCommandStatus
== EFI_TIMEOUT
)) {
2108 // avoid submit request sense command continuously.
2110 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
2111 Packet
->SenseDataLength
= 0;
2112 return PacketCommandStatus
;
2115 RequestSenseCommand (
2120 &Packet
->SenseDataLength
2124 return PacketCommandStatus
;
2129 AtapiPacketCommand (
2130 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2132 UINT8
*PacketCommand
,
2135 DATA_DIRECTION Direction
,
2136 UINT64 TimeoutInMicroSeconds
2140 Routine Description:
2142 Submits ATAPI command packet to the specified ATAPI device.
2146 AtapiScsiPrivate: Private data structure for the specified channel.
2147 Target: The Target ID of the ATAPI device to send the SCSI
2148 Request Packet. To ATAPI devices attached on an IDE
2149 Channel, Target ID 0 indicates Master device;Target
2150 ID 1 indicates Slave device.
2151 PacketCommand: Points to the ATAPI command packet.
2152 Buffer: Points to the transferred data.
2153 ByteCount: When input,indicates the buffer size; when output,
2154 indicates the actually transferred data size.
2155 Direction: Indicates the data transfer direction.
2156 TimeoutInMicroSeconds:
2157 The timeout, in micro second units, to use for the
2158 execution of this ATAPI command.
2159 A TimeoutInMicroSeconds value of 0 means that
2160 this function will wait indefinitely for the ATAPI
2162 If TimeoutInMicroSeconds is greater than zero, then
2163 this function will return EFI_TIMEOUT if the time
2164 required to execute the ATAPI command is greater
2165 than TimeoutInMicroSeconds.
2174 UINT16
*CommandIndex
;
2179 // Set all the command parameters by fill related registers.
2180 // Before write to all the following registers, BSY must be 0.
2182 Status
= StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2183 if (EFI_ERROR (Status
)) {
2184 return EFI_DEVICE_ERROR
;
2189 // Select device via Device/Head Register.
2190 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
2193 AtapiScsiPrivate
->PciIo
,
2194 AtapiScsiPrivate
->IoPort
->Head
,
2195 (UINT8
) ((Target
<< 4) | DEFAULT_CMD
) // DEFAULT_CMD: 0xa0 (1010,0000)
2199 // Set all the command parameters by fill related registers.
2200 // Before write to all the following registers, BSY DRQ must be 0.
2202 Status
= StatusDRQClear(AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2204 if (EFI_ERROR (Status
)) {
2205 if (Status
== EFI_ABORTED
) {
2206 Status
= EFI_DEVICE_ERROR
;
2213 // No OVL; No DMA (by setting feature register)
2216 AtapiScsiPrivate
->PciIo
,
2217 AtapiScsiPrivate
->IoPort
->Reg1
.Feature
,
2222 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
2223 // determine how much data should be transfered.
2226 AtapiScsiPrivate
->PciIo
,
2227 AtapiScsiPrivate
->IoPort
->CylinderLsb
,
2228 (UINT8
) (MAX_ATAPI_BYTE_COUNT
& 0x00ff)
2231 AtapiScsiPrivate
->PciIo
,
2232 AtapiScsiPrivate
->IoPort
->CylinderMsb
,
2233 (UINT8
) (MAX_ATAPI_BYTE_COUNT
>> 8)
2237 // DEFAULT_CTL:0x0a (0000,1010)
2238 // Disable interrupt
2241 AtapiScsiPrivate
->PciIo
,
2242 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
2247 // Send Packet command to inform device
2248 // that the following data bytes are command packet.
2251 AtapiScsiPrivate
->PciIo
,
2252 AtapiScsiPrivate
->IoPort
->Reg
.Command
,
2257 // Before data transfer, BSY should be 0 and DRQ should be 1.
2258 // if they are not in specified time frame,
2259 // retrieve Sense Key from Error Register before return.
2261 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2262 if (EFI_ERROR (Status
)) {
2263 if (Status
== EFI_ABORTED
) {
2264 Status
= EFI_DEVICE_ERROR
;
2272 // Send out command packet
2274 CommandIndex
= (UINT16
*) PacketCommand
;
2275 for (Count
= 0; Count
< 6; Count
++, CommandIndex
++) {
2276 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *CommandIndex
);
2280 // call AtapiPassThruPioReadWriteData() function to get
2281 // requested transfer data form device.
2283 return AtapiPassThruPioReadWriteData (
2288 TimeoutInMicroSeconds
2293 AtapiPassThruPioReadWriteData (
2294 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2297 DATA_DIRECTION Direction
,
2298 UINT64 TimeoutInMicroSeconds
2302 Routine Description:
2304 Performs data transfer between ATAPI device and host after the
2305 ATAPI command packet is sent.
2309 AtapiScsiPrivate: Private data structure for the specified channel.
2310 Buffer: Points to the transferred data.
2311 ByteCount: When input,indicates the buffer size; when output,
2312 indicates the actually transferred data size.
2313 Direction: Indicates the data transfer direction.
2314 TimeoutInMicroSeconds:
2315 The timeout, in micro second units, to use for the
2316 execution of this ATAPI command.
2317 A TimeoutInMicroSeconds value of 0 means that
2318 this function will wait indefinitely for the ATAPI
2320 If TimeoutInMicroSeconds is greater than zero, then
2321 this function will return EFI_TIMEOUT if the time
2322 required to execute the ATAPI command is greater
2323 than TimeoutInMicroSeconds.
2331 UINT32 RequiredWordCount
;
2332 UINT32 ActualWordCount
;
2337 Status
= EFI_SUCCESS
;
2340 // Non Data transfer request is also supported.
2342 if (*ByteCount
== 0 || Buffer
== NULL
) {
2344 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
))) {
2345 return EFI_DEVICE_ERROR
;
2350 RequiredWordCount
= *ByteCount
/ 2;
2353 // ActuralWordCount means the word count of data really transfered.
2355 ActualWordCount
= 0;
2357 while (ActualWordCount
< RequiredWordCount
) {
2359 // before each data transfer stream, the host should poll DRQ bit ready,
2360 // which indicates device's ready for data transfer .
2362 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2363 if (EFI_ERROR (Status
)) {
2364 *ByteCount
= ActualWordCount
* 2;
2366 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
2368 if (ActualWordCount
== 0) {
2369 return EFI_DEVICE_ERROR
;
2372 // ActualWordCount > 0
2374 if (ActualWordCount
< RequiredWordCount
) {
2375 return EFI_BAD_BUFFER_SIZE
;
2379 // get current data transfer size from Cylinder Registers.
2381 WordCount
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderMsb
) << 8;
2382 WordCount
= WordCount
| ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderLsb
);
2383 WordCount
= WordCount
& 0xffff;
2387 // perform a series data In/Out.
2389 for (Index
= 0; (Index
< WordCount
) && (ActualWordCount
< RequiredWordCount
); Index
++, ActualWordCount
++) {
2391 if (Direction
== DataIn
) {
2393 *ptrBuffer
= ReadPortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
);
2396 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *ptrBuffer
);
2404 // After data transfer is completed, normally, DRQ bit should clear.
2406 StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2409 // read status register to check whether error happens.
2411 Status
= AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
2413 *ByteCount
= ActualWordCount
* 2;
2421 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2426 Routine Description:
2428 Read one byte from a specified I/O port.
2432 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2447 EFI_PCI_IO_PASS_THROUGH_BAR
,
2458 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2463 Routine Description:
2465 Read one word from a specified I/O port.
2469 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2482 EfiPciIoWidthUint16
,
2483 EFI_PCI_IO_PASS_THROUGH_BAR
,
2494 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2500 Routine Description:
2502 Write one byte to a specified I/O port.
2506 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2508 Data - The data to write
2519 EFI_PCI_IO_PASS_THROUGH_BAR
,
2529 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2535 Routine Description:
2537 Write one word to a specified I/O port.
2541 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2543 Data - The data to write
2553 EfiPciIoWidthUint16
,
2554 EFI_PCI_IO_PASS_THROUGH_BAR
,
2563 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2564 UINT64 TimeoutInMicroSeconds
2568 Routine Description:
2570 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
2571 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2572 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2577 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2578 TimeoutInMicroSeconds - The time to wait for
2587 UINT8 StatusRegister
;
2590 if (TimeoutInMicroSeconds
== 0) {
2593 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2598 StatusRegister
= ReadPortB (
2599 AtapiScsiPrivate
->PciIo
,
2600 AtapiScsiPrivate
->IoPort
->Reg
.Status
2604 // wait for BSY == 0 and DRQ == 0
2606 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
2610 // check whether the command is aborted by the device
2612 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
2614 ErrRegister
= ReadPortB (
2615 AtapiScsiPrivate
->PciIo
,
2616 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2618 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2629 // Loop infinitely if not meeting expected condition
2631 if (TimeoutInMicroSeconds
== 0) {
2647 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2648 UINT64 TimeoutInMicroSeconds
2652 Routine Description:
2654 Check whether DRQ is clear in the Alternate Status Register.
2655 (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should
2656 wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2661 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2662 TimeoutInMicroSeconds - The time to wait for
2671 UINT8 AltStatusRegister
;
2674 if (TimeoutInMicroSeconds
== 0) {
2677 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2682 AltStatusRegister
= ReadPortB (
2683 AtapiScsiPrivate
->PciIo
,
2684 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2688 // wait for BSY == 0 and DRQ == 0
2690 if ((AltStatusRegister
& (DRQ
| BSY
)) == 0) {
2694 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2696 ErrRegister
= ReadPortB (
2697 AtapiScsiPrivate
->PciIo
,
2698 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2700 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2711 // Loop infinitely if not meeting expected condition
2713 if (TimeoutInMicroSeconds
== 0) {
2729 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2730 UINT64 TimeoutInMicroSeconds
2734 Routine Description:
2736 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
2737 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2738 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2743 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2744 TimeoutInMicroSeconds - The time to wait for
2753 UINT8 StatusRegister
;
2756 if (TimeoutInMicroSeconds
== 0) {
2759 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2764 // read Status Register will clear interrupt
2766 StatusRegister
= ReadPortB (
2767 AtapiScsiPrivate
->PciIo
,
2768 AtapiScsiPrivate
->IoPort
->Reg
.Status
2774 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
2778 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
2780 ErrRegister
= ReadPortB (
2781 AtapiScsiPrivate
->PciIo
,
2782 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2784 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2795 // Loop infinitely if not meeting expected condition
2797 if (TimeoutInMicroSeconds
== 0) {
2813 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2814 UINT64 TimeoutInMicroSeconds
2818 Routine Description:
2820 Check whether DRQ is ready in the Alternate Status Register.
2821 (BSY must also be cleared)
2822 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2823 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2828 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2829 TimeoutInMicroSeconds - The time to wait for
2838 UINT8 AltStatusRegister
;
2841 if (TimeoutInMicroSeconds
== 0) {
2844 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2849 // read Status Register will clear interrupt
2851 AltStatusRegister
= ReadPortB (
2852 AtapiScsiPrivate
->PciIo
,
2853 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2858 if ((AltStatusRegister
& (BSY
| DRQ
)) == DRQ
) {
2862 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2864 ErrRegister
= ReadPortB (
2865 AtapiScsiPrivate
->PciIo
,
2866 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2868 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2879 // Loop infinitely if not meeting expected condition
2881 if (TimeoutInMicroSeconds
== 0) {
2896 StatusWaitForBSYClear (
2897 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2898 UINT64 TimeoutInMicroSeconds
2902 Routine Description:
2904 Check whether BSY is clear in the Status Register.
2905 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2906 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2911 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2912 TimeoutInMicroSeconds - The time to wait for
2921 UINT8 StatusRegister
;
2923 if (TimeoutInMicroSeconds
== 0) {
2926 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2931 StatusRegister
= ReadPortB (
2932 AtapiScsiPrivate
->PciIo
,
2933 AtapiScsiPrivate
->IoPort
->Reg
.Status
2935 if ((StatusRegister
& BSY
) == 0x00) {
2945 // Loop infinitely if not meeting expected condition
2947 if (TimeoutInMicroSeconds
== 0) {
2962 AltStatusWaitForBSYClear (
2963 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2964 UINT64 TimeoutInMicroSeconds
2968 Routine Description:
2970 Check whether BSY is clear in the Alternate Status Register.
2971 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2972 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2977 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2978 TimeoutInMicroSeconds - The time to wait for
2987 UINT8 AltStatusRegister
;
2989 if (TimeoutInMicroSeconds
== 0) {
2992 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2997 AltStatusRegister
= ReadPortB (
2998 AtapiScsiPrivate
->PciIo
,
2999 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
3001 if ((AltStatusRegister
& BSY
) == 0x00) {
3010 // Loop infinitely if not meeting expected condition
3012 if (TimeoutInMicroSeconds
== 0) {
3028 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
3029 UINT64 TimeoutInMicroSeconds
3033 Routine Description:
3035 Check whether DRDY is ready in the Status Register.
3036 (BSY must also be cleared)
3037 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
3038 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
3043 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3044 TimeoutInMicroSeconds - The time to wait for
3053 UINT8 StatusRegister
;
3056 if (TimeoutInMicroSeconds
== 0) {
3059 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
3063 StatusRegister
= ReadPortB (
3064 AtapiScsiPrivate
->PciIo
,
3065 AtapiScsiPrivate
->IoPort
->Reg
.Status
3068 // BSY == 0 , DRDY == 1
3070 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
3074 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
3076 ErrRegister
= ReadPortB (
3077 AtapiScsiPrivate
->PciIo
,
3078 AtapiScsiPrivate
->IoPort
->Reg1
.Error
3080 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
3090 // Loop infinitely if not meeting expected condition
3092 if (TimeoutInMicroSeconds
== 0) {
3107 AltStatusDRDYReady (
3108 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
3109 UINT64 TimeoutInMicroSeconds
3113 Routine Description:
3115 Check whether DRDY is ready in the Alternate Status Register.
3116 (BSY must also be cleared)
3117 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
3118 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
3123 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3124 TimeoutInMicroSeconds - The time to wait for
3133 UINT8 AltStatusRegister
;
3136 if (TimeoutInMicroSeconds
== 0) {
3139 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
3143 AltStatusRegister
= ReadPortB (
3144 AtapiScsiPrivate
->PciIo
,
3145 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
3148 // BSY == 0 , DRDY == 1
3150 if ((AltStatusRegister
& (DRDY
| BSY
)) == DRDY
) {
3154 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
3156 ErrRegister
= ReadPortB (
3157 AtapiScsiPrivate
->PciIo
,
3158 AtapiScsiPrivate
->IoPort
->Reg1
.Error
3160 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
3170 // Loop infinitely if not meeting expected condition
3172 if (TimeoutInMicroSeconds
== 0) {
3187 AtapiPassThruCheckErrorStatus (
3188 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
3192 Routine Description:
3194 Check Error Register for Error Information.
3198 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3206 UINT8 StatusRegister
;
3207 UINT8 ErrorRegister
;
3209 StatusRegister
= ReadPortB (
3210 AtapiScsiPrivate
->PciIo
,
3211 AtapiScsiPrivate
->IoPort
->Reg
.Status
3214 DEBUG_CODE_BEGIN ();
3216 if (StatusRegister
& DWF
) {
3219 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
3224 if (StatusRegister
& CORR
) {
3227 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
3232 if (StatusRegister
& ERR
) {
3233 ErrorRegister
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg1
.Error
);
3236 if (ErrorRegister
& BBK_ERR
) {
3239 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
3244 if (ErrorRegister
& UNC_ERR
) {
3247 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
3252 if (ErrorRegister
& MC_ERR
) {
3255 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
3260 if (ErrorRegister
& ABRT_ERR
) {
3263 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
3268 if (ErrorRegister
& TK0NF_ERR
) {
3271 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
3276 if (ErrorRegister
& AMNF_ERR
) {
3279 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
3287 if ((StatusRegister
& (ERR
| DWF
| CORR
)) == 0) {
3292 return EFI_DEVICE_ERROR
;
3297 Installs Scsi Pass Thru and/or Ext Scsi Pass Thru
3298 protocols based on feature flags.
3300 @param Controller The controller handle to
3301 install these protocols on.
3302 @param AtapiScsiPrivate A pointer to the protocol private
3305 @retval EFI_SUCCESS The installation succeeds.
3306 @retval other The installation fails.
3310 InstallScsiPassThruProtocols (
3311 IN EFI_HANDLE
*ControllerHandle
,
3312 IN ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
3316 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
3317 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
3319 ScsiPassThru
= &AtapiScsiPrivate
->ScsiPassThru
;
3320 ExtScsiPassThru
= &AtapiScsiPrivate
->ExtScsiPassThru
;
3322 if (FeaturePcdGet (PcdSupportScsiPassThru
)) {
3323 ScsiPassThru
= CopyMem (ScsiPassThru
, &gScsiPassThruProtocolTemplate
, sizeof (*ScsiPassThru
));
3324 if (FeaturePcdGet (PcdSupportExtScsiPassThru
)) {
3325 ExtScsiPassThru
= CopyMem (ExtScsiPassThru
, &gExtScsiPassThruProtocolTemplate
, sizeof (*ExtScsiPassThru
));
3326 Status
= gBS
->InstallMultipleProtocolInterfaces (
3328 &gEfiScsiPassThruProtocolGuid
,
3330 &gEfiExtScsiPassThruProtocolGuid
,
3335 Status
= gBS
->InstallMultipleProtocolInterfaces (
3337 &gEfiScsiPassThruProtocolGuid
,
3343 if (FeaturePcdGet (PcdSupportExtScsiPassThru
)) {
3344 ExtScsiPassThru
= CopyMem (ExtScsiPassThru
, &gExtScsiPassThruProtocolTemplate
, sizeof (*ExtScsiPassThru
));
3345 Status
= gBS
->InstallMultipleProtocolInterfaces (
3347 &gEfiExtScsiPassThruProtocolGuid
,
3353 // This driver must support either ScsiPassThru or
3354 // ExtScsiPassThru protocols
3357 Status
= EFI_UNSUPPORTED
;
3365 The user Entry Point for module AtapiPassThru. The user code starts with this function.
3367 @param[in] ImageHandle The firmware allocated handle for the EFI image.
3368 @param[in] SystemTable A pointer to the EFI System Table.
3370 @retval EFI_SUCCESS The entry point is executed successfully.
3371 @retval other Some error occurs when executing this entry point.
3376 InitializeAtapiPassThru(
3377 IN EFI_HANDLE ImageHandle
,
3378 IN EFI_SYSTEM_TABLE
*SystemTable
3384 // Install driver model protocol(s).
3386 Status
= EfiLibInstallDriverBindingComponentName2 (
3389 &gAtapiScsiPassThruDriverBinding
,
3391 &gAtapiScsiPassThruComponentName
,
3392 &gAtapiScsiPassThruComponentName2
3394 ASSERT_EFI_ERROR (Status
);
3397 // Install EFI Driver Supported EFI Version Protocol required for
3398 // EFI drivers that are on PCI and other plug in cards.
3400 gAtapiScsiPassThruDriverSupportedEfiVersion
.FirmwareVersion
= PcdGet32 (PcdDriverSupportedEfiVersion
);
3401 Status
= gBS
->InstallMultipleProtocolInterfaces (
3403 &gEfiDriverSupportedEfiVersionProtocolGuid
,
3404 &gAtapiScsiPassThruDriverSupportedEfiVersion
,
3407 ASSERT_EFI_ERROR (Status
);