2 Copyright (c) 2006, Intel Corporation
3 All rights reserved. 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 static SCSI_COMMAND_SET gEndTable
= { 0xff, (DATA_DIRECTION
) 0xff };
19 /// This table contains all the supported ATAPI commands.
21 static 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_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
;
211 Status
= gBS
->OpenProtocol (
213 &gEfiPciIoProtocolGuid
,
215 This
->DriverBindingHandle
,
217 EFI_OPEN_PROTOCOL_BY_DRIVER
219 if (EFI_ERROR (Status
)) {
224 // Save original PCI attributes
226 Status
= PciIo
->Attributes (
228 EfiPciIoAttributeOperationGet
,
230 &OriginalPciAttributes
233 if (EFI_ERROR (Status
)) {
237 Status
= PciIo
->Attributes (
239 EfiPciIoAttributeOperationSupported
,
243 if (!EFI_ERROR (Status
)) {
244 Supports
&= (EFI_PCI_DEVICE_ENABLE
|
245 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
|
246 EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
);
247 Status
= PciIo
->Attributes (
249 EfiPciIoAttributeOperationEnable
,
254 if (EFI_ERROR (Status
)) {
259 // Create SCSI Pass Thru instance for the IDE channel.
261 Status
= RegisterAtapiScsiPassThru (This
, Controller
, PciIo
, OriginalPciAttributes
);
264 if (EFI_ERROR (Status
)) {
266 // Restore original PCI attributes
270 EfiPciIoAttributeOperationSet
,
271 OriginalPciAttributes
,
277 &gEfiPciIoProtocolGuid
,
278 This
->DriverBindingHandle
,
288 AtapiScsiPassThruDriverBindingStop (
289 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
290 IN EFI_HANDLE Controller
,
291 IN UINTN NumberOfChildren
,
292 IN EFI_HANDLE
*ChildHandleBuffer
298 Stop this driver on ControllerHandle. Support stoping any child handles
299 created by this driver.
303 This - Protocol instance pointer.
304 Controller - Handle of device to stop driver on
305 NumberOfChildren - Number of Children in the ChildHandleBuffer
306 ChildHandleBuffer - List of handles for the children we need to stop.
315 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
316 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
317 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
319 if (FeaturePcdGet (PcdSupportScsiPassThru
)) {
320 Status
= gBS
->OpenProtocol (
322 &gEfiScsiPassThruProtocolGuid
,
323 (VOID
**) &ScsiPassThru
,
324 This
->DriverBindingHandle
,
326 EFI_OPEN_PROTOCOL_GET_PROTOCOL
328 if (EFI_ERROR (Status
)) {
331 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru
);
332 if (FeaturePcdGet (PcdSupportExtScsiPassThru
)) {
333 Status
= gBS
->UninstallMultipleProtocolInterfaces (
335 &gEfiScsiPassThruProtocolGuid
,
336 &AtapiScsiPrivate
->ScsiPassThru
,
337 &gEfiExtScsiPassThruProtocolGuid
,
338 &AtapiScsiPrivate
->ExtScsiPassThru
,
342 Status
= gBS
->UninstallMultipleProtocolInterfaces (
344 &gEfiScsiPassThruProtocolGuid
,
345 &AtapiScsiPrivate
->ScsiPassThru
,
350 Status
= gBS
->OpenProtocol (
352 &gEfiExtScsiPassThruProtocolGuid
,
353 (VOID
**) &ExtScsiPassThru
,
354 This
->DriverBindingHandle
,
356 EFI_OPEN_PROTOCOL_GET_PROTOCOL
358 if (EFI_ERROR (Status
)) {
361 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (ExtScsiPassThru
);
362 Status
= gBS
->UninstallMultipleProtocolInterfaces (
364 &gEfiExtScsiPassThruProtocolGuid
,
365 &AtapiScsiPrivate
->ExtScsiPassThru
,
369 if (EFI_ERROR (Status
)) {
374 // Restore original PCI attributes
376 AtapiScsiPrivate
->PciIo
->Attributes (
377 AtapiScsiPrivate
->PciIo
,
378 EfiPciIoAttributeOperationSet
,
379 AtapiScsiPrivate
->OriginalPciAttributes
,
385 &gEfiPciIoProtocolGuid
,
386 This
->DriverBindingHandle
,
390 gBS
->FreePool (AtapiScsiPrivate
);
396 RegisterAtapiScsiPassThru (
397 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
398 IN EFI_HANDLE Controller
,
399 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
400 IN UINT64 OriginalPciAttributes
405 Attaches SCSI Pass Thru Protocol for specified IDE channel.
408 This - Protocol instance pointer.
409 Controller - Parent device handle to the IDE channel.
410 PciIo - PCI I/O protocol attached on the "Controller".
413 Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.
418 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
419 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[ATAPI_MAX_CHANNEL
];
421 AtapiScsiPrivate
= AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV
));
422 if (AtapiScsiPrivate
== NULL
) {
423 return EFI_OUT_OF_RESOURCES
;
426 AtapiScsiPrivate
->Signature
= ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE
;
427 AtapiScsiPrivate
->Handle
= Controller
;
430 // will reset the IoPort inside each API function.
432 AtapiScsiPrivate
->IoPort
= NULL
;
433 AtapiScsiPrivate
->PciIo
= PciIo
;
434 AtapiScsiPrivate
->OriginalPciAttributes
= OriginalPciAttributes
;
437 // Obtain IDE IO port registers' base addresses
439 Status
= GetIdeRegistersBaseAddr (PciIo
, IdeRegsBaseAddr
);
440 if (EFI_ERROR (Status
)) {
444 InitAtapiIoPortRegisters(AtapiScsiPrivate
, IdeRegsBaseAddr
);
447 // Initialize the LatestTargetId to MAX_TARGET_ID.
449 AtapiScsiPrivate
->LatestTargetId
= MAX_TARGET_ID
;
450 AtapiScsiPrivate
->LatestLun
= 0;
452 Status
= InstallScsiPassThruProtocols (&Controller
, AtapiScsiPrivate
);
459 AtapiScsiPassThruFunction (
460 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
463 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
464 IN EFI_EVENT Event OPTIONAL
470 Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
474 This: The EFI_SCSI_PASS_THRU_PROTOCOL instance.
475 Target: The Target ID of the ATAPI device to send the SCSI
476 Request Packet. To ATAPI devices attached on an IDE
477 Channel, Target ID 0 indicates Master device;Target
478 ID 1 indicates Slave device.
479 Lun: The LUN of the ATAPI device to send the SCSI Request
480 Packet. To the ATAPI device, Lun is always 0.
481 Packet: The SCSI Request Packet to send to the ATAPI device
482 specified by Target and Lun.
483 Event: If non-blocking I/O is not supported then Event is ignored,
484 and blocking I/O is performed.
485 If Event is NULL, then blocking I/O is performed.
486 If Event is not NULL and non blocking I/O is supported,
487 then non-blocking I/O is performed, and Event will be signaled
488 when the SCSI Request Packet completes.
496 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
499 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
502 // Target is not allowed beyond MAX_TARGET_ID
504 if ((Target
> MAX_TARGET_ID
) || (Lun
!= 0)) {
505 return EFI_INVALID_PARAMETER
;
509 // check the data fields in Packet parameter.
511 Status
= CheckSCSIRequestPacket (Packet
);
512 if (EFI_ERROR (Status
)) {
517 // If Request Packet targets at the IDE channel itself,
520 if (Target
== This
->Mode
->AdapterId
) {
521 Packet
->TransferLength
= 0;
526 // According to Target ID, reset the Atapi I/O Register mapping
527 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
528 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
530 if ((Target
/ 2) == 0) {
532 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
535 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
539 // the ATAPI SCSI interface does not support non-blocking I/O
540 // ignore the Event parameter
542 // Performs blocking I/O.
544 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, Packet
);
550 AtapiScsiPassThruGetNextDevice (
551 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
552 IN OUT UINT32
*Target
,
559 Used to retrieve the list of legal Target IDs for SCSI devices
564 This - Protocol instance pointer.
565 Target - On input, a pointer to the Target ID of a SCSI
566 device present on the SCSI channel. On output,
567 a pointer to the Target ID of the next SCSI device
568 present on a SCSI channel. An input value of
569 0xFFFFFFFF retrieves the Target ID of the first
570 SCSI device present on a SCSI channel.
571 Lun - On input, a pointer to the LUN of a SCSI device
572 present on the SCSI channel. On output, a pointer
573 to the LUN of the next SCSI device present on
577 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
578 on the SCSI channel was returned in Target and Lun.
579 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
580 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
581 returned on a previous call to GetNextDevice().
584 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
587 // Retrieve Device Private Data Structure.
589 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
592 // Check whether Target is valid.
594 if (Target
== NULL
|| Lun
== NULL
) {
595 return EFI_INVALID_PARAMETER
;
598 if ((*Target
!= 0xFFFFFFFF) &&
599 ((*Target
!= AtapiScsiPrivate
->LatestTargetId
) ||
600 (*Lun
!= AtapiScsiPrivate
->LatestLun
))) {
601 return EFI_INVALID_PARAMETER
;
604 if (*Target
== MAX_TARGET_ID
) {
605 return EFI_NOT_FOUND
;
608 if (*Target
== 0xFFFFFFFF) {
611 *Target
= AtapiScsiPrivate
->LatestTargetId
+ 1;
617 // Update the LatestTargetId.
619 AtapiScsiPrivate
->LatestTargetId
= *Target
;
620 AtapiScsiPrivate
->LatestLun
= *Lun
;
628 AtapiScsiPassThruBuildDevicePath (
629 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
632 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
638 Used to allocate and build a device path node for a SCSI device
639 on a SCSI channel. Would not build device path for a SCSI Host Controller.
643 This - Protocol instance pointer.
644 Target - The Target ID of the SCSI device for which
645 a device path node is to be allocated and built.
646 Lun - The LUN of the SCSI device for which a device
647 path node is to be allocated and built.
648 DevicePath - A pointer to a single device path node that
649 describes the SCSI device specified by
650 Target and Lun. This function is responsible
651 for allocating the buffer DevicePath with the boot
652 service AllocatePool(). It is the caller's
653 responsibility to free DevicePath when the caller
654 is finished with DevicePath.
656 EFI_SUCCESS - The device path node that describes the SCSI device
657 specified by Target and Lun was allocated and
658 returned in DevicePath.
659 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
660 not exist on the SCSI channel.
661 EFI_INVALID_PARAMETER - DevicePath is NULL.
662 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
670 // Validate parameters passed in.
673 if (DevicePath
== NULL
) {
674 return EFI_INVALID_PARAMETER
;
678 // can not build device path for the SCSI Host Controller.
680 if ((Target
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
681 return EFI_NOT_FOUND
;
684 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
686 return EFI_OUT_OF_RESOURCES
;
689 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
690 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
691 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
693 Node
->Atapi
.PrimarySecondary
= (UINT8
) (Target
/ 2);
694 Node
->Atapi
.SlaveMaster
= (UINT8
) (Target
% 2);
695 Node
->Atapi
.Lun
= (UINT16
) Lun
;
697 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
704 AtapiScsiPassThruGetTargetLun (
705 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
706 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
714 Used to translate a device path node to a Target ID and LUN.
718 This - Protocol instance pointer.
719 DevicePath - A pointer to the device path node that
720 describes a SCSI device on the SCSI channel.
721 Target - A pointer to the Target ID of a SCSI device
723 Lun - A pointer to the LUN of a SCSI device on
727 EFI_SUCCESS - DevicePath was successfully translated to a
728 Target ID and LUN, and they were returned
730 EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
731 EFI_UNSUPPORTED - This driver does not support the device path
732 node type in DevicePath.
733 EFI_NOT_FOUND - A valid translation from DevicePath to a
734 Target ID and LUN does not exist.
740 // Validate parameters passed in.
742 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
743 return EFI_INVALID_PARAMETER
;
747 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
749 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
750 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
751 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
752 return EFI_UNSUPPORTED
;
755 Node
= (EFI_DEV_PATH
*) DevicePath
;
757 *Target
= Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
;
758 *Lun
= Node
->Atapi
.Lun
;
760 if (*Target
> (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
761 return EFI_NOT_FOUND
;
769 AtapiScsiPassThruResetChannel (
770 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
776 Resets a SCSI channel.This operation resets all the
777 SCSI devices connected to the SCSI channel.
781 This - Protocol instance pointer.
785 EFI_SUCCESS - The SCSI channel was reset.
786 EFI_UNSUPPORTED - The SCSI channel does not support
787 a channel reset operation.
788 EFI_DEVICE_ERROR - A device error occurred while
789 attempting to reset the SCSI channel.
790 EFI_TIMEOUT - A timeout occurred while attempting
791 to reset the SCSI channel.
794 UINT8 DeviceControlValue
;
795 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
799 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
803 // Reset both Primary channel and Secondary channel.
804 // so, the IoPort pointer must point to the right I/O Register group
806 for (Index
= 0; Index
< 2; Index
++) {
810 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[Index
];
812 DeviceControlValue
= 0;
814 // set SRST bit to initiate soft reset
816 DeviceControlValue
|= SRST
;
820 DeviceControlValue
|= bit (1);
822 AtapiScsiPrivate
->PciIo
,
823 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
836 DeviceControlValue
&= 0xfb;
838 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
841 // slave device needs at most 31s to clear BSY
843 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000) != EFI_TIMEOUT
) {
857 AtapiScsiPassThruResetTarget (
858 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
866 Resets a SCSI device that is connected to a SCSI channel.
870 This - Protocol instance pointer.
871 Target - The Target ID of the SCSI device to reset.
872 Lun - The LUN of the SCSI device to reset.
876 EFI_SUCCESS - The SCSI device specified by Target and
878 EFI_UNSUPPORTED - The SCSI channel does not support a target
880 EFI_INVALID_PARAMETER - Target or Lun are invalid.
881 EFI_DEVICE_ERROR - A device error occurred while attempting
882 to reset the SCSI device specified by Target
884 EFI_TIMEOUT - A timeout occurred while attempting to reset
885 the SCSI device specified by Target and Lun.
888 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
892 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
894 if ((Target
> MAX_TARGET_ID
) || (Lun
!= 0)) {
895 return EFI_INVALID_PARAMETER
;
898 // Directly return EFI_SUCCESS if want to reset the host controller
900 if (Target
== This
->Mode
->AdapterId
) {
905 // According to Target ID, reset the Atapi I/O Register mapping
906 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
907 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
909 if ((Target
/ 2) == 0) {
910 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
912 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
916 // for ATAPI device, no need to wait DRDY ready after device selecting.
918 // bit7 and bit5 are both set to 1 for backward compatibility
920 DeviceSelect
= (UINT8
) (((bit (7) | bit (5)) | (Target
<< 4)));
921 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
923 Command
= ATAPI_SOFT_RESET_CMD
;
924 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
927 // BSY clear is the only status return to the host by the device
928 // when reset is complete.
929 // slave device needs at most 31s to clear BSY
931 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000))) {
936 // stall 5 seconds to make the device status stable
938 gBS
->Stall (5000000);
945 AtapiExtScsiPassThruFunction (
946 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
949 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
950 IN EFI_EVENT Event OPTIONAL
956 Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
960 This: The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
961 Target: The Target ID of the ATAPI device to send the SCSI
962 Request Packet. To ATAPI devices attached on an IDE
963 Channel, Target ID 0 indicates Master device;Target
964 ID 1 indicates Slave device.
965 Lun: The LUN of the ATAPI device to send the SCSI Request
966 Packet. To the ATAPI device, Lun is always 0.
967 Packet: The SCSI Request Packet to send to the ATAPI device
968 specified by Target and Lun.
969 Event: If non-blocking I/O is not supported then Event is ignored,
970 and blocking I/O is performed.
971 If Event is NULL, then blocking I/O is performed.
972 If Event is not NULL and non blocking I/O is supported,
973 then non-blocking I/O is performed, and Event will be signaled
974 when the SCSI Request Packet completes.
983 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
986 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
989 // For ATAPI device, UINT8 is enough to represent the SCSI ID on channel.
991 TargetId
= Target
[0];
994 // Target is not allowed beyond MAX_TARGET_ID
996 if ((TargetId
> MAX_TARGET_ID
) || (Lun
!= 0)) {
997 return EFI_INVALID_PARAMETER
;
1001 // check the data fields in Packet parameter.
1003 Status
= CheckExtSCSIRequestPacket (Packet
);
1004 if (EFI_ERROR (Status
)) {
1009 // If Request Packet targets at the IDE channel itself,
1012 if (TargetId
== (UINT8
)This
->Mode
->AdapterId
) {
1013 Packet
->InTransferLength
= Packet
->OutTransferLength
= 0;
1018 // According to Target ID, reset the Atapi I/O Register mapping
1019 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
1020 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
1022 if ((TargetId
/ 2) == 0) {
1023 TargetId
= (UINT8
) (TargetId
% 2);
1024 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
1026 TargetId
= (UINT8
) (TargetId
% 2);
1027 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
1031 // the ATAPI SCSI interface does not support non-blocking I/O
1032 // ignore the Event parameter
1034 // Performs blocking I/O.
1036 Status
= SubmitExtBlockingIoCommand (AtapiScsiPrivate
, TargetId
, Packet
);
1042 AtapiExtScsiPassThruGetNextTargetLun (
1043 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1044 IN OUT UINT8
**Target
,
1049 Routine Description:
1051 Used to retrieve the list of legal Target IDs for SCSI devices
1056 This - Protocol instance pointer.
1057 Target - On input, a pointer to the Target ID of a SCSI
1058 device present on the SCSI channel. On output,
1059 a pointer to the Target ID of the next SCSI device
1060 present on a SCSI channel. An input value of
1061 0xFFFFFFFF retrieves the Target ID of the first
1062 SCSI device present on a SCSI channel.
1063 Lun - On input, a pointer to the LUN of a SCSI device
1064 present on the SCSI channel. On output, a pointer
1065 to the LUN of the next SCSI device present on
1069 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
1070 on the SCSI channel was returned in Target and Lun.
1071 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
1072 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
1073 returned on a previous call to GetNextDevice().
1078 UINT8 ScsiId
[TARGET_MAX_BYTES
];
1079 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1082 // Retrieve Device Private Data Structure.
1084 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1087 // Check whether Target is valid.
1089 if (*Target
== NULL
|| Lun
== NULL
) {
1090 return EFI_INVALID_PARAMETER
;
1093 SetMem (ScsiId
, TARGET_MAX_BYTES
, 0xFF);
1095 TargetId
= (*Target
)[0];
1098 // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
1100 if (CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) {
1101 for (ByteIndex
= 1; ByteIndex
< TARGET_MAX_BYTES
; ByteIndex
++) {
1102 if ((*Target
)[ByteIndex
] != 0) {
1103 return EFI_INVALID_PARAMETER
;
1108 if ((CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) &&
1109 ((TargetId
!= AtapiScsiPrivate
->LatestTargetId
) ||
1110 (*Lun
!= AtapiScsiPrivate
->LatestLun
))) {
1111 return EFI_INVALID_PARAMETER
;
1114 if (TargetId
== MAX_TARGET_ID
) {
1115 return EFI_NOT_FOUND
;
1118 if (CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) == 0) {
1119 SetMem (*Target
, TARGET_MAX_BYTES
,0);
1121 (*Target
)[0] = (UINT8
) (AtapiScsiPrivate
->LatestTargetId
+ 1);
1127 // Update the LatestTargetId.
1129 AtapiScsiPrivate
->LatestTargetId
= (*Target
)[0];
1130 AtapiScsiPrivate
->LatestLun
= *Lun
;
1138 AtapiExtScsiPassThruBuildDevicePath (
1139 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1142 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
1146 Routine Description:
1148 Used to allocate and build a device path node for a SCSI device
1149 on a SCSI channel. Would not build device path for a SCSI Host Controller.
1153 This - Protocol instance pointer.
1154 Target - The Target ID of the SCSI device for which
1155 a device path node is to be allocated and built.
1156 Lun - The LUN of the SCSI device for which a device
1157 path node is to be allocated and built.
1158 DevicePath - A pointer to a single device path node that
1159 describes the SCSI device specified by
1160 Target and Lun. This function is responsible
1161 for allocating the buffer DevicePath with the boot
1162 service AllocatePool(). It is the caller's
1163 responsibility to free DevicePath when the caller
1164 is finished with DevicePath.
1166 EFI_SUCCESS - The device path node that describes the SCSI device
1167 specified by Target and Lun was allocated and
1168 returned in DevicePath.
1169 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
1170 not exist on the SCSI channel.
1171 EFI_INVALID_PARAMETER - DevicePath is NULL.
1172 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
1179 TargetId
= Target
[0];
1182 // Validate parameters passed in.
1185 if (DevicePath
== NULL
) {
1186 return EFI_INVALID_PARAMETER
;
1190 // can not build device path for the SCSI Host Controller.
1192 if ((TargetId
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
1193 return EFI_NOT_FOUND
;
1196 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
1198 return EFI_OUT_OF_RESOURCES
;
1201 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
1202 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
1203 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
1205 Node
->Atapi
.PrimarySecondary
= (UINT8
) (TargetId
/ 2);
1206 Node
->Atapi
.SlaveMaster
= (UINT8
) (TargetId
% 2);
1207 Node
->Atapi
.Lun
= (UINT16
) Lun
;
1209 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
1216 AtapiExtScsiPassThruGetTargetLun (
1217 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1218 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1224 Routine Description:
1226 Used to translate a device path node to a Target ID and LUN.
1230 This - Protocol instance pointer.
1231 DevicePath - A pointer to the device path node that
1232 describes a SCSI device on the SCSI channel.
1233 Target - A pointer to the Target ID of a SCSI device
1234 on the SCSI channel.
1235 Lun - A pointer to the LUN of a SCSI device on
1239 EFI_SUCCESS - DevicePath was successfully translated to a
1240 Target ID and LUN, and they were returned
1242 EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
1243 EFI_UNSUPPORTED - This driver does not support the device path
1244 node type in DevicePath.
1245 EFI_NOT_FOUND - A valid translation from DevicePath to a
1246 Target ID and LUN does not exist.
1252 // Validate parameters passed in.
1254 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
1255 return EFI_INVALID_PARAMETER
;
1259 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
1261 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
1262 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
1263 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
1264 return EFI_UNSUPPORTED
;
1267 ZeroMem (*Target
, TARGET_MAX_BYTES
);
1269 Node
= (EFI_DEV_PATH
*) DevicePath
;
1271 (*Target
)[0] = (UINT8
) (Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
);
1272 *Lun
= Node
->Atapi
.Lun
;
1274 if ((*Target
)[0] > (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
1275 return EFI_NOT_FOUND
;
1283 AtapiExtScsiPassThruResetChannel (
1284 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
1288 Routine Description:
1290 Resets a SCSI channel.This operation resets all the
1291 SCSI devices connected to the SCSI channel.
1295 This - Protocol instance pointer.
1299 EFI_SUCCESS - The SCSI channel was reset.
1300 EFI_UNSUPPORTED - The SCSI channel does not support
1301 a channel reset operation.
1302 EFI_DEVICE_ERROR - A device error occurred while
1303 attempting to reset the SCSI channel.
1304 EFI_TIMEOUT - A timeout occurred while attempting
1305 to reset the SCSI channel.
1308 UINT8 DeviceControlValue
;
1310 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1313 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1316 // Reset both Primary channel and Secondary channel.
1317 // so, the IoPort pointer must point to the right I/O Register group
1318 // And if there is a channel reset successfully, return EFI_SUCCESS.
1320 for (Index
= 0; Index
< 2; Index
++) {
1324 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[Index
];
1326 DeviceControlValue
= 0;
1328 // set SRST bit to initiate soft reset
1330 DeviceControlValue
|= SRST
;
1332 // disable Interrupt
1334 DeviceControlValue
|= bit (1);
1336 AtapiScsiPrivate
->PciIo
,
1337 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
1350 DeviceControlValue
&= 0xfb;
1352 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
1355 // slave device needs at most 31s to clear BSY
1357 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000) != EFI_TIMEOUT
) {
1371 AtapiExtScsiPassThruResetTarget (
1372 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1378 Routine Description:
1380 Resets a SCSI device that is connected to a SCSI channel.
1384 This - Protocol instance pointer.
1385 Target - The Target ID of the SCSI device to reset.
1386 Lun - The LUN of the SCSI device to reset.
1390 EFI_SUCCESS - The SCSI device specified by Target and
1392 EFI_UNSUPPORTED - The SCSI channel does not support a target
1394 EFI_INVALID_PARAMETER - Target or Lun are invalid.
1395 EFI_DEVICE_ERROR - A device error occurred while attempting
1396 to reset the SCSI device specified by Target
1398 EFI_TIMEOUT - A timeout occurred while attempting to reset
1399 the SCSI device specified by Target and Lun.
1405 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1407 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1408 TargetId
= Target
[0];
1410 if ((TargetId
> MAX_TARGET_ID
) || (Lun
!= 0)) {
1411 return EFI_INVALID_PARAMETER
;
1414 // Directly return EFI_SUCCESS if want to reset the host controller
1416 if (TargetId
== This
->Mode
->AdapterId
) {
1421 // According to Target ID, reset the Atapi I/O Register mapping
1422 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
1423 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
1425 if ((TargetId
/ 2) == 0) {
1426 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
1428 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
1432 // for ATAPI device, no need to wait DRDY ready after device selecting.
1434 // bit7 and bit5 are both set to 1 for backward compatibility
1436 DeviceSelect
= (UINT8
) (((bit (7) | bit (5)) | (TargetId
<< 4)));
1437 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
1439 Command
= ATAPI_SOFT_RESET_CMD
;
1440 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
1443 // BSY clear is the only status return to the host by the device
1444 // when reset is complete.
1445 // slave device needs at most 31s to clear BSY
1447 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000))) {
1452 // stall 5 seconds to make the device status stable
1454 gBS
->Stall (5000000);
1462 AtapiExtScsiPassThruGetNextTarget (
1463 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*This
,
1464 IN OUT UINT8
**Target
1468 Routine Description:
1469 Used to retrieve the list of legal Target IDs for SCSI devices
1473 This - Protocol instance pointer.
1474 Target - On input, a pointer to the Target ID of a SCSI
1475 device present on the SCSI channel. On output,
1476 a pointer to the Target ID of the next SCSI device
1477 present on a SCSI channel. An input value of
1478 0xFFFFFFFF retrieves the Target ID of the first
1479 SCSI device present on a SCSI channel.
1480 Lun - On input, a pointer to the LUN of a SCSI device
1481 present on the SCSI channel. On output, a pointer
1482 to the LUN of the next SCSI device present on
1486 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
1487 on the SCSI channel was returned in Target and Lun.
1488 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
1489 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
1490 returned on a previous call to GetNextDevice().
1494 UINT8 ScsiId
[TARGET_MAX_BYTES
];
1495 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
1499 // Retrieve Device Private Data Structure.
1501 AtapiScsiPrivate
= ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
1504 // Check whether Target is valid.
1506 if (*Target
== NULL
) {
1507 return EFI_INVALID_PARAMETER
;
1510 TargetId
= (*Target
)[0];
1511 SetMem (ScsiId
, TARGET_MAX_BYTES
, 0xFF);
1514 // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
1516 if (CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) {
1517 for (ByteIndex
= 1; ByteIndex
< TARGET_MAX_BYTES
; ByteIndex
++) {
1518 if ((*Target
)[ByteIndex
] != 0) {
1519 return EFI_INVALID_PARAMETER
;
1524 if ((CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) != 0) &&(TargetId
!= AtapiScsiPrivate
->LatestTargetId
)) {
1525 return EFI_INVALID_PARAMETER
;
1528 if (TargetId
== MAX_TARGET_ID
) {
1529 return EFI_NOT_FOUND
;
1532 if ((CompareMem(*Target
, ScsiId
, TARGET_MAX_BYTES
) == 0)) {
1533 SetMem (*Target
, TARGET_MAX_BYTES
, 0);
1535 (*Target
)[0] = (UINT8
) (AtapiScsiPrivate
->LatestTargetId
+ 1);
1539 // Update the LatestTargetId.
1541 AtapiScsiPrivate
->LatestTargetId
= (*Target
)[0];
1542 AtapiScsiPrivate
->LatestLun
= 0;
1548 GetIdeRegistersBaseAddr (
1549 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1550 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
1554 Routine Description:
1555 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
1556 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
1557 the PCI IDE controller's Configuration Space.
1560 PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance
1561 IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to
1562 receive IDE IO port registers' base addresses
1573 Status
= PciIo
->Pci
.Read (
1581 if (EFI_ERROR (Status
)) {
1585 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
1586 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
1587 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
1590 // The BARs should be of IO type
1592 if ((PciData
.Device
.Bar
[0] & BIT0
) == 0 ||
1593 (PciData
.Device
.Bar
[1] & BIT0
) == 0) {
1594 return EFI_UNSUPPORTED
;
1597 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
1598 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
1599 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
1600 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
1603 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
1604 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
1605 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
1608 // The BARs should be of IO type
1610 if ((PciData
.Device
.Bar
[2] & BIT0
) == 0 ||
1611 (PciData
.Device
.Bar
[3] & BIT0
) == 0) {
1612 return EFI_UNSUPPORTED
;
1615 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
1616 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
1617 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
1618 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
1625 InitAtapiIoPortRegisters (
1626 IN ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1627 IN IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
1631 Routine Description:
1633 Initialize each Channel's Base Address of CommandBlock and ControlBlock.
1637 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
1638 IdeRegsBaseAddr - The pointer of IDE_REGISTERS_BASE_ADDR
1648 UINT16 CommandBlockBaseAddr
;
1649 UINT16 ControlBlockBaseAddr
;
1650 IDE_BASE_REGISTERS
*RegisterPointer
;
1653 for (IdeChannel
= 0; IdeChannel
< ATAPI_MAX_CHANNEL
; IdeChannel
++) {
1655 RegisterPointer
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[IdeChannel
];
1658 // Initialize IDE IO port addresses, including Command Block registers
1659 // and Control Block registers
1661 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeChannel
].CommandBlockBaseAddr
;
1662 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeChannel
].ControlBlockBaseAddr
;
1664 RegisterPointer
->Data
= CommandBlockBaseAddr
;
1665 (*(UINT16
*) &RegisterPointer
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
1666 RegisterPointer
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
1667 RegisterPointer
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
1668 RegisterPointer
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
1669 RegisterPointer
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
1670 RegisterPointer
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
1671 (*(UINT16
*) &RegisterPointer
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
1673 (*(UINT16
*) &RegisterPointer
->Alt
) = ControlBlockBaseAddr
;
1674 RegisterPointer
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
1681 CheckSCSIRequestPacket (
1682 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1686 Routine Description:
1688 Checks the parameters in the SCSI Request Packet to make sure
1689 they are valid for a SCSI Pass Thru request.
1693 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1701 if (Packet
== NULL
) {
1702 return EFI_INVALID_PARAMETER
;
1705 if (!ValidCdbLength (Packet
->CdbLength
)) {
1706 return EFI_INVALID_PARAMETER
;
1709 if (Packet
->Cdb
== NULL
) {
1710 return EFI_INVALID_PARAMETER
;
1714 // Checks whether the request command is supported.
1716 if (!IsCommandValid (Packet
)) {
1717 return EFI_UNSUPPORTED
;
1725 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1729 Routine Description:
1731 Checks the requested SCSI command:
1732 Is it supported by this driver?
1733 Is the Data transfer direction reasonable?
1737 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1748 OpCode
= (UINT8
*) (Packet
->Cdb
);
1750 for (Index
= 0; CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)); Index
++) {
1752 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
1754 // Check whether the requested Command is supported by this driver
1756 if (Packet
->DataDirection
== DataIn
) {
1758 // Check whether the requested data direction conforms to
1759 // what it should be.
1761 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
1766 if (Packet
->DataDirection
== DataOut
) {
1768 // Check whether the requested data direction conforms to
1769 // what it should be.
1771 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
1784 SubmitBlockingIoCommand (
1785 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1787 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1791 Routine Description:
1793 Performs blocking I/O request.
1797 AtapiScsiPrivate: Private data structure for the specified channel.
1798 Target: The Target ID of the ATAPI device to send the SCSI
1799 Request Packet. To ATAPI devices attached on an IDE
1800 Channel, Target ID 0 indicates Master device;Target
1801 ID 1 indicates Slave device.
1802 Packet: The SCSI Request Packet to send to the ATAPI device
1803 specified by Target.
1809 UINT8 PacketCommand
[12];
1810 UINT64 TimeoutInMicroSeconds
;
1811 EFI_STATUS PacketCommandStatus
;
1814 // Fill ATAPI Command Packet according to CDB
1816 ZeroMem (&PacketCommand
, 12);
1817 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
1820 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
1822 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
1825 // Submit ATAPI Command Packet
1827 PacketCommandStatus
= AtapiPacketCommand (
1832 &(Packet
->TransferLength
),
1833 (DATA_DIRECTION
) Packet
->DataDirection
,
1834 TimeoutInMicroSeconds
1836 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
1837 Packet
->SenseDataLength
= 0;
1838 return PacketCommandStatus
;
1842 // Return SenseData if PacketCommandStatus matches
1843 // the following return codes.
1845 if ((PacketCommandStatus
== EFI_BAD_BUFFER_SIZE
) ||
1846 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
1847 (PacketCommandStatus
== EFI_TIMEOUT
)) {
1850 // avoid submit request sense command continuously.
1852 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
1853 Packet
->SenseDataLength
= 0;
1854 return PacketCommandStatus
;
1857 RequestSenseCommand (
1862 &Packet
->SenseDataLength
1866 return PacketCommandStatus
;
1870 RequestSenseCommand (
1871 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1875 UINT8
*SenseDataLength
1879 Routine Description:
1881 Sumbit request sense command
1885 AtapiScsiPrivate - The pionter of ATAPI_SCSI_PASS_THRU_DEV
1886 Target - The target ID
1887 Timeout - The time to complete the command
1888 SenseData - The buffer to fill in sense data
1889 SenseDataLength - The length of buffer
1897 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet
;
1901 ZeroMem (&Packet
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1904 Cdb
[0] = OP_REQUEST_SENSE
;
1905 Cdb
[4] = (UINT8
) (*SenseDataLength
);
1907 Packet
.Timeout
= Timeout
;
1908 Packet
.DataBuffer
= SenseData
;
1909 Packet
.SenseData
= NULL
;
1911 Packet
.TransferLength
= *SenseDataLength
;
1912 Packet
.CdbLength
= 12;
1913 Packet
.DataDirection
= DataIn
;
1915 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, &Packet
);
1916 *SenseDataLength
= (UINT8
) (Packet
.TransferLength
);
1921 CheckExtSCSIRequestPacket (
1922 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1926 Routine Description:
1928 Checks the parameters in the SCSI Request Packet to make sure
1929 they are valid for a SCSI Pass Thru request.
1933 Packet - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1941 if (Packet
== NULL
) {
1942 return EFI_INVALID_PARAMETER
;
1945 if (!ValidCdbLength (Packet
->CdbLength
)) {
1946 return EFI_INVALID_PARAMETER
;
1949 if (Packet
->Cdb
== NULL
) {
1950 return EFI_INVALID_PARAMETER
;
1954 // Checks whether the request command is supported.
1956 if (!IsExtCommandValid (Packet
)) {
1957 return EFI_UNSUPPORTED
;
1966 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1970 Routine Description:
1972 Checks the requested SCSI command:
1973 Is it supported by this driver?
1974 Is the Data transfer direction reasonable?
1978 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1989 OpCode
= (UINT8
*) (Packet
->Cdb
);
1991 for (Index
= 0; CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)); Index
++) {
1993 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
1995 // Check whether the requested Command is supported by this driver
1997 if (Packet
->DataDirection
== DataIn
) {
1999 // Check whether the requested data direction conforms to
2000 // what it should be.
2002 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
2007 if (Packet
->DataDirection
== DataOut
) {
2009 // Check whether the requested data direction conforms to
2010 // what it should be.
2012 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
2025 SubmitExtBlockingIoCommand (
2026 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2028 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
2032 Routine Description:
2034 Performs blocking I/O request.
2038 AtapiScsiPrivate: Private data structure for the specified channel.
2039 Target: The Target ID of the ATAPI device to send the SCSI
2040 Request Packet. To ATAPI devices attached on an IDE
2041 Channel, Target ID 0 indicates Master device;Target
2042 ID 1 indicates Slave device.
2043 Packet: The SCSI Request Packet to send to the ATAPI device
2044 specified by Target.
2050 UINT8 PacketCommand
[12];
2051 UINT64 TimeoutInMicroSeconds
;
2052 EFI_STATUS PacketCommandStatus
;
2055 // Fill ATAPI Command Packet according to CDB
2057 ZeroMem (&PacketCommand
, 12);
2058 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
2061 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
2063 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
2066 // Submit ATAPI Command Packet
2068 if (Packet
->DataDirection
== DataIn
) {
2069 PacketCommandStatus
= AtapiPacketCommand (
2073 Packet
->InDataBuffer
,
2074 &(Packet
->InTransferLength
),
2076 TimeoutInMicroSeconds
2080 PacketCommandStatus
= AtapiPacketCommand (
2084 Packet
->OutDataBuffer
,
2085 &(Packet
->OutTransferLength
),
2087 TimeoutInMicroSeconds
2091 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
2092 Packet
->SenseDataLength
= 0;
2093 return PacketCommandStatus
;
2097 // Return SenseData if PacketCommandStatus matches
2098 // the following return codes.
2100 if ((PacketCommandStatus
== EFI_BAD_BUFFER_SIZE
) ||
2101 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
2102 (PacketCommandStatus
== EFI_TIMEOUT
)) {
2105 // avoid submit request sense command continuously.
2107 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
2108 Packet
->SenseDataLength
= 0;
2109 return PacketCommandStatus
;
2112 RequestSenseCommand (
2117 &Packet
->SenseDataLength
2121 return PacketCommandStatus
;
2126 AtapiPacketCommand (
2127 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2129 UINT8
*PacketCommand
,
2132 DATA_DIRECTION Direction
,
2133 UINT64 TimeoutInMicroSeconds
2137 Routine Description:
2139 Submits ATAPI command packet to the specified ATAPI device.
2143 AtapiScsiPrivate: Private data structure for the specified channel.
2144 Target: The Target ID of the ATAPI device to send the SCSI
2145 Request Packet. To ATAPI devices attached on an IDE
2146 Channel, Target ID 0 indicates Master device;Target
2147 ID 1 indicates Slave device.
2148 PacketCommand: Points to the ATAPI command packet.
2149 Buffer: Points to the transferred data.
2150 ByteCount: When input,indicates the buffer size; when output,
2151 indicates the actually transferred data size.
2152 Direction: Indicates the data transfer direction.
2153 TimeoutInMicroSeconds:
2154 The timeout, in micro second units, to use for the
2155 execution of this ATAPI command.
2156 A TimeoutInMicroSeconds value of 0 means that
2157 this function will wait indefinitely for the ATAPI
2159 If TimeoutInMicroSeconds is greater than zero, then
2160 this function will return EFI_TIMEOUT if the time
2161 required to execute the ATAPI command is greater
2162 than TimeoutInMicroSeconds.
2171 UINT16
*CommandIndex
;
2176 // Set all the command parameters by fill related registers.
2177 // Before write to all the following registers, BSY must be 0.
2179 Status
= StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2180 if (EFI_ERROR (Status
)) {
2181 return EFI_DEVICE_ERROR
;
2186 // Select device via Device/Head Register.
2187 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
2190 AtapiScsiPrivate
->PciIo
,
2191 AtapiScsiPrivate
->IoPort
->Head
,
2192 (UINT8
) ((Target
<< 4) | DEFAULT_CMD
) // DEFAULT_CMD: 0xa0 (1010,0000)
2196 // Set all the command parameters by fill related registers.
2197 // Before write to all the following registers, BSY DRQ must be 0.
2199 Status
= StatusDRQClear(AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2201 if (EFI_ERROR (Status
)) {
2202 if (Status
== EFI_ABORTED
) {
2203 Status
= EFI_DEVICE_ERROR
;
2210 // No OVL; No DMA (by setting feature register)
2213 AtapiScsiPrivate
->PciIo
,
2214 AtapiScsiPrivate
->IoPort
->Reg1
.Feature
,
2219 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
2220 // determine how much data should be transfered.
2223 AtapiScsiPrivate
->PciIo
,
2224 AtapiScsiPrivate
->IoPort
->CylinderLsb
,
2225 (UINT8
) (MAX_ATAPI_BYTE_COUNT
& 0x00ff)
2228 AtapiScsiPrivate
->PciIo
,
2229 AtapiScsiPrivate
->IoPort
->CylinderMsb
,
2230 (UINT8
) (MAX_ATAPI_BYTE_COUNT
>> 8)
2234 // DEFAULT_CTL:0x0a (0000,1010)
2235 // Disable interrupt
2238 AtapiScsiPrivate
->PciIo
,
2239 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
2244 // Send Packet command to inform device
2245 // that the following data bytes are command packet.
2248 AtapiScsiPrivate
->PciIo
,
2249 AtapiScsiPrivate
->IoPort
->Reg
.Command
,
2254 // Before data transfer, BSY should be 0 and DRQ should be 1.
2255 // if they are not in specified time frame,
2256 // retrieve Sense Key from Error Register before return.
2258 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2259 if (EFI_ERROR (Status
)) {
2260 if (Status
== EFI_ABORTED
) {
2261 Status
= EFI_DEVICE_ERROR
;
2269 // Send out command packet
2271 CommandIndex
= (UINT16
*) PacketCommand
;
2272 for (Count
= 0; Count
< 6; Count
++, CommandIndex
++) {
2273 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *CommandIndex
);
2277 // call AtapiPassThruPioReadWriteData() function to get
2278 // requested transfer data form device.
2280 return AtapiPassThruPioReadWriteData (
2285 TimeoutInMicroSeconds
2290 AtapiPassThruPioReadWriteData (
2291 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2294 DATA_DIRECTION Direction
,
2295 UINT64 TimeoutInMicroSeconds
2299 Routine Description:
2301 Performs data transfer between ATAPI device and host after the
2302 ATAPI command packet is sent.
2306 AtapiScsiPrivate: Private data structure for the specified channel.
2307 Buffer: Points to the transferred data.
2308 ByteCount: When input,indicates the buffer size; when output,
2309 indicates the actually transferred data size.
2310 Direction: Indicates the data transfer direction.
2311 TimeoutInMicroSeconds:
2312 The timeout, in micro second units, to use for the
2313 execution of this ATAPI command.
2314 A TimeoutInMicroSeconds value of 0 means that
2315 this function will wait indefinitely for the ATAPI
2317 If TimeoutInMicroSeconds is greater than zero, then
2318 this function will return EFI_TIMEOUT if the time
2319 required to execute the ATAPI command is greater
2320 than TimeoutInMicroSeconds.
2328 UINT32 RequiredWordCount
;
2329 UINT32 ActualWordCount
;
2334 Status
= EFI_SUCCESS
;
2337 // Non Data transfer request is also supported.
2339 if (*ByteCount
== 0 || Buffer
== NULL
) {
2341 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
))) {
2342 return EFI_DEVICE_ERROR
;
2347 RequiredWordCount
= *ByteCount
/ 2;
2350 // ActuralWordCount means the word count of data really transfered.
2352 ActualWordCount
= 0;
2354 while (ActualWordCount
< RequiredWordCount
) {
2356 // before each data transfer stream, the host should poll DRQ bit ready,
2357 // which indicates device's ready for data transfer .
2359 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2360 if (EFI_ERROR (Status
)) {
2361 *ByteCount
= ActualWordCount
* 2;
2363 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
2365 if (ActualWordCount
== 0) {
2366 return EFI_DEVICE_ERROR
;
2369 // ActualWordCount > 0
2371 if (ActualWordCount
< RequiredWordCount
) {
2372 return EFI_BAD_BUFFER_SIZE
;
2376 // get current data transfer size from Cylinder Registers.
2378 WordCount
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderMsb
) << 8;
2379 WordCount
= WordCount
| ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderLsb
);
2380 WordCount
= WordCount
& 0xffff;
2384 // perform a series data In/Out.
2386 for (Index
= 0; (Index
< WordCount
) && (ActualWordCount
< RequiredWordCount
); Index
++, ActualWordCount
++) {
2388 if (Direction
== DataIn
) {
2390 *ptrBuffer
= ReadPortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
);
2393 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *ptrBuffer
);
2401 // After data transfer is completed, normally, DRQ bit should clear.
2403 StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
2406 // read status register to check whether error happens.
2408 Status
= AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
2410 *ByteCount
= ActualWordCount
* 2;
2418 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2423 Routine Description:
2425 Read one byte from a specified I/O port.
2429 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2444 EFI_PCI_IO_PASS_THROUGH_BAR
,
2455 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2460 Routine Description:
2462 Read one word from a specified I/O port.
2466 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2479 EfiPciIoWidthUint16
,
2480 EFI_PCI_IO_PASS_THROUGH_BAR
,
2491 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2497 Routine Description:
2499 Write one byte to a specified I/O port.
2503 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2505 Data - The data to write
2516 EFI_PCI_IO_PASS_THROUGH_BAR
,
2526 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2532 Routine Description:
2534 Write one word to a specified I/O port.
2538 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2540 Data - The data to write
2550 EfiPciIoWidthUint16
,
2551 EFI_PCI_IO_PASS_THROUGH_BAR
,
2560 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2561 UINT64 TimeoutInMicroSeconds
2565 Routine Description:
2567 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
2568 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2569 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2574 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2575 TimeoutInMicroSeconds - The time to wait for
2584 UINT8 StatusRegister
;
2587 if (TimeoutInMicroSeconds
== 0) {
2590 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2595 StatusRegister
= ReadPortB (
2596 AtapiScsiPrivate
->PciIo
,
2597 AtapiScsiPrivate
->IoPort
->Reg
.Status
2601 // wait for BSY == 0 and DRQ == 0
2603 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
2607 // check whether the command is aborted by the device
2609 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
2611 ErrRegister
= ReadPortB (
2612 AtapiScsiPrivate
->PciIo
,
2613 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2615 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2626 // Loop infinitely if not meeting expected condition
2628 if (TimeoutInMicroSeconds
== 0) {
2644 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2645 UINT64 TimeoutInMicroSeconds
2649 Routine Description:
2651 Check whether DRQ is clear in the Alternate Status Register.
2652 (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should
2653 wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2658 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2659 TimeoutInMicroSeconds - The time to wait for
2668 UINT8 AltStatusRegister
;
2671 if (TimeoutInMicroSeconds
== 0) {
2674 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2679 AltStatusRegister
= ReadPortB (
2680 AtapiScsiPrivate
->PciIo
,
2681 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2685 // wait for BSY == 0 and DRQ == 0
2687 if ((AltStatusRegister
& (DRQ
| BSY
)) == 0) {
2691 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2693 ErrRegister
= ReadPortB (
2694 AtapiScsiPrivate
->PciIo
,
2695 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2697 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2708 // Loop infinitely if not meeting expected condition
2710 if (TimeoutInMicroSeconds
== 0) {
2726 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2727 UINT64 TimeoutInMicroSeconds
2731 Routine Description:
2733 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
2734 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2735 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2740 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2741 TimeoutInMicroSeconds - The time to wait for
2750 UINT8 StatusRegister
;
2753 if (TimeoutInMicroSeconds
== 0) {
2756 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2761 // read Status Register will clear interrupt
2763 StatusRegister
= ReadPortB (
2764 AtapiScsiPrivate
->PciIo
,
2765 AtapiScsiPrivate
->IoPort
->Reg
.Status
2771 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
2775 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
2777 ErrRegister
= ReadPortB (
2778 AtapiScsiPrivate
->PciIo
,
2779 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2781 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2792 // Loop infinitely if not meeting expected condition
2794 if (TimeoutInMicroSeconds
== 0) {
2810 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2811 UINT64 TimeoutInMicroSeconds
2815 Routine Description:
2817 Check whether DRQ is ready in the Alternate Status Register.
2818 (BSY must also be cleared)
2819 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2820 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2825 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2826 TimeoutInMicroSeconds - The time to wait for
2835 UINT8 AltStatusRegister
;
2838 if (TimeoutInMicroSeconds
== 0) {
2841 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2846 // read Status Register will clear interrupt
2848 AltStatusRegister
= ReadPortB (
2849 AtapiScsiPrivate
->PciIo
,
2850 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2855 if ((AltStatusRegister
& (BSY
| DRQ
)) == DRQ
) {
2859 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2861 ErrRegister
= ReadPortB (
2862 AtapiScsiPrivate
->PciIo
,
2863 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2865 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2876 // Loop infinitely if not meeting expected condition
2878 if (TimeoutInMicroSeconds
== 0) {
2893 StatusWaitForBSYClear (
2894 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2895 UINT64 TimeoutInMicroSeconds
2899 Routine Description:
2901 Check whether BSY is clear in the Status Register.
2902 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2903 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2908 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2909 TimeoutInMicroSeconds - The time to wait for
2918 UINT8 StatusRegister
;
2920 if (TimeoutInMicroSeconds
== 0) {
2923 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2928 StatusRegister
= ReadPortB (
2929 AtapiScsiPrivate
->PciIo
,
2930 AtapiScsiPrivate
->IoPort
->Reg
.Status
2932 if ((StatusRegister
& BSY
) == 0x00) {
2942 // Loop infinitely if not meeting expected condition
2944 if (TimeoutInMicroSeconds
== 0) {
2959 AltStatusWaitForBSYClear (
2960 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2961 UINT64 TimeoutInMicroSeconds
2965 Routine Description:
2967 Check whether BSY is clear in the Alternate Status Register.
2968 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2969 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2974 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2975 TimeoutInMicroSeconds - The time to wait for
2984 UINT8 AltStatusRegister
;
2986 if (TimeoutInMicroSeconds
== 0) {
2989 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2994 AltStatusRegister
= ReadPortB (
2995 AtapiScsiPrivate
->PciIo
,
2996 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2998 if ((AltStatusRegister
& BSY
) == 0x00) {
3007 // Loop infinitely if not meeting expected condition
3009 if (TimeoutInMicroSeconds
== 0) {
3025 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
3026 UINT64 TimeoutInMicroSeconds
3030 Routine Description:
3032 Check whether DRDY is ready in the Status Register.
3033 (BSY must also be cleared)
3034 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
3035 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
3040 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3041 TimeoutInMicroSeconds - The time to wait for
3050 UINT8 StatusRegister
;
3053 if (TimeoutInMicroSeconds
== 0) {
3056 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
3060 StatusRegister
= ReadPortB (
3061 AtapiScsiPrivate
->PciIo
,
3062 AtapiScsiPrivate
->IoPort
->Reg
.Status
3065 // BSY == 0 , DRDY == 1
3067 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
3071 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
3073 ErrRegister
= ReadPortB (
3074 AtapiScsiPrivate
->PciIo
,
3075 AtapiScsiPrivate
->IoPort
->Reg1
.Error
3077 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
3087 // Loop infinitely if not meeting expected condition
3089 if (TimeoutInMicroSeconds
== 0) {
3104 AltStatusDRDYReady (
3105 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
3106 UINT64 TimeoutInMicroSeconds
3110 Routine Description:
3112 Check whether DRDY is ready in the Alternate Status Register.
3113 (BSY must also be cleared)
3114 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
3115 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
3120 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3121 TimeoutInMicroSeconds - The time to wait for
3130 UINT8 AltStatusRegister
;
3133 if (TimeoutInMicroSeconds
== 0) {
3136 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
3140 AltStatusRegister
= ReadPortB (
3141 AtapiScsiPrivate
->PciIo
,
3142 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
3145 // BSY == 0 , DRDY == 1
3147 if ((AltStatusRegister
& (DRDY
| BSY
)) == DRDY
) {
3151 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
3153 ErrRegister
= ReadPortB (
3154 AtapiScsiPrivate
->PciIo
,
3155 AtapiScsiPrivate
->IoPort
->Reg1
.Error
3157 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
3167 // Loop infinitely if not meeting expected condition
3169 if (TimeoutInMicroSeconds
== 0) {
3184 AtapiPassThruCheckErrorStatus (
3185 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
3189 Routine Description:
3191 Check Error Register for Error Information.
3195 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3203 UINT8 StatusRegister
;
3204 UINT8 ErrorRegister
;
3206 StatusRegister
= ReadPortB (
3207 AtapiScsiPrivate
->PciIo
,
3208 AtapiScsiPrivate
->IoPort
->Reg
.Status
3211 DEBUG_CODE_BEGIN ();
3213 if (StatusRegister
& DWF
) {
3216 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
3221 if (StatusRegister
& CORR
) {
3224 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
3229 if (StatusRegister
& ERR
) {
3230 ErrorRegister
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg1
.Error
);
3233 if (ErrorRegister
& BBK_ERR
) {
3236 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
3241 if (ErrorRegister
& UNC_ERR
) {
3244 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
3249 if (ErrorRegister
& MC_ERR
) {
3252 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
3257 if (ErrorRegister
& ABRT_ERR
) {
3260 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
3265 if (ErrorRegister
& TK0NF_ERR
) {
3268 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
3273 if (ErrorRegister
& AMNF_ERR
) {
3276 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
3284 if ((StatusRegister
& (ERR
| DWF
| CORR
)) == 0) {
3289 return EFI_DEVICE_ERROR
;
3294 Installs Scsi Pass Thru and/or Ext Scsi Pass Thru
3295 protocols based on feature flags.
3297 @param Controller The controller handle to
3298 install these protocols on.
3299 @param AtapiScsiPrivate A pointer to the protocol private
3302 @retval EFI_SUCCESS The installation succeeds.
3303 @retval other The installation fails.
3307 InstallScsiPassThruProtocols (
3308 IN EFI_HANDLE
*ControllerHandle
,
3309 IN ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
3313 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
3314 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
3316 ScsiPassThru
= &AtapiScsiPrivate
->ScsiPassThru
;
3317 ExtScsiPassThru
= &AtapiScsiPrivate
->ExtScsiPassThru
;
3319 if (FeaturePcdGet (PcdSupportScsiPassThru
)) {
3320 ScsiPassThru
= CopyMem (ScsiPassThru
, &gScsiPassThruProtocolTemplate
, sizeof (*ScsiPassThru
));
3321 if (FeaturePcdGet (PcdSupportExtScsiPassThru
)) {
3322 ExtScsiPassThru
= CopyMem (ExtScsiPassThru
, &gExtScsiPassThruProtocolTemplate
, sizeof (*ExtScsiPassThru
));
3323 Status
= gBS
->InstallMultipleProtocolInterfaces (
3325 &gEfiScsiPassThruProtocolGuid
,
3327 &gEfiExtScsiPassThruProtocolGuid
,
3332 Status
= gBS
->InstallMultipleProtocolInterfaces (
3334 &gEfiScsiPassThruProtocolGuid
,
3340 if (FeaturePcdGet (PcdSupportExtScsiPassThru
)) {
3341 ExtScsiPassThru
= CopyMem (ExtScsiPassThru
, &gExtScsiPassThruProtocolTemplate
, sizeof (*ExtScsiPassThru
));
3342 Status
= gBS
->InstallMultipleProtocolInterfaces (
3344 &gEfiExtScsiPassThruProtocolGuid
,
3350 // This driver must support either ScsiPassThru or
3351 // ExtScsiPassThru protocols
3354 Status
= EFI_UNSUPPORTED
;
3362 The user Entry Point for module AtapiPassThru. The user code starts with this function.
3364 @param[in] ImageHandle The firmware allocated handle for the EFI image.
3365 @param[in] SystemTable A pointer to the EFI System Table.
3367 @retval EFI_SUCCESS The entry point is executed successfully.
3368 @retval other Some error occurs when executing this entry point.
3373 InitializeAtapiPassThru(
3374 IN EFI_HANDLE ImageHandle
,
3375 IN EFI_SYSTEM_TABLE
*SystemTable
3381 // Install driver model protocol(s).
3383 Status
= EfiLibInstallDriverBindingComponentName2 (
3386 &gAtapiScsiPassThruDriverBinding
,
3388 &gAtapiScsiPassThruComponentName
,
3389 &gAtapiScsiPassThruComponentName2
3391 ASSERT_EFI_ERROR (Status
);