2 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
3 This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 #include "AtapiPassThru.h"
16 SCSI_COMMAND_SET gEndTable
= { 0xff, (DATA_DIRECTION
) 0xff };
19 /// This table contains all the supported ATAPI commands.
21 SCSI_COMMAND_SET gSupportedATAPICommands
[] = {
22 { OP_INQUIRY
, DataIn
},
23 { OP_LOAD_UNLOAD_CD
, NoData
},
24 { OP_MECHANISM_STATUS
, DataIn
},
25 { OP_MODE_SELECT_10
, DataOut
},
26 { OP_MODE_SENSE_10
, DataIn
},
27 { OP_PAUSE_RESUME
, NoData
},
28 { OP_PLAY_AUDIO_10
, DataIn
},
29 { OP_PLAY_AUDIO_MSF
, DataIn
},
30 { OP_PLAY_CD
, DataIn
},
31 { OP_PLAY_CD_MSF
, DataIn
},
32 { OP_PREVENT_ALLOW_MEDIUM_REMOVAL
,NoData
},
33 { OP_READ_10
, DataIn
},
34 { OP_READ_12
, DataIn
},
35 { OP_READ_CAPACITY
, DataIn
},
36 { OP_READ_CD
, DataIn
},
37 { OP_READ_CD_MSF
, DataIn
},
38 { OP_READ_HEADER
, DataIn
},
39 { OP_READ_SUB_CHANNEL
, DataIn
},
40 { OP_READ_TOC
, DataIn
},
41 { OP_REQUEST_SENSE
, DataIn
},
43 { OP_SEEK_10
, NoData
},
44 { OP_SET_CD_SPEED
, DataOut
},
45 { OP_STOPPLAY_SCAN
, NoData
},
46 { OP_START_STOP_UNIT
, NoData
},
47 { OP_TEST_UNIT_READY
, NoData
},
48 { OP_FORMAT_UNIT
, DataOut
},
49 { OP_READ_FORMAT_CAPACITIES
, DataIn
},
50 { OP_VERIFY
, DataOut
},
51 { OP_WRITE_10
, DataOut
},
52 { OP_WRITE_12
, DataOut
},
53 { OP_WRITE_AND_VERIFY
, DataOut
},
54 { 0xff, (DATA_DIRECTION
) 0xff }
57 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_MODE gScsiPassThruMode
= {
61 EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
,
65 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_PROTOCOL gScsiPassThruProtocolTemplate
= {
67 AtapiScsiPassThruFunction
,
68 AtapiScsiPassThruGetNextDevice
,
69 AtapiScsiPassThruBuildDevicePath
,
70 AtapiScsiPassThruGetTargetLun
,
71 AtapiScsiPassThruResetChannel
,
72 AtapiScsiPassThruResetTarget
75 GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_MODE gExtScsiPassThruMode
= {
77 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
| EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
,
81 GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_PROTOCOL gExtScsiPassThruProtocolTemplate
= {
82 &gExtScsiPassThruMode
,
83 AtapiExtScsiPassThruFunction
,
84 AtapiExtScsiPassThruGetNextTargetLun
,
85 AtapiExtScsiPassThruBuildDevicePath
,
86 AtapiExtScsiPassThruGetTargetLun
,
87 AtapiExtScsiPassThruResetChannel
,
88 AtapiExtScsiPassThruResetTarget
,
89 AtapiExtScsiPassThruGetNextTarget
92 EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding
= {
93 AtapiScsiPassThruDriverBindingSupported
,
94 AtapiScsiPassThruDriverBindingStart
,
95 AtapiScsiPassThruDriverBindingStop
,
103 AtapiScsiPassThruDriverBindingSupported (
104 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
105 IN EFI_HANDLE Controller
,
106 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
111 Test to see if this driver supports ControllerHandle. Any ControllerHandle
112 that has gEfiPciIoProtocolGuid installed and is IDE Controller it will be supported.
116 This - Protocol instance pointer.
117 Controller - Handle of device to test
118 RemainingDevicePath - Not used
126 EFI_PCI_IO_PROTOCOL
*PciIo
;
131 // Open the IO Abstraction(s) needed to perform the supported test
133 Status
= gBS
->OpenProtocol (
135 &gEfiPciIoProtocolGuid
,
137 This
->DriverBindingHandle
,
139 EFI_OPEN_PROTOCOL_BY_DRIVER
141 if (EFI_ERROR (Status
)) {
145 // Use the PCI I/O Protocol to see if Controller is a IDE Controller that
146 // can be managed by this driver. Read the PCI Configuration Header
149 Status
= PciIo
->Pci
.Read (
153 sizeof (Pci
) / sizeof (UINT32
),
156 if (EFI_ERROR (Status
)) {
159 &gEfiPciIoProtocolGuid
,
160 This
->DriverBindingHandle
,
163 return EFI_UNSUPPORTED
;
166 if (Pci
.Hdr
.ClassCode
[2] != PCI_CLASS_MASS_STORAGE
|| Pci
.Hdr
.ClassCode
[1] != PCI_CLASS_MASS_STORAGE_IDE
) {
168 Status
= EFI_UNSUPPORTED
;
173 &gEfiPciIoProtocolGuid
,
174 This
->DriverBindingHandle
,
183 AtapiScsiPassThruDriverBindingStart (
184 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
185 IN EFI_HANDLE Controller
,
186 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
191 Create handles for IDE channels specified by RemainingDevicePath.
192 Install SCSI Pass Thru Protocol onto each created handle.
196 This - Protocol instance pointer.
197 Controller - Handle of device to test
198 RemainingDevicePath - Not used
206 EFI_PCI_IO_PROTOCOL
*PciIo
;
208 UINT64 OriginalPciAttributes
;
209 BOOLEAN PciAttributesSaved
;
212 Status
= gBS
->OpenProtocol (
214 &gEfiPciIoProtocolGuid
,
216 This
->DriverBindingHandle
,
218 EFI_OPEN_PROTOCOL_BY_DRIVER
220 if (EFI_ERROR (Status
)) {
224 PciAttributesSaved
= FALSE
;
226 // Save original PCI attributes
228 Status
= PciIo
->Attributes (
230 EfiPciIoAttributeOperationGet
,
232 &OriginalPciAttributes
235 if (EFI_ERROR (Status
)) {
238 PciAttributesSaved
= TRUE
;
240 Status
= PciIo
->Attributes (
242 EfiPciIoAttributeOperationSupported
,
246 if (!EFI_ERROR (Status
)) {
247 Supports
&= (EFI_PCI_DEVICE_ENABLE
|
248 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
|
249 EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
);
250 Status
= PciIo
->Attributes (
252 EfiPciIoAttributeOperationEnable
,
257 if (EFI_ERROR (Status
)) {
262 // Create SCSI Pass Thru instance for the IDE channel.
264 Status
= RegisterAtapiScsiPassThru (This
, Controller
, PciIo
, OriginalPciAttributes
);
267 if (EFI_ERROR (Status
)) {
268 if (PciAttributesSaved
== TRUE
) {
270 // Restore original PCI attributes
274 EfiPciIoAttributeOperationSet
,
275 OriginalPciAttributes
,
282 &gEfiPciIoProtocolGuid
,
283 This
->DriverBindingHandle
,
293 AtapiScsiPassThruDriverBindingStop (
294 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
295 IN EFI_HANDLE Controller
,
296 IN UINTN NumberOfChildren
,
297 IN EFI_HANDLE
*ChildHandleBuffer
303 Stop this driver on ControllerHandle. Support stoping any child handles
304 created by this driver.
308 This - Protocol instance pointer.
309 Controller - Handle of device to stop driver on
310 NumberOfChildren - Number of Children in the ChildHandleBuffer
311 ChildHandleBuffer - List of handles for the children we need to stop.
320 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
321 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
322 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
324 if (FeaturePcdGet (PcdSupportScsiPassThru
)) {
325 Status
= gBS
->OpenProtocol (
327 &gEfiScsiPassThruProtocolGuid
,
328 (VOID
**) &ScsiPassThru
,
329 This
->DriverBindingHandle
,
331 EFI_OPEN_PROTOCOL_GET_PROTOCOL
333 if (EFI_ERROR (Status
)) {
336 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru
);
337 if (FeaturePcdGet (PcdSupportExtScsiPassThru
)) {
338 Status
= gBS
->UninstallMultipleProtocolInterfaces (
340 &gEfiScsiPassThruProtocolGuid
,
341 &AtapiScsiPrivate
->ScsiPassThru
,
342 &gEfiExtScsiPassThruProtocolGuid
,
343 &AtapiScsiPrivate
->ExtScsiPassThru
,
347 Status
= gBS
->UninstallMultipleProtocolInterfaces (
349 &gEfiScsiPassThruProtocolGuid
,
350 &AtapiScsiPrivate
->ScsiPassThru
,
355 Status
= gBS
->OpenProtocol (
357 &gEfiExtScsiPassThruProtocolGuid
,
358 (VOID
**) &ExtScsiPassThru
,
359 This
->DriverBindingHandle
,
361 EFI_OPEN_PROTOCOL_GET_PROTOCOL
363 if (EFI_ERROR (Status
)) {
366 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (ExtScsiPassThru
);
367 Status
= gBS
->UninstallMultipleProtocolInterfaces (
369 &gEfiExtScsiPassThruProtocolGuid
,
370 &AtapiScsiPrivate
->ExtScsiPassThru
,
374 if (EFI_ERROR (Status
)) {
379 // Restore original PCI attributes
381 AtapiScsiPrivate
->PciIo
->Attributes (
382 AtapiScsiPrivate
->PciIo
,
383 EfiPciIoAttributeOperationSet
,
384 AtapiScsiPrivate
->OriginalPciAttributes
,
390 &gEfiPciIoProtocolGuid
,
391 This
->DriverBindingHandle
,
395 gBS
->FreePool (AtapiScsiPrivate
);
401 RegisterAtapiScsiPassThru (
402 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
403 IN EFI_HANDLE Controller
,
404 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
405 IN UINT64 OriginalPciAttributes
410 Attaches SCSI Pass Thru Protocol for specified IDE channel.
413 This - Protocol instance pointer.
414 Controller - Parent device handle to the IDE channel.
415 PciIo - PCI I/O protocol attached on the "Controller".
418 Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.
423 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
424 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[ATAPI_MAX_CHANNEL
];
426 AtapiScsiPrivate
= AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV
));
427 if (AtapiScsiPrivate
== NULL
) {
428 return EFI_OUT_OF_RESOURCES
;
431 AtapiScsiPrivate
->Signature
= ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE
;
432 AtapiScsiPrivate
->Handle
= Controller
;
435 // will reset the IoPort inside each API function.
437 AtapiScsiPrivate
->IoPort
= NULL
;
438 AtapiScsiPrivate
->PciIo
= PciIo
;
439 AtapiScsiPrivate
->OriginalPciAttributes
= OriginalPciAttributes
;
442 // Obtain IDE IO port registers' base addresses
444 Status
= GetIdeRegistersBaseAddr (PciIo
, IdeRegsBaseAddr
);
445 if (EFI_ERROR (Status
)) {
449 InitAtapiIoPortRegisters(AtapiScsiPrivate
, IdeRegsBaseAddr
);
452 // Initialize the LatestTargetId to MAX_TARGET_ID.
454 AtapiScsiPrivate
->LatestTargetId
= MAX_TARGET_ID
;
455 AtapiScsiPrivate
->LatestLun
= 0;
457 Status
= InstallScsiPassThruProtocols (&Controller
, AtapiScsiPrivate
);
464 AtapiScsiPassThruFunction (
465 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
468 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
469 IN EFI_EVENT Event OPTIONAL
475 Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
479 This: The EFI_SCSI_PASS_THRU_PROTOCOL instance.
480 Target: The Target ID of the ATAPI device to send the SCSI
481 Request Packet. To ATAPI devices attached on an IDE
482 Channel, Target ID 0 indicates Master device;Target
483 ID 1 indicates Slave device.
484 Lun: The LUN of the ATAPI device to send the SCSI Request
485 Packet. To the ATAPI device, Lun is always 0.
486 Packet: The SCSI Request Packet to send to the ATAPI device
487 specified by Target and Lun.
488 Event: If non-blocking I/O is not supported then Event is ignored,
489 and blocking I/O is performed.
490 If Event is NULL, then blocking I/O is performed.
491 If Event is not NULL and non blocking I/O is supported,
492 then non-blocking I/O is performed, and Event will be signaled
493 when the SCSI Request Packet completes.
501 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
504 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
507 // Target is not allowed beyond MAX_TARGET_ID
509 if ((Target
> MAX_TARGET_ID
) || (Lun
!= 0)) {
510 return EFI_INVALID_PARAMETER
;
514 // check the data fields in Packet parameter.
516 Status
= CheckSCSIRequestPacket (Packet
);
517 if (EFI_ERROR (Status
)) {
522 // If Request Packet targets at the IDE channel itself,
525 if (Target
== This
->Mode
->AdapterId
) {
526 Packet
->TransferLength
= 0;
531 // According to Target ID, reset the Atapi I/O Register mapping
532 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
533 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
535 if ((Target
/ 2) == 0) {
537 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
540 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
544 // the ATAPI SCSI interface does not support non-blocking I/O
545 // ignore the Event parameter
547 // Performs blocking I/O.
549 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, Packet
);
555 AtapiScsiPassThruGetNextDevice (
556 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
557 IN OUT UINT32
*Target
,
564 Used to retrieve the list of legal Target IDs for SCSI devices
569 This - Protocol instance pointer.
570 Target - On input, a pointer to the Target ID of a SCSI
571 device present on the SCSI channel. On output,
572 a pointer to the Target ID of the next SCSI device
573 present on a SCSI channel. An input value of
574 0xFFFFFFFF retrieves the Target ID of the first
575 SCSI device present on a SCSI channel.
576 Lun - On input, a pointer to the LUN of a SCSI device
577 present on the SCSI channel. On output, a pointer
578 to the LUN of the next SCSI device present on
582 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
583 on the SCSI channel was returned in Target and Lun.
584 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
585 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
586 returned on a previous call to GetNextDevice().
589 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
592 // Retrieve Device Private Data Structure.
594 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
597 // Check whether Target is valid.
599 if (Target
== NULL
|| Lun
== NULL
) {
600 return EFI_INVALID_PARAMETER
;
603 if ((*Target
!= 0xFFFFFFFF) &&
604 ((*Target
!= AtapiScsiPrivate
->LatestTargetId
) ||
605 (*Lun
!= AtapiScsiPrivate
->LatestLun
))) {
606 return EFI_INVALID_PARAMETER
;
609 if (*Target
== MAX_TARGET_ID
) {
610 return EFI_NOT_FOUND
;
613 if (*Target
== 0xFFFFFFFF) {
616 *Target
= AtapiScsiPrivate
->LatestTargetId
+ 1;
622 // Update the LatestTargetId.
624 AtapiScsiPrivate
->LatestTargetId
= *Target
;
625 AtapiScsiPrivate
->LatestLun
= *Lun
;
633 AtapiScsiPassThruBuildDevicePath (
634 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
637 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
643 Used to allocate and build a device path node for a SCSI device
644 on a SCSI channel. Would not build device path for a SCSI Host Controller.
648 This - Protocol instance pointer.
649 Target - The Target ID of the SCSI device for which
650 a device path node is to be allocated and built.
651 Lun - The LUN of the SCSI device for which a device
652 path node is to be allocated and built.
653 DevicePath - A pointer to a single device path node that
654 describes the SCSI device specified by
655 Target and Lun. This function is responsible
656 for allocating the buffer DevicePath with the boot
657 service AllocatePool(). It is the caller's
658 responsibility to free DevicePath when the caller
659 is finished with DevicePath.
661 EFI_SUCCESS - The device path node that describes the SCSI device
662 specified by Target and Lun was allocated and
663 returned in DevicePath.
664 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
665 not exist on the SCSI channel.
666 EFI_INVALID_PARAMETER - DevicePath is NULL.
667 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
675 // Validate parameters passed in.
678 if (DevicePath
== NULL
) {
679 return EFI_INVALID_PARAMETER
;
683 // can not build device path for the SCSI Host Controller.
685 if ((Target
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
686 return EFI_NOT_FOUND
;
689 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
691 return EFI_OUT_OF_RESOURCES
;
694 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
695 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
696 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
698 Node
->Atapi
.PrimarySecondary
= (UINT8
) (Target
/ 2);
699 Node
->Atapi
.SlaveMaster
= (UINT8
) (Target
% 2);
700 Node
->Atapi
.Lun
= (UINT16
) Lun
;
702 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
709 AtapiScsiPassThruGetTargetLun (
710 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
711 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
719 Used to translate a device path node to a Target ID and LUN.
723 This - Protocol instance pointer.
724 DevicePath - A pointer to the device path node that
725 describes a SCSI device on the SCSI channel.
726 Target - A pointer to the Target ID of a SCSI device
728 Lun - A pointer to the LUN of a SCSI device on
732 EFI_SUCCESS - DevicePath was successfully translated to a
733 Target ID and LUN, and they were returned
735 EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
736 EFI_UNSUPPORTED - This driver does not support the device path
737 node type in DevicePath.
738 EFI_NOT_FOUND - A valid translation from DevicePath to a
739 Target ID and LUN does not exist.
745 // Validate parameters passed in.
747 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
748 return EFI_INVALID_PARAMETER
;
752 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
754 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
755 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
756 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
757 return EFI_UNSUPPORTED
;
760 Node
= (EFI_DEV_PATH
*) DevicePath
;
762 *Target
= Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
;
763 *Lun
= Node
->Atapi
.Lun
;
765 if (*Target
> (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
766 return EFI_NOT_FOUND
;
774 AtapiScsiPassThruResetChannel (
775 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
781 Resets a SCSI channel.This operation resets all the
782 SCSI devices connected to the SCSI channel.
786 This - Protocol instance pointer.
790 EFI_SUCCESS - The SCSI channel was reset.
791 EFI_UNSUPPORTED - The SCSI channel does not support
792 a channel reset operation.
793 EFI_DEVICE_ERROR - A device error occurred while
794 attempting to reset the SCSI channel.
795 EFI_TIMEOUT - A timeout occurred while attempting
796 to reset the SCSI channel.
799 UINT8 DeviceControlValue
;
800 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
804 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
808 // Reset both Primary channel and Secondary channel.
809 // so, the IoPort pointer must point to the right I/O Register group
811 for (Index
= 0; Index
< 2; Index
++) {
815 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[Index
];
817 DeviceControlValue
= 0;
819 // set SRST bit to initiate soft reset
821 DeviceControlValue
|= SRST
;
825 DeviceControlValue
|= BIT1
;
827 AtapiScsiPrivate
->PciIo
,
828 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
841 DeviceControlValue
&= 0xfb;
843 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
846 // slave device needs at most 31s to clear BSY
848 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000) != EFI_TIMEOUT
) {
862 AtapiScsiPassThruResetTarget (
863 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
871 Resets a SCSI device that is connected to a SCSI channel.
875 This - Protocol instance pointer.
876 Target - The Target ID of the SCSI device to reset.
877 Lun - The LUN of the SCSI device to reset.
881 EFI_SUCCESS - The SCSI device specified by Target and
883 EFI_UNSUPPORTED - The SCSI channel does not support a target
885 EFI_INVALID_PARAMETER - Target or Lun are invalid.
886 EFI_DEVICE_ERROR - A device error occurred while attempting
887 to reset the SCSI device specified by Target
889 EFI_TIMEOUT - A timeout occurred while attempting to reset
890 the SCSI device specified by Target and Lun.
893 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
897 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
899 if ((Target
> MAX_TARGET_ID
) || (Lun
!= 0)) {
900 return EFI_INVALID_PARAMETER
;
903 // Directly return EFI_SUCCESS if want to reset the host controller
905 if (Target
== This
->Mode
->AdapterId
) {
910 // According to Target ID, reset the Atapi I/O Register mapping
911 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
912 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
914 if ((Target
/ 2) == 0) {
915 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
917 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
921 // for ATAPI device, no need to wait DRDY ready after device selecting.
923 // bit7 and bit5 are both set to 1 for backward compatibility
925 DeviceSelect
= (UINT8
) (((BIT7
| BIT5
) | (Target
<< 4)));
926 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
928 Command
= ATAPI_SOFT_RESET_CMD
;
929 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
932 // BSY clear is the only status return to the host by the device
933 // when reset is complete.
934 // slave device needs at most 31s to clear BSY
936 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000))) {
941 // stall 5 seconds to make the device status stable
943 gBS
->Stall (5000000);
950 AtapiExtScsiPassThruFunction (
951 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
954 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
955 IN EFI_EVENT Event OPTIONAL
961 Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
965 This: The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
966 Target: The Target ID of the ATAPI device to send the SCSI
967 Request Packet. To ATAPI devices attached on an IDE
968 Channel, Target ID 0 indicates Master device;Target
969 ID 1 indicates Slave device.
970 Lun: The LUN of the ATAPI device to send the SCSI Request
971 Packet. To the ATAPI device, Lun is always 0.
972 Packet: The SCSI Request Packet to send to the ATAPI device
973 specified by Target and Lun.
974 Event: If non-blocking I/O is not supported then Event is ignored,
975 and blocking I/O is performed.
976 If Event is NULL, then blocking I/O is performed.
977 If Event is not NULL and non blocking I/O is supported,
978 then non-blocking I/O is performed, and Event will be signaled
979 when the SCSI Request Packet completes.
988 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
991 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
994 // For ATAPI device, UINT8 is enough to represent the SCSI ID on channel.
996 TargetId
= Target
[0];
999 // Target is not allowed beyond MAX_TARGET_ID
1001 if ((TargetId
> MAX_TARGET_ID
) || (Lun
!= 0)) {
1002 return EFI_INVALID_PARAMETER
;
1006 // check the data fields in Packet parameter.
1008 Status
= CheckExtSCSIRequestPacket (Packet
);
1009 if (EFI_ERROR (Status
)) {
1014 // If Request Packet targets at the IDE channel itself,
1017 if (TargetId
== (UINT8
)This
->Mode
->AdapterId
) {
1018 Packet
->InTransferLength
= Packet
->OutTransferLength
= 0;
1023 // According to Target ID, reset the Atapi I/O Register mapping
1024 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
1025 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
1027 if ((TargetId
/ 2) == 0) {
1028 TargetId
= (UINT8
) (TargetId
% 2);
1029 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
1031 TargetId
= (UINT8
) (TargetId
% 2);
1032 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
1036 // the ATAPI SCSI interface does not support non-blocking I/O
1037 // ignore the Event parameter
1039 // Performs blocking I/O.
1041 Status
= SubmitExtBlockingIoCommand (AtapiScsiPrivate
, TargetId
, Packet
);
1047 AtapiExtScsiPassThruGetNextTargetLun (
1048 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1049 IN OUT UINT8
**Target
,
1054 Routine Description:
1056 Used to retrieve the list of legal Target IDs for SCSI devices
1061 This - Protocol instance pointer.
1062 Target - On input, a pointer to the Target ID of a SCSI
1063 device present on the SCSI channel. On output,
1064 a pointer to the Target ID of the next SCSI device
1065 present on a SCSI channel. An input value of
1066 0xFFFFFFFF retrieves the Target ID of the first
1067 SCSI device present on a SCSI channel.
1068 Lun - On input, a pointer to the LUN of a SCSI device
1069 present on the SCSI channel. On output, a pointer
1070 to the LUN of the next SCSI device present on
1074 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
1075 on the SCSI channel was returned in Target and Lun.
1076 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
1077 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
1078 returned on a previous call to GetNextDevice().
1083 UINT8 ScsiId
[TARGET_MAX_BYTES
];
1084 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1087 // Retrieve Device Private Data Structure.
1089 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1092 // Check whether Target is valid.
1094 if (*Target
== NULL
|| Lun
== NULL
) {
1095 return EFI_INVALID_PARAMETER
;
1098 SetMem (ScsiId
, TARGET_MAX_BYTES
, 0xFF);
1100 TargetId
= (*Target
)[0];
1103 // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
1105 if (CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) {
1106 for (ByteIndex
= 1; ByteIndex
< TARGET_MAX_BYTES
; ByteIndex
++) {
1107 if ((*Target
)[ByteIndex
] != 0) {
1108 return EFI_INVALID_PARAMETER
;
1113 if ((CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) &&
1114 ((TargetId
!= AtapiScsiPrivate
->LatestTargetId
) ||
1115 (*Lun
!= AtapiScsiPrivate
->LatestLun
))) {
1116 return EFI_INVALID_PARAMETER
;
1119 if (TargetId
== MAX_TARGET_ID
) {
1120 return EFI_NOT_FOUND
;
1123 if (CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) == 0) {
1124 SetMem (*Target
, TARGET_MAX_BYTES
,0);
1126 (*Target
)[0] = (UINT8
) (AtapiScsiPrivate
->LatestTargetId
+ 1);
1132 // Update the LatestTargetId.
1134 AtapiScsiPrivate
->LatestTargetId
= (*Target
)[0];
1135 AtapiScsiPrivate
->LatestLun
= *Lun
;
1143 AtapiExtScsiPassThruBuildDevicePath (
1144 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1147 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
1151 Routine Description:
1153 Used to allocate and build a device path node for a SCSI device
1154 on a SCSI channel. Would not build device path for a SCSI Host Controller.
1158 This - Protocol instance pointer.
1159 Target - The Target ID of the SCSI device for which
1160 a device path node is to be allocated and built.
1161 Lun - The LUN of the SCSI device for which a device
1162 path node is to be allocated and built.
1163 DevicePath - A pointer to a single device path node that
1164 describes the SCSI device specified by
1165 Target and Lun. This function is responsible
1166 for allocating the buffer DevicePath with the boot
1167 service AllocatePool(). It is the caller's
1168 responsibility to free DevicePath when the caller
1169 is finished with DevicePath.
1171 EFI_SUCCESS - The device path node that describes the SCSI device
1172 specified by Target and Lun was allocated and
1173 returned in DevicePath.
1174 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
1175 not exist on the SCSI channel.
1176 EFI_INVALID_PARAMETER - DevicePath is NULL.
1177 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
1184 TargetId
= Target
[0];
1187 // Validate parameters passed in.
1190 if (DevicePath
== NULL
) {
1191 return EFI_INVALID_PARAMETER
;
1195 // can not build device path for the SCSI Host Controller.
1197 if ((TargetId
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
1198 return EFI_NOT_FOUND
;
1201 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
1203 return EFI_OUT_OF_RESOURCES
;
1206 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
1207 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
1208 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
1210 Node
->Atapi
.PrimarySecondary
= (UINT8
) (TargetId
/ 2);
1211 Node
->Atapi
.SlaveMaster
= (UINT8
) (TargetId
% 2);
1212 Node
->Atapi
.Lun
= (UINT16
) Lun
;
1214 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
1221 AtapiExtScsiPassThruGetTargetLun (
1222 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1223 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1229 Routine Description:
1231 Used to translate a device path node to a Target ID and LUN.
1235 This - Protocol instance pointer.
1236 DevicePath - A pointer to the device path node that
1237 describes a SCSI device on the SCSI channel.
1238 Target - A pointer to the Target ID of a SCSI device
1239 on the SCSI channel.
1240 Lun - A pointer to the LUN of a SCSI device on
1244 EFI_SUCCESS - DevicePath was successfully translated to a
1245 Target ID and LUN, and they were returned
1247 EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
1248 EFI_UNSUPPORTED - This driver does not support the device path
1249 node type in DevicePath.
1250 EFI_NOT_FOUND - A valid translation from DevicePath to a
1251 Target ID and LUN does not exist.
1257 // Validate parameters passed in.
1259 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
1260 return EFI_INVALID_PARAMETER
;
1264 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
1266 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
1267 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
1268 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
1269 return EFI_UNSUPPORTED
;
1272 ZeroMem (*Target
, TARGET_MAX_BYTES
);
1274 Node
= (EFI_DEV_PATH
*) DevicePath
;
1276 (*Target
)[0] = (UINT8
) (Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
);
1277 *Lun
= Node
->Atapi
.Lun
;
1279 if ((*Target
)[0] > (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
1280 return EFI_NOT_FOUND
;
1288 AtapiExtScsiPassThruResetChannel (
1289 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
1293 Routine Description:
1295 Resets a SCSI channel.This operation resets all the
1296 SCSI devices connected to the SCSI channel.
1300 This - Protocol instance pointer.
1304 EFI_SUCCESS - The SCSI channel was reset.
1305 EFI_UNSUPPORTED - The SCSI channel does not support
1306 a channel reset operation.
1307 EFI_DEVICE_ERROR - A device error occurred while
1308 attempting to reset the SCSI channel.
1309 EFI_TIMEOUT - A timeout occurred while attempting
1310 to reset the SCSI channel.
1313 UINT8 DeviceControlValue
;
1315 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1318 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1321 // Reset both Primary channel and Secondary channel.
1322 // so, the IoPort pointer must point to the right I/O Register group
1323 // And if there is a channel reset successfully, return EFI_SUCCESS.
1325 for (Index
= 0; Index
< 2; Index
++) {
1329 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[Index
];
1331 DeviceControlValue
= 0;
1333 // set SRST bit to initiate soft reset
1335 DeviceControlValue
|= SRST
;
1337 // disable Interrupt
1339 DeviceControlValue
|= BIT1
;
1341 AtapiScsiPrivate
->PciIo
,
1342 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
1355 DeviceControlValue
&= 0xfb;
1357 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
1360 // slave device needs at most 31s to clear BSY
1362 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000) != EFI_TIMEOUT
) {
1376 AtapiExtScsiPassThruResetTarget (
1377 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1383 Routine Description:
1385 Resets a SCSI device that is connected to a SCSI channel.
1389 This - Protocol instance pointer.
1390 Target - The Target ID of the SCSI device to reset.
1391 Lun - The LUN of the SCSI device to reset.
1395 EFI_SUCCESS - The SCSI device specified by Target and
1397 EFI_UNSUPPORTED - The SCSI channel does not support a target
1399 EFI_INVALID_PARAMETER - Target or Lun are invalid.
1400 EFI_DEVICE_ERROR - A device error occurred while attempting
1401 to reset the SCSI device specified by Target
1403 EFI_TIMEOUT - A timeout occurred while attempting to reset
1404 the SCSI device specified by Target and Lun.
1410 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1412 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1413 TargetId
= Target
[0];
1415 if ((TargetId
> MAX_TARGET_ID
) || (Lun
!= 0)) {
1416 return EFI_INVALID_PARAMETER
;
1419 // Directly return EFI_SUCCESS if want to reset the host controller
1421 if (TargetId
== This
->Mode
->AdapterId
) {
1426 // According to Target ID, reset the Atapi I/O Register mapping
1427 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
1428 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
1430 if ((TargetId
/ 2) == 0) {
1431 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
1433 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
1437 // for ATAPI device, no need to wait DRDY ready after device selecting.
1439 // bit7 and bit5 are both set to 1 for backward compatibility
1441 DeviceSelect
= (UINT8
) ((BIT7
| BIT5
) | (TargetId
<< 4));
1442 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
1444 Command
= ATAPI_SOFT_RESET_CMD
;
1445 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
1448 // BSY clear is the only status return to the host by the device
1449 // when reset is complete.
1450 // slave device needs at most 31s to clear BSY
1452 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000))) {
1457 // stall 5 seconds to make the device status stable
1459 gBS
->Stall (5000000);
1467 AtapiExtScsiPassThruGetNextTarget (
1468 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1469 IN OUT UINT8
**Target
1473 Routine Description:
1474 Used to retrieve the list of legal Target IDs for SCSI devices
1478 This - Protocol instance pointer.
1479 Target - On input, a pointer to the Target ID of a SCSI
1480 device present on the SCSI channel. On output,
1481 a pointer to the Target ID of the next SCSI device
1482 present on a SCSI channel. An input value of
1483 0xFFFFFFFF retrieves the Target ID of the first
1484 SCSI device present on a SCSI channel.
1485 Lun - On input, a pointer to the LUN of a SCSI device
1486 present on the SCSI channel. On output, a pointer
1487 to the LUN of the next SCSI device present on
1491 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
1492 on the SCSI channel was returned in Target and Lun.
1493 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
1494 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
1495 returned on a previous call to GetNextDevice().
1499 UINT8 ScsiId
[TARGET_MAX_BYTES
];
1500 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1504 // Retrieve Device Private Data Structure.
1506 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1509 // Check whether Target is valid.
1511 if (*Target
== NULL
) {
1512 return EFI_INVALID_PARAMETER
;
1515 TargetId
= (*Target
)[0];
1516 SetMem (ScsiId
, TARGET_MAX_BYTES
, 0xFF);
1519 // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
1521 if (CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) {
1522 for (ByteIndex
= 1; ByteIndex
< TARGET_MAX_BYTES
; ByteIndex
++) {
1523 if ((*Target
)[ByteIndex
] != 0) {
1524 return EFI_INVALID_PARAMETER
;
1529 if ((CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) &&(TargetId
!= AtapiScsiPrivate
->LatestTargetId
)) {
1530 return EFI_INVALID_PARAMETER
;
1533 if (TargetId
== MAX_TARGET_ID
) {
1534 return EFI_NOT_FOUND
;
1537 if ((CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) == 0)) {
1538 SetMem (*Target
, TARGET_MAX_BYTES
, 0);
1540 (*Target
)[0] = (UINT8
) (AtapiScsiPrivate
->LatestTargetId
+ 1);
1544 // Update the LatestTargetId.
1546 AtapiScsiPrivate
->LatestTargetId
= (*Target
)[0];
1547 AtapiScsiPrivate
->LatestLun
= 0;
1553 GetIdeRegistersBaseAddr (
1554 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1555 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
1559 Routine Description:
1560 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
1561 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
1562 the PCI IDE controller's Configuration Space.
1565 PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance
1566 IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to
1567 receive IDE IO port registers' base addresses
1578 Status
= PciIo
->Pci
.Read (
1586 if (EFI_ERROR (Status
)) {
1590 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
1591 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
1592 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
1595 // The BARs should be of IO type
1597 if ((PciData
.Device
.Bar
[0] & BIT0
) == 0 ||
1598 (PciData
.Device
.Bar
[1] & BIT0
) == 0) {
1599 return EFI_UNSUPPORTED
;
1602 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
1603 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
1604 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
1605 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
1608 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
1609 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
1610 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
1613 // The BARs should be of IO type
1615 if ((PciData
.Device
.Bar
[2] & BIT0
) == 0 ||
1616 (PciData
.Device
.Bar
[3] & BIT0
) == 0) {
1617 return EFI_UNSUPPORTED
;
1620 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
1621 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
1622 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
1623 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
1630 InitAtapiIoPortRegisters (
1631 IN ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1632 IN IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
1636 Routine Description:
1638 Initialize each Channel's Base Address of CommandBlock and ControlBlock.
1642 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
1643 IdeRegsBaseAddr - The pointer of IDE_REGISTERS_BASE_ADDR
1653 UINT16 CommandBlockBaseAddr
;
1654 UINT16 ControlBlockBaseAddr
;
1655 IDE_BASE_REGISTERS
*RegisterPointer
;
1658 for (IdeChannel
= 0; IdeChannel
< ATAPI_MAX_CHANNEL
; IdeChannel
++) {
1660 RegisterPointer
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[IdeChannel
];
1663 // Initialize IDE IO port addresses, including Command Block registers
1664 // and Control Block registers
1666 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeChannel
].CommandBlockBaseAddr
;
1667 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeChannel
].ControlBlockBaseAddr
;
1669 RegisterPointer
->Data
= CommandBlockBaseAddr
;
1670 (*(UINT16
*) &RegisterPointer
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
1671 RegisterPointer
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
1672 RegisterPointer
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
1673 RegisterPointer
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
1674 RegisterPointer
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
1675 RegisterPointer
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
1676 (*(UINT16
*) &RegisterPointer
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
1678 (*(UINT16
*) &RegisterPointer
->Alt
) = ControlBlockBaseAddr
;
1679 RegisterPointer
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
1686 CheckSCSIRequestPacket (
1687 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1691 Routine Description:
1693 Checks the parameters in the SCSI Request Packet to make sure
1694 they are valid for a SCSI Pass Thru request.
1698 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1706 if (Packet
== NULL
) {
1707 return EFI_INVALID_PARAMETER
;
1710 if (!ValidCdbLength (Packet
->CdbLength
)) {
1711 return EFI_INVALID_PARAMETER
;
1714 if (Packet
->Cdb
== NULL
) {
1715 return EFI_INVALID_PARAMETER
;
1719 // Checks whether the request command is supported.
1721 if (!IsCommandValid (Packet
)) {
1722 return EFI_UNSUPPORTED
;
1730 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1734 Routine Description:
1736 Checks the requested SCSI command:
1737 Is it supported by this driver?
1738 Is the Data transfer direction reasonable?
1742 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1754 OpCode
= (UINT8
*) (Packet
->Cdb
);
1755 ArrayLen
= (UINT8
) (sizeof (gSupportedATAPICommands
) / sizeof (gSupportedATAPICommands
[0]));
1757 for (Index
= 0; (Index
< ArrayLen
) && (CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)) != 0); Index
++) {
1759 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
1761 // Check whether the requested Command is supported by this driver
1763 if (Packet
->DataDirection
== DataIn
) {
1765 // Check whether the requested data direction conforms to
1766 // what it should be.
1768 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
1773 if (Packet
->DataDirection
== DataOut
) {
1775 // Check whether the requested data direction conforms to
1776 // what it should be.
1778 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
1791 SubmitBlockingIoCommand (
1792 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1794 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1798 Routine Description:
1800 Performs blocking I/O request.
1804 AtapiScsiPrivate: Private data structure for the specified channel.
1805 Target: The Target ID of the ATAPI device to send the SCSI
1806 Request Packet. To ATAPI devices attached on an IDE
1807 Channel, Target ID 0 indicates Master device;Target
1808 ID 1 indicates Slave device.
1809 Packet: The SCSI Request Packet to send to the ATAPI device
1810 specified by Target.
1816 UINT8 PacketCommand
[12];
1817 UINT64 TimeoutInMicroSeconds
;
1818 EFI_STATUS PacketCommandStatus
;
1821 // Fill ATAPI Command Packet according to CDB
1823 ZeroMem (&PacketCommand
, 12);
1824 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
1827 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
1829 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
1832 // Submit ATAPI Command Packet
1834 PacketCommandStatus
= AtapiPacketCommand (
1839 &(Packet
->TransferLength
),
1840 (DATA_DIRECTION
) Packet
->DataDirection
,
1841 TimeoutInMicroSeconds
1843 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
1844 Packet
->SenseDataLength
= 0;
1845 return PacketCommandStatus
;
1849 // Return SenseData if PacketCommandStatus matches
1850 // the following return codes.
1852 if ((PacketCommandStatus
== EFI_BAD_BUFFER_SIZE
) ||
1853 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
1854 (PacketCommandStatus
== EFI_TIMEOUT
)) {
1857 // avoid submit request sense command continuously.
1859 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
1860 Packet
->SenseDataLength
= 0;
1861 return PacketCommandStatus
;
1864 RequestSenseCommand (
1869 &Packet
->SenseDataLength
1873 return PacketCommandStatus
;
1877 RequestSenseCommand (
1878 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1882 UINT8
*SenseDataLength
1886 Routine Description:
1888 Sumbit request sense command
1892 AtapiScsiPrivate - The pionter of ATAPI_SCSI_PASS_THRU_DEV
1893 Target - The target ID
1894 Timeout - The time to complete the command
1895 SenseData - The buffer to fill in sense data
1896 SenseDataLength - The length of buffer
1904 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet
;
1908 ZeroMem (&Packet
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1911 Cdb
[0] = OP_REQUEST_SENSE
;
1912 Cdb
[4] = (UINT8
) (*SenseDataLength
);
1914 Packet
.Timeout
= Timeout
;
1915 Packet
.DataBuffer
= SenseData
;
1916 Packet
.SenseData
= NULL
;
1918 Packet
.TransferLength
= *SenseDataLength
;
1919 Packet
.CdbLength
= 12;
1920 Packet
.DataDirection
= DataIn
;
1922 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, &Packet
);
1923 *SenseDataLength
= (UINT8
) (Packet
.TransferLength
);
1928 CheckExtSCSIRequestPacket (
1929 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1933 Routine Description:
1935 Checks the parameters in the SCSI Request Packet to make sure
1936 they are valid for a SCSI Pass Thru request.
1940 Packet - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1948 if (Packet
== NULL
) {
1949 return EFI_INVALID_PARAMETER
;
1952 if (!ValidCdbLength (Packet
->CdbLength
)) {
1953 return EFI_INVALID_PARAMETER
;
1956 if (Packet
->Cdb
== NULL
) {
1957 return EFI_INVALID_PARAMETER
;
1961 // Checks whether the request command is supported.
1963 if (!IsExtCommandValid (Packet
)) {
1964 return EFI_UNSUPPORTED
;
1973 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1977 Routine Description:
1979 Checks the requested SCSI command:
1980 Is it supported by this driver?
1981 Is the Data transfer direction reasonable?
1985 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1997 OpCode
= (UINT8
*) (Packet
->Cdb
);
1998 ArrayLen
= (UINT8
) (sizeof (gSupportedATAPICommands
) / sizeof (gSupportedATAPICommands
[0]));
2000 for (Index
= 0; (Index
< ArrayLen
) && (CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)) != 0); Index
++) {
2002 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
2004 // Check whether the requested Command is supported by this driver
2006 if (Packet
->DataDirection
== DataIn
) {
2008 // Check whether the requested data direction conforms to
2009 // what it should be.
2011 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
2016 if (Packet
->DataDirection
== DataOut
) {
2018 // Check whether the requested data direction conforms to
2019 // what it should be.
2021 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
2034 SubmitExtBlockingIoCommand (
2035 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2037 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
2041 Routine Description:
2043 Performs blocking I/O request.
2047 AtapiScsiPrivate: Private data structure for the specified channel.
2048 Target: The Target ID of the ATAPI device to send the SCSI
2049 Request Packet. To ATAPI devices attached on an IDE
2050 Channel, Target ID 0 indicates Master device;Target
2051 ID 1 indicates Slave device.
2052 Packet: The SCSI Request Packet to send to the ATAPI device
2053 specified by Target.
2059 UINT8 PacketCommand
[12];
2060 UINT64 TimeoutInMicroSeconds
;
2061 EFI_STATUS PacketCommandStatus
;
2064 // Fill ATAPI Command Packet according to CDB
2066 ZeroMem (&PacketCommand
, 12);
2067 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
2070 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
2072 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
2075 // Submit ATAPI Command Packet
2077 if (Packet
->DataDirection
== DataIn
) {
2078 PacketCommandStatus
= AtapiPacketCommand (
2082 Packet
->InDataBuffer
,
2083 &(Packet
->InTransferLength
),
2085 TimeoutInMicroSeconds
2089 PacketCommandStatus
= AtapiPacketCommand (
2093 Packet
->OutDataBuffer
,
2094 &(Packet
->OutTransferLength
),
2096 TimeoutInMicroSeconds
2100 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
2101 Packet
->SenseDataLength
= 0;
2102 return PacketCommandStatus
;
2106 // Return SenseData if PacketCommandStatus matches
2107 // the following return codes.
2109 if ((PacketCommandStatus
== EFI_BAD_BUFFER_SIZE
) ||
2110 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
2111 (PacketCommandStatus
== EFI_TIMEOUT
)) {
2114 // avoid submit request sense command continuously.
2116 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
2117 Packet
->SenseDataLength
= 0;
2118 return PacketCommandStatus
;
2121 RequestSenseCommand (
2126 &Packet
->SenseDataLength
2130 return PacketCommandStatus
;
2135 AtapiPacketCommand (
2136 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2138 UINT8
*PacketCommand
,
2141 DATA_DIRECTION Direction
,
2142 UINT64 TimeoutInMicroSeconds
2146 Routine Description:
2148 Submits ATAPI command packet to the specified ATAPI device.
2152 AtapiScsiPrivate: Private data structure for the specified channel.
2153 Target: The Target ID of the ATAPI device to send the SCSI
2154 Request Packet. To ATAPI devices attached on an IDE
2155 Channel, Target ID 0 indicates Master device;Target
2156 ID 1 indicates Slave device.
2157 PacketCommand: Points to the ATAPI command packet.
2158 Buffer: Points to the transferred data.
2159 ByteCount: When input,indicates the buffer size; when output,
2160 indicates the actually transferred data size.
2161 Direction: Indicates the data transfer direction.
2162 TimeoutInMicroSeconds:
2163 The timeout, in micro second units, to use for the
2164 execution of this ATAPI command.
2165 A TimeoutInMicroSeconds value of 0 means that
2166 this function will wait indefinitely for the ATAPI
2168 If TimeoutInMicroSeconds is greater than zero, then
2169 this function will return EFI_TIMEOUT if the time
2170 required to execute the ATAPI command is greater
2171 than TimeoutInMicroSeconds.
2180 UINT16
*CommandIndex
;
2185 // Set all the command parameters by fill related registers.
2186 // Before write to all the following registers, BSY must be 0.
2188 Status
= StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2189 if (EFI_ERROR (Status
)) {
2190 return EFI_DEVICE_ERROR
;
2195 // Select device via Device/Head Register.
2196 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
2199 AtapiScsiPrivate
->PciIo
,
2200 AtapiScsiPrivate
->IoPort
->Head
,
2201 (UINT8
) ((Target
<< 4) | DEFAULT_CMD
) // DEFAULT_CMD: 0xa0 (1010,0000)
2205 // Set all the command parameters by fill related registers.
2206 // Before write to all the following registers, BSY DRQ must be 0.
2208 Status
= StatusDRQClear(AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2210 if (EFI_ERROR (Status
)) {
2211 if (Status
== EFI_ABORTED
) {
2212 Status
= EFI_DEVICE_ERROR
;
2219 // No OVL; No DMA (by setting feature register)
2222 AtapiScsiPrivate
->PciIo
,
2223 AtapiScsiPrivate
->IoPort
->Reg1
.Feature
,
2228 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
2229 // determine how much data should be transfered.
2232 AtapiScsiPrivate
->PciIo
,
2233 AtapiScsiPrivate
->IoPort
->CylinderLsb
,
2234 (UINT8
) (MAX_ATAPI_BYTE_COUNT
& 0x00ff)
2237 AtapiScsiPrivate
->PciIo
,
2238 AtapiScsiPrivate
->IoPort
->CylinderMsb
,
2239 (UINT8
) (MAX_ATAPI_BYTE_COUNT
>> 8)
2243 // DEFAULT_CTL:0x0a (0000,1010)
2244 // Disable interrupt
2247 AtapiScsiPrivate
->PciIo
,
2248 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
2253 // Send Packet command to inform device
2254 // that the following data bytes are command packet.
2257 AtapiScsiPrivate
->PciIo
,
2258 AtapiScsiPrivate
->IoPort
->Reg
.Command
,
2263 // Before data transfer, BSY should be 0 and DRQ should be 1.
2264 // if they are not in specified time frame,
2265 // retrieve Sense Key from Error Register before return.
2267 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2268 if (EFI_ERROR (Status
)) {
2269 if (Status
== EFI_ABORTED
) {
2270 Status
= EFI_DEVICE_ERROR
;
2278 // Send out command packet
2280 CommandIndex
= (UINT16
*) PacketCommand
;
2281 for (Count
= 0; Count
< 6; Count
++, CommandIndex
++) {
2282 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *CommandIndex
);
2286 // call AtapiPassThruPioReadWriteData() function to get
2287 // requested transfer data form device.
2289 return AtapiPassThruPioReadWriteData (
2294 TimeoutInMicroSeconds
2299 AtapiPassThruPioReadWriteData (
2300 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2303 DATA_DIRECTION Direction
,
2304 UINT64 TimeoutInMicroSeconds
2308 Routine Description:
2310 Performs data transfer between ATAPI device and host after the
2311 ATAPI command packet is sent.
2315 AtapiScsiPrivate: Private data structure for the specified channel.
2316 Buffer: Points to the transferred data.
2317 ByteCount: When input,indicates the buffer size; when output,
2318 indicates the actually transferred data size.
2319 Direction: Indicates the data transfer direction.
2320 TimeoutInMicroSeconds:
2321 The timeout, in micro second units, to use for the
2322 execution of this ATAPI command.
2323 A TimeoutInMicroSeconds value of 0 means that
2324 this function will wait indefinitely for the ATAPI
2326 If TimeoutInMicroSeconds is greater than zero, then
2327 this function will return EFI_TIMEOUT if the time
2328 required to execute the ATAPI command is greater
2329 than TimeoutInMicroSeconds.
2337 UINT32 RequiredWordCount
;
2338 UINT32 ActualWordCount
;
2343 Status
= EFI_SUCCESS
;
2346 // Non Data transfer request is also supported.
2348 if (*ByteCount
== 0 || Buffer
== NULL
) {
2350 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
))) {
2351 return EFI_DEVICE_ERROR
;
2356 RequiredWordCount
= *ByteCount
/ 2;
2359 // ActuralWordCount means the word count of data really transfered.
2361 ActualWordCount
= 0;
2363 while (ActualWordCount
< RequiredWordCount
) {
2365 // before each data transfer stream, the host should poll DRQ bit ready,
2366 // which indicates device's ready for data transfer .
2368 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2369 if (EFI_ERROR (Status
)) {
2370 *ByteCount
= ActualWordCount
* 2;
2372 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
2374 if (ActualWordCount
== 0) {
2375 return EFI_DEVICE_ERROR
;
2378 // ActualWordCount > 0
2380 if (ActualWordCount
< RequiredWordCount
) {
2381 return EFI_BAD_BUFFER_SIZE
;
2385 // get current data transfer size from Cylinder Registers.
2387 WordCount
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderMsb
) << 8;
2388 WordCount
= WordCount
| ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderLsb
);
2389 WordCount
= WordCount
& 0xffff;
2393 // perform a series data In/Out.
2395 for (Index
= 0; (Index
< WordCount
) && (ActualWordCount
< RequiredWordCount
); Index
++, ActualWordCount
++) {
2397 if (Direction
== DataIn
) {
2399 *ptrBuffer
= ReadPortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
);
2402 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *ptrBuffer
);
2410 // After data transfer is completed, normally, DRQ bit should clear.
2412 StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2415 // read status register to check whether error happens.
2417 Status
= AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
2419 *ByteCount
= ActualWordCount
* 2;
2427 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2432 Routine Description:
2434 Read one byte from a specified I/O port.
2438 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2453 EFI_PCI_IO_PASS_THROUGH_BAR
,
2464 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2469 Routine Description:
2471 Read one word from a specified I/O port.
2475 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2488 EfiPciIoWidthUint16
,
2489 EFI_PCI_IO_PASS_THROUGH_BAR
,
2500 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2506 Routine Description:
2508 Write one byte to a specified I/O port.
2512 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2514 Data - The data to write
2525 EFI_PCI_IO_PASS_THROUGH_BAR
,
2535 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2541 Routine Description:
2543 Write one word to a specified I/O port.
2547 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2549 Data - The data to write
2559 EfiPciIoWidthUint16
,
2560 EFI_PCI_IO_PASS_THROUGH_BAR
,
2569 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2570 UINT64 TimeoutInMicroSeconds
2574 Routine Description:
2576 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
2577 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2578 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2583 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2584 TimeoutInMicroSeconds - The time to wait for
2593 UINT8 StatusRegister
;
2596 if (TimeoutInMicroSeconds
== 0) {
2599 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2604 StatusRegister
= ReadPortB (
2605 AtapiScsiPrivate
->PciIo
,
2606 AtapiScsiPrivate
->IoPort
->Reg
.Status
2610 // wait for BSY == 0 and DRQ == 0
2612 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
2616 // check whether the command is aborted by the device
2618 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
2620 ErrRegister
= ReadPortB (
2621 AtapiScsiPrivate
->PciIo
,
2622 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2624 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2635 // Loop infinitely if not meeting expected condition
2637 if (TimeoutInMicroSeconds
== 0) {
2653 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2654 UINT64 TimeoutInMicroSeconds
2658 Routine Description:
2660 Check whether DRQ is clear in the Alternate Status Register.
2661 (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should
2662 wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2667 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2668 TimeoutInMicroSeconds - The time to wait for
2677 UINT8 AltStatusRegister
;
2680 if (TimeoutInMicroSeconds
== 0) {
2683 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2688 AltStatusRegister
= ReadPortB (
2689 AtapiScsiPrivate
->PciIo
,
2690 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2694 // wait for BSY == 0 and DRQ == 0
2696 if ((AltStatusRegister
& (DRQ
| BSY
)) == 0) {
2700 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2702 ErrRegister
= ReadPortB (
2703 AtapiScsiPrivate
->PciIo
,
2704 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2706 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2717 // Loop infinitely if not meeting expected condition
2719 if (TimeoutInMicroSeconds
== 0) {
2735 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2736 UINT64 TimeoutInMicroSeconds
2740 Routine Description:
2742 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
2743 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2744 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2749 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2750 TimeoutInMicroSeconds - The time to wait for
2759 UINT8 StatusRegister
;
2762 if (TimeoutInMicroSeconds
== 0) {
2765 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2770 // read Status Register will clear interrupt
2772 StatusRegister
= ReadPortB (
2773 AtapiScsiPrivate
->PciIo
,
2774 AtapiScsiPrivate
->IoPort
->Reg
.Status
2780 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
2784 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
2786 ErrRegister
= ReadPortB (
2787 AtapiScsiPrivate
->PciIo
,
2788 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2790 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2801 // Loop infinitely if not meeting expected condition
2803 if (TimeoutInMicroSeconds
== 0) {
2819 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2820 UINT64 TimeoutInMicroSeconds
2824 Routine Description:
2826 Check whether DRQ is ready in the Alternate Status Register.
2827 (BSY must also be cleared)
2828 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2829 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2834 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2835 TimeoutInMicroSeconds - The time to wait for
2844 UINT8 AltStatusRegister
;
2847 if (TimeoutInMicroSeconds
== 0) {
2850 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2855 // read Status Register will clear interrupt
2857 AltStatusRegister
= ReadPortB (
2858 AtapiScsiPrivate
->PciIo
,
2859 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2864 if ((AltStatusRegister
& (BSY
| DRQ
)) == DRQ
) {
2868 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2870 ErrRegister
= ReadPortB (
2871 AtapiScsiPrivate
->PciIo
,
2872 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2874 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2885 // Loop infinitely if not meeting expected condition
2887 if (TimeoutInMicroSeconds
== 0) {
2902 StatusWaitForBSYClear (
2903 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2904 UINT64 TimeoutInMicroSeconds
2908 Routine Description:
2910 Check whether BSY is clear in the Status Register.
2911 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2912 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2917 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2918 TimeoutInMicroSeconds - The time to wait for
2927 UINT8 StatusRegister
;
2929 if (TimeoutInMicroSeconds
== 0) {
2932 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2937 StatusRegister
= ReadPortB (
2938 AtapiScsiPrivate
->PciIo
,
2939 AtapiScsiPrivate
->IoPort
->Reg
.Status
2941 if ((StatusRegister
& BSY
) == 0x00) {
2951 // Loop infinitely if not meeting expected condition
2953 if (TimeoutInMicroSeconds
== 0) {
2968 AltStatusWaitForBSYClear (
2969 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2970 UINT64 TimeoutInMicroSeconds
2974 Routine Description:
2976 Check whether BSY is clear in the Alternate Status Register.
2977 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2978 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2983 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2984 TimeoutInMicroSeconds - The time to wait for
2993 UINT8 AltStatusRegister
;
2995 if (TimeoutInMicroSeconds
== 0) {
2998 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
3003 AltStatusRegister
= ReadPortB (
3004 AtapiScsiPrivate
->PciIo
,
3005 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
3007 if ((AltStatusRegister
& BSY
) == 0x00) {
3016 // Loop infinitely if not meeting expected condition
3018 if (TimeoutInMicroSeconds
== 0) {
3034 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
3035 UINT64 TimeoutInMicroSeconds
3039 Routine Description:
3041 Check whether DRDY is ready in the Status Register.
3042 (BSY must also be cleared)
3043 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
3044 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
3049 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3050 TimeoutInMicroSeconds - The time to wait for
3059 UINT8 StatusRegister
;
3062 if (TimeoutInMicroSeconds
== 0) {
3065 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
3069 StatusRegister
= ReadPortB (
3070 AtapiScsiPrivate
->PciIo
,
3071 AtapiScsiPrivate
->IoPort
->Reg
.Status
3074 // BSY == 0 , DRDY == 1
3076 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
3080 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
3082 ErrRegister
= ReadPortB (
3083 AtapiScsiPrivate
->PciIo
,
3084 AtapiScsiPrivate
->IoPort
->Reg1
.Error
3086 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
3096 // Loop infinitely if not meeting expected condition
3098 if (TimeoutInMicroSeconds
== 0) {
3113 AltStatusDRDYReady (
3114 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
3115 UINT64 TimeoutInMicroSeconds
3119 Routine Description:
3121 Check whether DRDY is ready in the Alternate Status Register.
3122 (BSY must also be cleared)
3123 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
3124 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
3129 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3130 TimeoutInMicroSeconds - The time to wait for
3139 UINT8 AltStatusRegister
;
3142 if (TimeoutInMicroSeconds
== 0) {
3145 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
3149 AltStatusRegister
= ReadPortB (
3150 AtapiScsiPrivate
->PciIo
,
3151 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
3154 // BSY == 0 , DRDY == 1
3156 if ((AltStatusRegister
& (DRDY
| BSY
)) == DRDY
) {
3160 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
3162 ErrRegister
= ReadPortB (
3163 AtapiScsiPrivate
->PciIo
,
3164 AtapiScsiPrivate
->IoPort
->Reg1
.Error
3166 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
3176 // Loop infinitely if not meeting expected condition
3178 if (TimeoutInMicroSeconds
== 0) {
3193 AtapiPassThruCheckErrorStatus (
3194 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
3198 Routine Description:
3200 Check Error Register for Error Information.
3204 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3212 UINT8 StatusRegister
;
3213 UINT8 ErrorRegister
;
3215 StatusRegister
= ReadPortB (
3216 AtapiScsiPrivate
->PciIo
,
3217 AtapiScsiPrivate
->IoPort
->Reg
.Status
3220 DEBUG_CODE_BEGIN ();
3222 if (StatusRegister
& DWF
) {
3225 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
3230 if (StatusRegister
& CORR
) {
3233 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
3238 if (StatusRegister
& ERR
) {
3239 ErrorRegister
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg1
.Error
);
3242 if (ErrorRegister
& BBK_ERR
) {
3245 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
3250 if (ErrorRegister
& UNC_ERR
) {
3253 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
3258 if (ErrorRegister
& MC_ERR
) {
3261 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
3266 if (ErrorRegister
& ABRT_ERR
) {
3269 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
3274 if (ErrorRegister
& TK0NF_ERR
) {
3277 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
3282 if (ErrorRegister
& AMNF_ERR
) {
3285 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
3293 if ((StatusRegister
& (ERR
| DWF
| CORR
)) == 0) {
3298 return EFI_DEVICE_ERROR
;
3303 Installs Scsi Pass Thru and/or Ext Scsi Pass Thru
3304 protocols based on feature flags.
3306 @param Controller The controller handle to
3307 install these protocols on.
3308 @param AtapiScsiPrivate A pointer to the protocol private
3311 @retval EFI_SUCCESS The installation succeeds.
3312 @retval other The installation fails.
3316 InstallScsiPassThruProtocols (
3317 IN EFI_HANDLE
*ControllerHandle
,
3318 IN ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
3322 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
3323 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
3325 ScsiPassThru
= &AtapiScsiPrivate
->ScsiPassThru
;
3326 ExtScsiPassThru
= &AtapiScsiPrivate
->ExtScsiPassThru
;
3328 if (FeaturePcdGet (PcdSupportScsiPassThru
)) {
3329 ScsiPassThru
= CopyMem (ScsiPassThru
, &gScsiPassThruProtocolTemplate
, sizeof (*ScsiPassThru
));
3330 if (FeaturePcdGet (PcdSupportExtScsiPassThru
)) {
3331 ExtScsiPassThru
= CopyMem (ExtScsiPassThru
, &gExtScsiPassThruProtocolTemplate
, sizeof (*ExtScsiPassThru
));
3332 Status
= gBS
->InstallMultipleProtocolInterfaces (
3334 &gEfiScsiPassThruProtocolGuid
,
3336 &gEfiExtScsiPassThruProtocolGuid
,
3341 Status
= gBS
->InstallMultipleProtocolInterfaces (
3343 &gEfiScsiPassThruProtocolGuid
,
3349 if (FeaturePcdGet (PcdSupportExtScsiPassThru
)) {
3350 ExtScsiPassThru
= CopyMem (ExtScsiPassThru
, &gExtScsiPassThruProtocolTemplate
, sizeof (*ExtScsiPassThru
));
3351 Status
= gBS
->InstallMultipleProtocolInterfaces (
3353 &gEfiExtScsiPassThruProtocolGuid
,
3359 // This driver must support either ScsiPassThru or
3360 // ExtScsiPassThru protocols
3363 Status
= EFI_UNSUPPORTED
;
3371 The user Entry Point for module AtapiPassThru. The user code starts with this function.
3373 @param[in] ImageHandle The firmware allocated handle for the EFI image.
3374 @param[in] SystemTable A pointer to the EFI System Table.
3376 @retval EFI_SUCCESS The entry point is executed successfully.
3377 @retval other Some error occurs when executing this entry point.
3382 InitializeAtapiPassThru(
3383 IN EFI_HANDLE ImageHandle
,
3384 IN EFI_SYSTEM_TABLE
*SystemTable
3390 // Install driver model protocol(s).
3392 Status
= EfiLibInstallDriverBindingComponentName2 (
3395 &gAtapiScsiPassThruDriverBinding
,
3397 &gAtapiScsiPassThruComponentName
,
3398 &gAtapiScsiPassThruComponentName2
3400 ASSERT_EFI_ERROR (Status
);
3403 // Install EFI Driver Supported EFI Version Protocol required for
3404 // EFI drivers that are on PCI and other plug in cards.
3406 gAtapiScsiPassThruDriverSupportedEfiVersion
.FirmwareVersion
= PcdGet32 (PcdDriverSupportedEfiVersion
);
3407 Status
= gBS
->InstallMultipleProtocolInterfaces (
3409 &gEfiDriverSupportedEfiVersionProtocolGuid
,
3410 &gAtapiScsiPassThruDriverSupportedEfiVersion
,
3413 ASSERT_EFI_ERROR (Status
);