3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
22 #include "AtapiPassThru.h"
26 AtapiScsiPassThruDriverBindingSupported (
27 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
28 IN EFI_HANDLE Controller
,
29 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
34 AtapiScsiPassThruDriverBindingStart (
35 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
36 IN EFI_HANDLE Controller
,
37 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
42 AtapiScsiPassThruDriverBindingStop (
43 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
44 IN EFI_HANDLE Controller
,
45 IN UINTN NumberOfChildren
,
46 IN EFI_HANDLE
*ChildHandleBuffer
50 // IDE registers' fixed address
52 static IDE_BASE_REGISTERS gAtapiIoPortRegisters
[2] = {
53 { 0x1f0, { 0x1f1 }, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, { 0x1f7 }, { 0x3f6 }, 0x3f7, 0 },
54 { 0x170, { 0x171 }, 0x172, 0x173, 0x174, 0x175, 0x176, { 0x177 }, { 0x376 }, 0x377, 0 }
57 static SCSI_COMMAND_SET gEndTable
= { 0xff, 0xff };
60 // This table contains all the supported ATAPI commands.
62 static SCSI_COMMAND_SET gSupportedATAPICommands
[] = {
63 { OP_INQUIRY
, DataIn
},
64 { OP_LOAD_UNLOAD_CD
, NoData
},
65 { OP_MECHANISM_STATUS
, DataIn
},
66 { OP_MODE_SELECT_10
, DataOut
},
67 { OP_MODE_SENSE_10
, DataIn
},
68 { OP_PAUSE_RESUME
, NoData
},
69 { OP_PLAY_AUDIO_10
, DataIn
},
70 { OP_PLAY_AUDIO_MSF
, DataIn
},
71 { OP_PLAY_CD
, DataIn
},
72 { OP_PLAY_CD_MSF
, DataIn
},
73 { OP_PREVENT_ALLOW_MEDIUM_REMOVAL
,NoData
},
74 { OP_READ_10
, DataIn
},
75 { OP_READ_12
, DataIn
},
76 { OP_READ_CAPACITY
, DataIn
},
77 { OP_READ_CD
, DataIn
},
78 { OP_READ_CD_MSF
, DataIn
},
79 { OP_READ_HEADER
, DataIn
},
80 { OP_READ_SUB_CHANNEL
, DataIn
},
81 { OP_READ_TOC
, DataIn
},
82 { OP_REQUEST_SENSE
, DataIn
},
84 { OP_SEEK_10
, NoData
},
85 { OP_SET_CD_SPEED
, DataOut
},
86 { OP_STOPPLAY_SCAN
, NoData
},
87 { OP_START_STOP_UNIT
, NoData
},
88 { OP_TEST_UNIT_READY
, NoData
},
89 { OP_FORMAT_UNIT
, DataOut
},
90 { OP_READ_FORMAT_CAPACITIES
, DataIn
},
91 { OP_VERIFY
, DataOut
},
92 { OP_WRITE_10
, DataOut
},
93 { OP_WRITE_12
, DataOut
},
94 { OP_WRITE_AND_VERIFY
, DataOut
},
98 static CHAR16
*gControllerNameString
= (CHAR16
*) L
"ATAPI Controller";
99 static CHAR16
*gAtapiChannelString
= (CHAR16
*) L
"ATAPI Channel";
101 EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding
= {
102 AtapiScsiPassThruDriverBindingSupported
,
103 AtapiScsiPassThruDriverBindingStart
,
104 AtapiScsiPassThruDriverBindingStop
,
112 AtapiScsiPassThruDriverBindingSupported (
113 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
114 IN EFI_HANDLE Controller
,
115 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
123 (Standard DriverBinding Protocol Supported() function)
129 // TODO: This - add argument and description to function comment
130 // TODO: Controller - add argument and description to function comment
131 // TODO: RemainingDevicePath - add argument and description to function comment
132 // TODO: EFI_UNSUPPORTED - add return value to function comment
135 EFI_PCI_IO_PROTOCOL
*PciIo
;
139 // Open the IO Abstraction(s) needed to perform the supported test
141 Status
= gBS
->OpenProtocol (
143 &gEfiPciIoProtocolGuid
,
145 This
->DriverBindingHandle
,
147 EFI_OPEN_PROTOCOL_BY_DRIVER
149 if (EFI_ERROR (Status
)) {
153 // Use the PCI I/O Protocol to see if Controller is a IDE Controller that
154 // can be managed by this driver. Read the PCI Configuration Header
157 Status
= PciIo
->Pci
.Read (
161 sizeof (Pci
) / sizeof (UINT32
),
164 if (EFI_ERROR (Status
)) {
167 &gEfiPciIoProtocolGuid
,
168 This
->DriverBindingHandle
,
171 return EFI_UNSUPPORTED
;
174 if (Pci
.Hdr
.ClassCode
[2] != PCI_CLASS_MASS_STORAGE
|| Pci
.Hdr
.ClassCode
[1] != PCI_CLASS_IDE
) {
176 Status
= EFI_UNSUPPORTED
;
181 &gEfiPciIoProtocolGuid
,
182 This
->DriverBindingHandle
,
191 AtapiScsiPassThruDriverBindingStart (
192 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
193 IN EFI_HANDLE Controller
,
194 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
199 Create handles for IDE channels specified by RemainingDevicePath.
200 Install SCSI Pass Thru Protocol onto each created handle.
203 (Standard DriverBinding Protocol Start() function)
209 // TODO: This - add argument and description to function comment
210 // TODO: Controller - add argument and description to function comment
211 // TODO: RemainingDevicePath - add argument and description to function comment
214 EFI_PCI_IO_PROTOCOL
*PciIo
;
217 Status
= gBS
->OpenProtocol (
219 &gEfiPciIoProtocolGuid
,
221 This
->DriverBindingHandle
,
223 EFI_OPEN_PROTOCOL_BY_DRIVER
225 if (EFI_ERROR (Status
)) {
229 Status
= PciIo
->Attributes (
231 EfiPciIoAttributeOperationEnable
,
232 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
,
235 if (EFI_ERROR (Status
)) {
240 // Create SCSI Pass Thru instance for the IDE channel.
242 Status
= RegisterAtapiScsiPassThru (This
, Controller
, PciIo
);
245 if (EFI_ERROR (Status
)) {
249 EfiPciIoAttributeOperationDisable
,
250 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
,
257 &gEfiPciIoProtocolGuid
,
258 This
->DriverBindingHandle
,
268 AtapiScsiPassThruDriverBindingStop (
269 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
270 IN EFI_HANDLE Controller
,
271 IN UINTN NumberOfChildren
,
272 IN EFI_HANDLE
*ChildHandleBuffer
280 (Standard DriverBinding Protocol Stop() function)
286 // TODO: This - add argument and description to function comment
287 // TODO: Controller - add argument and description to function comment
288 // TODO: NumberOfChildren - add argument and description to function comment
289 // TODO: ChildHandleBuffer - add argument and description to function comment
290 // TODO: EFI_SUCCESS - add return value to function comment
293 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
294 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
296 Status
= gBS
->OpenProtocol (
298 &gEfiScsiPassThruProtocolGuid
,
299 (VOID
**) &ScsiPassThru
,
300 This
->DriverBindingHandle
,
302 EFI_OPEN_PROTOCOL_GET_PROTOCOL
304 if (EFI_ERROR (Status
)) {
308 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru
);
310 Status
= gBS
->UninstallProtocolInterface (
312 &gEfiScsiPassThruProtocolGuid
,
313 &AtapiScsiPrivate
->ScsiPassThru
315 if (EFI_ERROR (Status
)) {
319 // Release Pci Io protocol on the controller handle.
321 AtapiScsiPrivate
->PciIo
->Attributes (
322 AtapiScsiPrivate
->PciIo
,
323 EfiPciIoAttributeOperationDisable
,
324 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
,
330 &gEfiPciIoProtocolGuid
,
331 This
->DriverBindingHandle
,
335 gBS
->FreePool (AtapiScsiPrivate
);
341 RegisterAtapiScsiPassThru (
342 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
343 IN EFI_HANDLE Controller
,
344 IN EFI_PCI_IO_PROTOCOL
*PciIo
349 Attaches SCSI Pass Thru Protocol for specified IDE channel.
352 Controller: Parent device handle to the IDE channel.
353 PciIo: PCI I/O protocol attached on the "Controller".
356 Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.
358 // TODO: This - add argument and description to function comment
359 // TODO: Controller - add argument and description to function comment
360 // TODO: PciIo - add argument and description to function comment
361 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
364 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
367 AtapiScsiPrivate
= AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV
));
368 if (AtapiScsiPrivate
== NULL
) {
369 return EFI_OUT_OF_RESOURCES
;
372 Attributes
= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
;
373 CopyMem (AtapiScsiPrivate
->ChannelName
, gAtapiChannelString
, sizeof (gAtapiChannelString
));
378 PciIo
->Attributes (PciIo
, EfiPciIoAttributeOperationSet
, Attributes
, NULL
);
380 AtapiScsiPrivate
->Signature
= ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE
;
381 AtapiScsiPrivate
->Handle
= Controller
;
384 // will reset the IoPort inside each API function.
386 AtapiScsiPrivate
->IoPort
= gAtapiIoPortRegisters
;
387 AtapiScsiPrivate
->PciIo
= PciIo
;
390 // initialize SCSI Pass Thru Protocol interface
392 AtapiScsiPrivate
->ScsiPassThru
.Mode
= &AtapiScsiPrivate
->ScsiPassThruMode
;
393 AtapiScsiPrivate
->ScsiPassThru
.PassThru
= AtapiScsiPassThruFunction
;
394 AtapiScsiPrivate
->ScsiPassThru
.GetNextDevice
= AtapiScsiPassThruGetNextDevice
;
395 AtapiScsiPrivate
->ScsiPassThru
.BuildDevicePath
= AtapiScsiPassThruBuildDevicePath
;
396 AtapiScsiPrivate
->ScsiPassThru
.GetTargetLun
= AtapiScsiPassThruGetTargetLun
;
397 AtapiScsiPrivate
->ScsiPassThru
.ResetChannel
= AtapiScsiPassThruResetChannel
;
398 AtapiScsiPrivate
->ScsiPassThru
.ResetTarget
= AtapiScsiPassThruResetTarget
;
403 CopyMem (AtapiScsiPrivate
->ControllerName
, gControllerNameString
, sizeof (gControllerNameString
));
405 AtapiScsiPrivate
->ScsiPassThruMode
.ControllerName
= AtapiScsiPrivate
->ControllerName
;
406 AtapiScsiPrivate
->ScsiPassThruMode
.ChannelName
= AtapiScsiPrivate
->ChannelName
;
407 AtapiScsiPrivate
->ScsiPassThruMode
.AdapterId
= 4;
409 // non-RAID SCSI controllers should set both physical and logical attributes
411 AtapiScsiPrivate
->ScsiPassThruMode
.Attributes
= EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
412 EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
413 AtapiScsiPrivate
->ScsiPassThruMode
.IoAlign
= 0;
416 // Initialize the LatestTargetId to 0xFFFFFFFF (for the GetNextDevice() call).
418 AtapiScsiPrivate
->LatestTargetId
= 0xFFFFFFFF;
419 AtapiScsiPrivate
->LatestLun
= 0;
421 Status
= gBS
->InstallProtocolInterface (
423 &gEfiScsiPassThruProtocolGuid
,
424 EFI_NATIVE_INTERFACE
,
425 &AtapiScsiPrivate
->ScsiPassThru
432 AtapiScsiPassThruFunction (
433 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
436 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
437 IN EFI_EVENT Event OPTIONAL
442 Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
445 This: The EFI_SCSI_PASS_THRU_PROTOCOL instance.
446 Target: The Target ID of the ATAPI device to send the SCSI
447 Request Packet. To ATAPI devices attached on an IDE
448 Channel, Target ID 0 indicates Master device;Target
449 ID 1 indicates Slave device.
450 Lun: The LUN of the ATAPI device to send the SCSI Request
451 Packet. To the ATAPI device, Lun is always 0.
452 Packet: The SCSI Request Packet to send to the ATAPI device
453 specified by Target and Lun.
454 Event: If non-blocking I/O is not supported then Event is ignored,
455 and blocking I/O is performed.
456 If Event is NULL, then blocking I/O is performed.
457 If Event is not NULL and non blocking I/O is supported,
458 then non-blocking I/O is performed, and Event will be signaled
459 when the SCSI Request Packet completes.
464 // TODO: This - add argument and description to function comment
465 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
466 // TODO: EFI_SUCCESS - add return value to function comment
468 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
471 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
474 // Target is not allowed beyond MAX_TARGET_ID
476 if (Target
> MAX_TARGET_ID
) {
477 return EFI_INVALID_PARAMETER
;
481 // check the data fields in Packet parameter.
483 Status
= CheckSCSIRequestPacket (Packet
);
484 if (EFI_ERROR (Status
)) {
489 // If Request Packet targets at the IDE channel itself,
492 if (Target
== This
->Mode
->AdapterId
) {
493 Packet
->TransferLength
= 0;
498 // According to Target ID, reset the Atapi I/O Register mapping
499 // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],
500 // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]
502 if ((Target
/ 2) == 0) {
503 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[0];
505 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[1];
509 // the ATAPI SCSI interface does not support non-blocking I/O
510 // ignore the Event parameter
512 // Performs blocking I/O.
514 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, Packet
);
520 AtapiScsiPassThruGetNextDevice (
521 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
522 IN OUT UINT32
*Target
,
528 Used to retrieve the list of legal Target IDs for SCSI devices
532 This - Protocol instance pointer.
533 Target - On input, a pointer to the Target ID of a SCSI
534 device present on the SCSI channel. On output,
535 a pointer to the Target ID of the next SCSI device
536 present on a SCSI channel. An input value of
537 0xFFFFFFFF retrieves the Target ID of the first
538 SCSI device present on a SCSI channel.
539 Lun - On input, a pointer to the LUN of a SCSI device
540 present on the SCSI channel. On output, a pointer
541 to the LUN of the next SCSI device present on
545 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
546 on the SCSI channel was returned in Target and Lun.
547 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
548 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
549 returned on a previous call to GetNextDevice().
552 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
555 // Retrieve Device Private Data Structure.
557 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
560 // Check whether Target is valid.
562 if (Target
== NULL
|| Lun
== NULL
) {
563 return EFI_INVALID_PARAMETER
;
566 if ((*Target
!= 0xFFFFFFFF) &&
567 ((*Target
!= AtapiScsiPrivate
->LatestTargetId
) ||
568 (*Lun
!= AtapiScsiPrivate
->LatestLun
))) {
569 return EFI_INVALID_PARAMETER
;
572 if (*Target
== MAX_TARGET_ID
) {
573 return EFI_NOT_FOUND
;
576 if (*Target
== 0xFFFFFFFF) {
579 *Target
= AtapiScsiPrivate
->LatestTargetId
+ 1;
585 // Update the LatestTargetId.
587 AtapiScsiPrivate
->LatestTargetId
= *Target
;
588 AtapiScsiPrivate
->LatestLun
= *Lun
;
596 AtapiScsiPassThruBuildDevicePath (
597 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
600 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
605 Used to allocate and build a device path node for a SCSI device
606 on a SCSI channel. Would not build device path for a SCSI Host Controller.
609 This - Protocol instance pointer.
610 Target - The Target ID of the SCSI device for which
611 a device path node is to be allocated and built.
612 Lun - The LUN of the SCSI device for which a device
613 path node is to be allocated and built.
614 DevicePath - A pointer to a single device path node that
615 describes the SCSI device specified by
616 Target and Lun. This function is responsible
617 for allocating the buffer DevicePath with the boot
618 service AllocatePool(). It is the caller's
619 responsibility to free DevicePath when the caller
620 is finished with DevicePath.
622 EFI_SUCCESS - The device path node that describes the SCSI device
623 specified by Target and Lun was allocated and
624 returned in DevicePath.
625 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
626 not exist on the SCSI channel.
627 EFI_INVALID_PARAMETER - DevicePath is NULL.
628 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
632 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
636 // Retrieve Device Private Data Structure.
638 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
641 // Validate parameters passed in.
644 if (DevicePath
== NULL
) {
645 return EFI_INVALID_PARAMETER
;
649 // can not build device path for the SCSI Host Controller.
651 if ((Target
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
652 return EFI_NOT_FOUND
;
655 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
657 return EFI_OUT_OF_RESOURCES
;
660 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
661 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
662 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
664 Node
->Atapi
.PrimarySecondary
= (UINT8
) (Target
/ 2);
665 Node
->Atapi
.SlaveMaster
= (UINT8
) (Target
% 2);
666 Node
->Atapi
.Lun
= (UINT16
) Lun
;
668 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
675 AtapiScsiPassThruGetTargetLun (
676 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
677 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
684 Used to translate a device path node to a Target ID and LUN.
687 This - Protocol instance pointer.
688 DevicePath - A pointer to the device path node that
689 describes a SCSI device on the SCSI channel.
690 Target - A pointer to the Target ID of a SCSI device
692 Lun - A pointer to the LUN of a SCSI device on
695 EFI_SUCCESS - DevicePath was successfully translated to a
696 Target ID and LUN, and they were returned
698 EFI_INVALID_PARAMETER - DevicePath is NULL.
699 EFI_INVALID_PARAMETER - Target is NULL.
700 EFI_INVALID_PARAMETER - Lun is NULL.
701 EFI_UNSUPPORTED - This driver does not support the device path
702 node type in DevicePath.
703 EFI_NOT_FOUND - A valid translation from DevicePath to a
704 Target ID and LUN does not exist.
710 // Validate parameters passed in.
712 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
713 return EFI_INVALID_PARAMETER
;
717 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
719 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
720 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
721 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
722 return EFI_UNSUPPORTED
;
725 Node
= (EFI_DEV_PATH
*) DevicePath
;
727 *Target
= Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
;
728 *Lun
= Node
->Atapi
.Lun
;
730 if (*Target
> (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
731 return EFI_NOT_FOUND
;
739 AtapiScsiPassThruResetChannel (
740 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
745 Resets a SCSI channel.This operation resets all the
746 SCSI devices connected to the SCSI channel.
749 This - Protocol instance pointer.
752 EFI_SUCCESS - The SCSI channel was reset.
753 EFI_UNSUPPORTED - The SCSI channel does not support
754 a channel reset operation.
755 EFI_DEVICE_ERROR - A device error occurred while
756 attempting to reset the SCSI channel.
757 EFI_TIMEOUT - A timeout occurred while attempting
758 to reset the SCSI channel.
761 UINT8 DeviceControlValue
;
762 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
765 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
768 // Reset both Primary channel and Secondary channel.
769 // so, the IoPort pointer must point to the right I/O Register group
771 for (Index
= 0; Index
< 2; Index
++) {
775 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[Index
];
777 DeviceControlValue
= 0;
779 // set SRST bit to initiate soft reset
781 DeviceControlValue
|= SRST
;
785 DeviceControlValue
|= bit (1);
787 AtapiScsiPrivate
->PciIo
,
788 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
801 DeviceControlValue
&= 0xfb;
803 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
806 // slave device needs at most 31s to clear BSY
808 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000) == EFI_TIMEOUT
) {
809 return EFI_DEVICE_ERROR
;
818 AtapiScsiPassThruResetTarget (
819 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
826 Resets a SCSI device that is connected to a SCSI channel.
829 This - Protocol instance pointer.
830 Target - The Target ID of the SCSI device to reset.
831 Lun - The LUN of the SCSI device to reset.
834 EFI_SUCCESS - The SCSI device specified by Target and
836 EFI_UNSUPPORTED - The SCSI channel does not support a target
838 EFI_INVALID_PARAMETER - Target or Lun are invalid.
839 EFI_DEVICE_ERROR - A device error occurred while attempting
840 to reset the SCSI device specified by Target
842 EFI_TIMEOUT - A timeout occurred while attempting to reset
843 the SCSI device specified by Target and Lun.
846 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
850 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
852 if (Target
> MAX_TARGET_ID
) {
853 return EFI_INVALID_PARAMETER
;
856 // Directly return EFI_SUCCESS if want to reset the host controller
858 if (Target
== This
->Mode
->AdapterId
) {
863 // According to Target ID, reset the Atapi I/O Register mapping
864 // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],
865 // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]
867 if ((Target
/ 2) == 0) {
868 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[0];
870 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[1];
874 // for ATAPI device, no need to wait DRDY ready after device selecting.
876 // bit7 and bit5 are both set to 1 for backward compatibility
878 DeviceSelect
= (UINT8
) (((bit (7) | bit (5)) | (Target
<< 4)));
879 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
881 Command
= ATAPI_SOFT_RESET_CMD
;
882 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
885 // BSY clear is the only status return to the host by the device
886 // when reset is complete.
887 // slave device needs at most 31s to clear BSY
889 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000))) {
890 return EFI_DEVICE_ERROR
;
894 // stall 5 seconds to make the device status stable
896 gBS
->Stall (5000000);
903 CheckSCSIRequestPacket (
904 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
908 Checks the parameters in the SCSI Request Packet to make sure
909 they are valid for a SCSI Pass Thru request.
912 // TODO: function comment is missing 'Routine Description:'
913 // TODO: function comment is missing 'Arguments:'
914 // TODO: function comment is missing 'Returns:'
915 // TODO: Packet - add argument and description to function comment
916 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
917 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
918 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
919 // TODO: EFI_UNSUPPORTED - add return value to function comment
920 // TODO: EFI_SUCCESS - add return value to function comment
922 if (Packet
== NULL
) {
923 return EFI_INVALID_PARAMETER
;
926 if (!ValidCdbLength (Packet
->CdbLength
)) {
927 return EFI_INVALID_PARAMETER
;
930 if (Packet
->Cdb
== NULL
) {
931 return EFI_INVALID_PARAMETER
;
935 // Checks whether the request command is supported.
937 if (!IsCommandValid (Packet
)) {
938 return EFI_UNSUPPORTED
;
946 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
950 Checks the requested SCSI command:
951 Is it supported by this driver?
952 Is the Data transfer direction reasonable?
955 // TODO: function comment is missing 'Routine Description:'
956 // TODO: function comment is missing 'Arguments:'
957 // TODO: function comment is missing 'Returns:'
958 // TODO: Packet - add argument and description to function comment
963 OpCode
= (UINT8
*) (Packet
->Cdb
);
965 for (Index
= 0; CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)); Index
++) {
967 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
969 // Check whether the requested Command is supported by this driver
971 if (Packet
->DataDirection
== DataIn
) {
973 // Check whether the requested data direction conforms to
974 // what it should be.
976 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
981 if (Packet
->DataDirection
== DataOut
) {
983 // Check whether the requested data direction conforms to
984 // what it should be.
986 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
999 SubmitBlockingIoCommand (
1000 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1002 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1006 Routine Description:
1007 Performs blocking I/O request.
1010 AtapiScsiPrivate: Private data structure for the specified channel.
1011 Target: The Target ID of the ATAPI device to send the SCSI
1012 Request Packet. To ATAPI devices attached on an IDE
1013 Channel, Target ID 0 indicates Master device;Target
1014 ID 1 indicates Slave device.
1015 Packet: The SCSI Request Packet to send to the ATAPI device
1016 specified by Target.
1021 // TODO: AtapiScsiPrivate - add argument and description to function comment
1023 UINT8 PacketCommand
[12];
1024 UINT64 TimeoutInMicroSeconds
;
1025 EFI_STATUS PacketCommandStatus
;
1028 // Fill ATAPI Command Packet according to CDB
1030 ZeroMem (&PacketCommand
, 12);
1031 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
1034 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
1036 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
1039 // Submit ATAPI Command Packet
1041 PacketCommandStatus
= AtapiPacketCommand (
1046 &(Packet
->TransferLength
),
1047 Packet
->DataDirection
,
1048 TimeoutInMicroSeconds
1050 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
1051 Packet
->SenseDataLength
= 0;
1052 return PacketCommandStatus
;
1055 // Return SenseData if PacketCommandStatus matches
1056 // the following return codes.
1058 if ((PacketCommandStatus
== EFI_WARN_BUFFER_TOO_SMALL
) ||
1059 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
1060 (PacketCommandStatus
== EFI_TIMEOUT
)) {
1063 // avoid submit request sense command continuously.
1065 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
1066 Packet
->SenseDataLength
= 0;
1067 return PacketCommandStatus
;
1070 RequestSenseCommand (
1075 &Packet
->SenseDataLength
1079 return PacketCommandStatus
;
1083 RequestSenseCommand (
1084 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1088 UINT8
*SenseDataLength
1092 Routine Description:
1094 TODO: Add function description
1098 AtapiScsiPrivate - TODO: add argument description
1099 Target - TODO: add argument description
1100 Timeout - TODO: add argument description
1101 SenseData - TODO: add argument description
1102 SenseDataLength - TODO: add argument description
1106 TODO: add return values
1110 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet
;
1114 ZeroMem (&Packet
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1117 Cdb
[0] = OP_REQUEST_SENSE
;
1118 Cdb
[4] = (UINT8
) (*SenseDataLength
);
1120 Packet
.Timeout
= Timeout
;
1121 Packet
.DataBuffer
= SenseData
;
1122 Packet
.SenseData
= NULL
;
1124 Packet
.TransferLength
= *SenseDataLength
;
1125 Packet
.CdbLength
= 12;
1126 Packet
.DataDirection
= DataIn
;
1128 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, &Packet
);
1129 *SenseDataLength
= (UINT8
) (Packet
.TransferLength
);
1134 AtapiPacketCommand (
1135 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1137 UINT8
*PacketCommand
,
1140 DATA_DIRECTION Direction
,
1141 UINT64 TimeoutInMicroSeconds
1145 Routine Description:
1146 Submits ATAPI command packet to the specified ATAPI device.
1149 AtapiScsiPrivate: Private data structure for the specified channel.
1150 Target: The Target ID of the ATAPI device to send the SCSI
1151 Request Packet. To ATAPI devices attached on an IDE
1152 Channel, Target ID 0 indicates Master device;Target
1153 ID 1 indicates Slave device.
1154 PacketCommand: Points to the ATAPI command packet.
1155 Buffer: Points to the transferred data.
1156 ByteCount: When input,indicates the buffer size; when output,
1157 indicates the actually transferred data size.
1158 Direction: Indicates the data transfer direction.
1159 TimeoutInMicroSeconds:
1160 The timeout, in micro second units, to use for the
1161 execution of this ATAPI command.
1162 A TimeoutInMicroSeconds value of 0 means that
1163 this function will wait indefinitely for the ATAPI
1165 If TimeoutInMicroSeconds is greater than zero, then
1166 this function will return EFI_TIMEOUT if the time
1167 required to execute the ATAPI command is greater
1168 than TimeoutInMicroSeconds.
1174 // TODO: AtapiScsiPrivate - add argument and description to function comment
1175 // TODO: PacketCommand - add argument and description to function comment
1176 // TODO: Buffer - add argument and description to function comment
1177 // TODO: ByteCount - add argument and description to function comment
1178 // TODO: Direction - add argument and description to function comment
1181 UINT16
*CommandIndex
;
1186 // Set all the command parameters by fill related registers.
1187 // Before write to all the following registers, BSY and DRQ must be 0.
1189 Status
= StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1190 if (EFI_ERROR (Status
)) {
1191 if (Status
== EFI_ABORTED
) {
1192 Status
= EFI_DEVICE_ERROR
;
1199 // Select device via Device/Head Register.
1200 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
1203 AtapiScsiPrivate
->PciIo
,
1204 AtapiScsiPrivate
->IoPort
->Head
,
1205 (UINT8
) ((Target
<< 4) | DEFAULT_CMD
) // DEFAULT_CMD: 0xa0 (1010,0000)
1209 // No OVL; No DMA (by setting feature register)
1212 AtapiScsiPrivate
->PciIo
,
1213 AtapiScsiPrivate
->IoPort
->Reg1
.Feature
,
1218 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
1219 // determine how much data should be transfered.
1222 AtapiScsiPrivate
->PciIo
,
1223 AtapiScsiPrivate
->IoPort
->CylinderLsb
,
1224 (UINT8
) (MAX_ATAPI_BYTE_COUNT
& 0x00ff)
1227 AtapiScsiPrivate
->PciIo
,
1228 AtapiScsiPrivate
->IoPort
->CylinderMsb
,
1229 (UINT8
) (MAX_ATAPI_BYTE_COUNT
>> 8)
1233 // DEFAULT_CTL:0x0a (0000,1010)
1234 // Disable interrupt
1237 AtapiScsiPrivate
->PciIo
,
1238 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
1243 // Send Packet command to inform device
1244 // that the following data bytes are command packet.
1247 AtapiScsiPrivate
->PciIo
,
1248 AtapiScsiPrivate
->IoPort
->Reg
.Command
,
1253 // Before data transfer, BSY should be 0 and DRQ should be 1.
1254 // if they are not in specified time frame,
1255 // retrieve Sense Key from Error Register before return.
1257 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1258 if (EFI_ERROR (Status
)) {
1259 if (Status
== EFI_ABORTED
) {
1260 Status
= EFI_DEVICE_ERROR
;
1268 // Send out command packet
1270 CommandIndex
= (UINT16
*) PacketCommand
;
1271 for (Count
= 0; Count
< 6; Count
++, CommandIndex
++) {
1272 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *CommandIndex
);
1276 // call AtapiPassThruPioReadWriteData() function to get
1277 // requested transfer data form device.
1279 return AtapiPassThruPioReadWriteData (
1284 TimeoutInMicroSeconds
1289 AtapiPassThruPioReadWriteData (
1290 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1293 DATA_DIRECTION Direction
,
1294 UINT64 TimeoutInMicroSeconds
1298 Routine Description:
1299 Performs data transfer between ATAPI device and host after the
1300 ATAPI command packet is sent.
1303 AtapiScsiPrivate: Private data structure for the specified channel.
1304 Buffer: Points to the transferred data.
1305 ByteCount: When input,indicates the buffer size; when output,
1306 indicates the actually transferred data size.
1307 Direction: Indicates the data transfer direction.
1308 TimeoutInMicroSeconds:
1309 The timeout, in micro second units, to use for the
1310 execution of this ATAPI command.
1311 A TimeoutInMicroSeconds value of 0 means that
1312 this function will wait indefinitely for the ATAPI
1314 If TimeoutInMicroSeconds is greater than zero, then
1315 this function will return EFI_TIMEOUT if the time
1316 required to execute the ATAPI command is greater
1317 than TimeoutInMicroSeconds.
1323 // TODO: AtapiScsiPrivate - add argument and description to function comment
1324 // TODO: Buffer - add argument and description to function comment
1325 // TODO: ByteCount - add argument and description to function comment
1326 // TODO: Direction - add argument and description to function comment
1327 // TODO: EFI_DEVICE_ERROR - add return value to function comment
1328 // TODO: EFI_DEVICE_ERROR - add return value to function comment
1329 // TODO: EFI_WARN_BUFFER_TOO_SMALL - add return value to function comment
1332 UINT32 RequiredWordCount
;
1333 UINT32 ActualWordCount
;
1339 Status
= EFI_SUCCESS
;
1342 // Non Data transfer request is also supported.
1344 if (*ByteCount
== 0 || Buffer
== NULL
) {
1346 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
))) {
1347 return EFI_DEVICE_ERROR
;
1352 RequiredWordCount
= *ByteCount
/ 2;
1355 // ActuralWordCount means the word count of data really transfered.
1357 ActualWordCount
= 0;
1359 while (ActualWordCount
< RequiredWordCount
) {
1361 // before each data transfer stream, the host should poll DRQ bit ready,
1362 // which indicates device's ready for data transfer .
1364 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1365 if (EFI_ERROR (Status
)) {
1366 *ByteCount
= ActualWordCount
* 2;
1368 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
1370 if (ActualWordCount
== 0) {
1371 return EFI_DEVICE_ERROR
;
1374 // ActualWordCount > 0
1376 if (ActualWordCount
< RequiredWordCount
) {
1377 return EFI_WARN_BUFFER_TOO_SMALL
;
1381 // get current data transfer size from Cylinder Registers.
1385 (ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderMsb
) << 8) |
1386 ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderLsb
)
1391 // perform a series data In/Out.
1393 for (Index
= 0; (Index
< WordCount
) && (ActualWordCount
< RequiredWordCount
); Index
++, ActualWordCount
++) {
1395 if (Direction
== DataIn
) {
1397 *ptrBuffer
= ReadPortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
);
1400 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *ptrBuffer
);
1408 // After data transfer is completed, normally, DRQ bit should clear.
1410 StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1413 // read status register to check whether error happens.
1415 Status
= AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
1417 *ByteCount
= ActualWordCount
* 2;
1425 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1429 Read one byte from a specified I/O port.
1431 // TODO: function comment is missing 'Routine Description:'
1432 // TODO: function comment is missing 'Arguments:'
1433 // TODO: function comment is missing 'Returns:'
1434 // TODO: PciIo - add argument and description to function comment
1435 // TODO: Port - add argument and description to function comment
1443 EFI_PCI_IO_PASS_THROUGH_BAR
,
1454 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1458 Read one word from a specified I/O port.
1460 // TODO: function comment is missing 'Routine Description:'
1461 // TODO: function comment is missing 'Arguments:'
1462 // TODO: function comment is missing 'Returns:'
1463 // TODO: PciIo - add argument and description to function comment
1464 // TODO: Port - add argument and description to function comment
1471 EfiPciIoWidthUint16
,
1472 EFI_PCI_IO_PASS_THROUGH_BAR
,
1483 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1488 Write one byte to a specified I/O port.
1490 // TODO: function comment is missing 'Routine Description:'
1491 // TODO: function comment is missing 'Arguments:'
1492 // TODO: function comment is missing 'Returns:'
1493 // TODO: PciIo - add argument and description to function comment
1494 // TODO: Port - add argument and description to function comment
1495 // TODO: Data - add argument and description to function comment
1501 EFI_PCI_IO_PASS_THROUGH_BAR
,
1512 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1517 Write one word to a specified I/O port.
1519 // TODO: function comment is missing 'Routine Description:'
1520 // TODO: function comment is missing 'Arguments:'
1521 // TODO: function comment is missing 'Returns:'
1522 // TODO: PciIo - add argument and description to function comment
1523 // TODO: Port - add argument and description to function comment
1524 // TODO: Data - add argument and description to function comment
1529 EfiPciIoWidthUint16
,
1530 EFI_PCI_IO_PASS_THROUGH_BAR
,
1539 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1540 UINT64 TimeoutInMicroSeconds
1543 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
1544 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1545 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1548 // TODO: function comment is missing 'Routine Description:'
1549 // TODO: function comment is missing 'Arguments:'
1550 // TODO: function comment is missing 'Returns:'
1551 // TODO: AtapiScsiPrivate - add argument and description to function comment
1552 // TODO: TimeoutInMicroSeconds - add argument and description to function comment
1553 // TODO: EFI_ABORTED - add return value to function comment
1554 // TODO: EFI_TIMEOUT - add return value to function comment
1555 // TODO: EFI_SUCCESS - add return value to function comment
1558 UINT8 StatusRegister
;
1561 if (TimeoutInMicroSeconds
== 0) {
1564 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1569 StatusRegister
= ReadPortB (
1570 AtapiScsiPrivate
->PciIo
,
1571 AtapiScsiPrivate
->IoPort
->Reg
.Status
1575 // wait for BSY == 0 and DRQ == 0
1577 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
1581 // check whether the command is aborted by the device
1583 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1585 ErrRegister
= ReadPortB (
1586 AtapiScsiPrivate
->PciIo
,
1587 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1589 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1600 // Loop infinitely if not meeting expected condition
1602 if (TimeoutInMicroSeconds
== 0) {
1618 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1619 UINT64 TimeoutInMicroSeconds
1622 Check whether DRQ is clear in the Alternate Status Register.
1623 (BSY must also be cleared).
1624 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1625 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1628 // TODO: function comment is missing 'Routine Description:'
1629 // TODO: function comment is missing 'Arguments:'
1630 // TODO: function comment is missing 'Returns:'
1631 // TODO: AtapiScsiPrivate - add argument and description to function comment
1632 // TODO: TimeoutInMicroSeconds - add argument and description to function comment
1633 // TODO: EFI_ABORTED - add return value to function comment
1634 // TODO: EFI_TIMEOUT - add return value to function comment
1635 // TODO: EFI_SUCCESS - add return value to function comment
1638 UINT8 AltStatusRegister
;
1641 if (TimeoutInMicroSeconds
== 0) {
1644 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1649 AltStatusRegister
= ReadPortB (
1650 AtapiScsiPrivate
->PciIo
,
1651 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1655 // wait for BSY == 0 and DRQ == 0
1657 if ((AltStatusRegister
& (DRQ
| BSY
)) == 0) {
1661 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
1663 ErrRegister
= ReadPortB (
1664 AtapiScsiPrivate
->PciIo
,
1665 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1667 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1678 // Loop infinitely if not meeting expected condition
1680 if (TimeoutInMicroSeconds
== 0) {
1696 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1697 UINT64 TimeoutInMicroSeconds
1700 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
1701 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1702 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1705 // TODO: function comment is missing 'Routine Description:'
1706 // TODO: function comment is missing 'Arguments:'
1707 // TODO: function comment is missing 'Returns:'
1708 // TODO: AtapiScsiPrivate - add argument and description to function comment
1709 // TODO: TimeoutInMicroSeconds - add argument and description to function comment
1710 // TODO: EFI_ABORTED - add return value to function comment
1711 // TODO: EFI_TIMEOUT - add return value to function comment
1712 // TODO: EFI_SUCCESS - add return value to function comment
1715 UINT8 StatusRegister
;
1718 if (TimeoutInMicroSeconds
== 0) {
1721 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1726 // read Status Register will clear interrupt
1728 StatusRegister
= ReadPortB (
1729 AtapiScsiPrivate
->PciIo
,
1730 AtapiScsiPrivate
->IoPort
->Reg
.Status
1736 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1740 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1742 ErrRegister
= ReadPortB (
1743 AtapiScsiPrivate
->PciIo
,
1744 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1746 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1757 // Loop infinitely if not meeting expected condition
1759 if (TimeoutInMicroSeconds
== 0) {
1775 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1776 UINT64 TimeoutInMicroSeconds
1779 Check whether DRQ is ready in the Alternate Status Register.
1780 (BSY must also be cleared)
1781 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1782 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1785 // TODO: function comment is missing 'Routine Description:'
1786 // TODO: function comment is missing 'Arguments:'
1787 // TODO: function comment is missing 'Returns:'
1788 // TODO: AtapiScsiPrivate - add argument and description to function comment
1789 // TODO: TimeoutInMicroSeconds - add argument and description to function comment
1790 // TODO: EFI_ABORTED - add return value to function comment
1791 // TODO: EFI_TIMEOUT - add return value to function comment
1792 // TODO: EFI_SUCCESS - add return value to function comment
1795 UINT8 AltStatusRegister
;
1798 if (TimeoutInMicroSeconds
== 0) {
1801 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1806 // read Status Register will clear interrupt
1808 AltStatusRegister
= ReadPortB (
1809 AtapiScsiPrivate
->PciIo
,
1810 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1815 if ((AltStatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1819 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
1821 ErrRegister
= ReadPortB (
1822 AtapiScsiPrivate
->PciIo
,
1823 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1825 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1836 // Loop infinitely if not meeting expected condition
1838 if (TimeoutInMicroSeconds
== 0) {
1853 StatusWaitForBSYClear (
1854 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1855 UINT64 TimeoutInMicroSeconds
1858 Check whether BSY is clear in the Status Register.
1859 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1860 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1863 // TODO: function comment is missing 'Routine Description:'
1864 // TODO: function comment is missing 'Arguments:'
1865 // TODO: function comment is missing 'Returns:'
1866 // TODO: AtapiScsiPrivate - add argument and description to function comment
1867 // TODO: TimeoutInMicroSeconds - add argument and description to function comment
1868 // TODO: EFI_TIMEOUT - add return value to function comment
1869 // TODO: EFI_SUCCESS - add return value to function comment
1872 UINT8 StatusRegister
;
1874 if (TimeoutInMicroSeconds
== 0) {
1877 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1882 StatusRegister
= ReadPortB (
1883 AtapiScsiPrivate
->PciIo
,
1884 AtapiScsiPrivate
->IoPort
->Reg
.Status
1886 if ((StatusRegister
& BSY
) == 0x00) {
1896 // Loop infinitely if not meeting expected condition
1898 if (TimeoutInMicroSeconds
== 0) {
1913 AltStatusWaitForBSYClear (
1914 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1915 UINT64 TimeoutInMicroSeconds
1918 Check whether BSY is clear in the Alternate Status Register.
1919 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1920 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1923 // TODO: function comment is missing 'Routine Description:'
1924 // TODO: function comment is missing 'Arguments:'
1925 // TODO: function comment is missing 'Returns:'
1926 // TODO: AtapiScsiPrivate - add argument and description to function comment
1927 // TODO: TimeoutInMicroSeconds - add argument and description to function comment
1928 // TODO: EFI_TIMEOUT - add return value to function comment
1929 // TODO: EFI_SUCCESS - add return value to function comment
1932 UINT8 AltStatusRegister
;
1934 if (TimeoutInMicroSeconds
== 0) {
1937 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1942 AltStatusRegister
= ReadPortB (
1943 AtapiScsiPrivate
->PciIo
,
1944 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1946 if ((AltStatusRegister
& BSY
) == 0x00) {
1955 // Loop infinitely if not meeting expected condition
1957 if (TimeoutInMicroSeconds
== 0) {
1973 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1974 UINT64 TimeoutInMicroSeconds
1977 Check whether DRDY is ready in the Status Register.
1978 (BSY must also be cleared)
1979 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1980 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1983 // TODO: function comment is missing 'Routine Description:'
1984 // TODO: function comment is missing 'Arguments:'
1985 // TODO: function comment is missing 'Returns:'
1986 // TODO: AtapiScsiPrivate - add argument and description to function comment
1987 // TODO: TimeoutInMicroSeconds - add argument and description to function comment
1988 // TODO: EFI_ABORTED - add return value to function comment
1989 // TODO: EFI_TIMEOUT - add return value to function comment
1990 // TODO: EFI_SUCCESS - add return value to function comment
1993 UINT8 StatusRegister
;
1996 if (TimeoutInMicroSeconds
== 0) {
1999 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2003 StatusRegister
= ReadPortB (
2004 AtapiScsiPrivate
->PciIo
,
2005 AtapiScsiPrivate
->IoPort
->Reg
.Status
2008 // BSY == 0 , DRDY == 1
2010 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
2014 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
2016 ErrRegister
= ReadPortB (
2017 AtapiScsiPrivate
->PciIo
,
2018 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2020 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2030 // Loop infinitely if not meeting expected condition
2032 if (TimeoutInMicroSeconds
== 0) {
2047 AltStatusDRDYReady (
2048 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2049 UINT64 TimeoutInMicroSeconds
2052 Check whether DRDY is ready in the Alternate Status Register.
2053 (BSY must also be cleared)
2054 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2055 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2058 // TODO: function comment is missing 'Routine Description:'
2059 // TODO: function comment is missing 'Arguments:'
2060 // TODO: function comment is missing 'Returns:'
2061 // TODO: AtapiScsiPrivate - add argument and description to function comment
2062 // TODO: TimeoutInMicroSeconds - add argument and description to function comment
2063 // TODO: EFI_ABORTED - add return value to function comment
2064 // TODO: EFI_TIMEOUT - add return value to function comment
2065 // TODO: EFI_SUCCESS - add return value to function comment
2068 UINT8 AltStatusRegister
;
2071 if (TimeoutInMicroSeconds
== 0) {
2074 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2078 AltStatusRegister
= ReadPortB (
2079 AtapiScsiPrivate
->PciIo
,
2080 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2083 // BSY == 0 , DRDY == 1
2085 if ((AltStatusRegister
& (DRDY
| BSY
)) == DRDY
) {
2089 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2091 ErrRegister
= ReadPortB (
2092 AtapiScsiPrivate
->PciIo
,
2093 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2095 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2105 // Loop infinitely if not meeting expected condition
2107 if (TimeoutInMicroSeconds
== 0) {
2122 AtapiPassThruCheckErrorStatus (
2123 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
2126 Check Error Register for Error Information.
2128 // TODO: function comment is missing 'Routine Description:'
2129 // TODO: function comment is missing 'Arguments:'
2130 // TODO: function comment is missing 'Returns:'
2131 // TODO: AtapiScsiPrivate - add argument and description to function comment
2132 // TODO: EFI_SUCCESS - add return value to function comment
2133 // TODO: EFI_DEVICE_ERROR - add return value to function comment
2135 UINT8 StatusRegister
;
2139 UINT8 ErrorRegister
;
2143 StatusRegister
= ReadPortB (
2144 AtapiScsiPrivate
->PciIo
,
2145 AtapiScsiPrivate
->IoPort
->Reg
.Status
2149 if (StatusRegister
& DWF
) {
2152 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
2157 if (StatusRegister
& CORR
) {
2160 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
2165 if (StatusRegister
& ERR
) {
2166 ErrorRegister
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg1
.Error
);
2168 if (ErrorRegister
& BBK_ERR
) {
2171 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
2176 if (ErrorRegister
& UNC_ERR
) {
2179 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
2184 if (ErrorRegister
& MC_ERR
) {
2187 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
2192 if (ErrorRegister
& ABRT_ERR
) {
2195 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
2200 if (ErrorRegister
& TK0NF_ERR
) {
2203 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
2208 if (ErrorRegister
& AMNF_ERR
) {
2211 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
2219 if ((StatusRegister
& (ERR
| DWF
| CORR
)) == 0) {
2224 return EFI_DEVICE_ERROR
;