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 static CHAR16
*gControllerNameString
= (CHAR16
*) L
"ATAPI Controller";
58 static CHAR16
*gAtapiChannelString
= (CHAR16
*) L
"ATAPI Channel";
60 EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding
= {
61 AtapiScsiPassThruDriverBindingSupported
,
62 AtapiScsiPassThruDriverBindingStart
,
63 AtapiScsiPassThruDriverBindingStop
,
72 (Standard DriverBinding Protocol Supported() function)
76 @todo This - add argument and description to function comment
77 @todo Controller - add argument and description to function comment
78 @todo RemainingDevicePath - add argument and description to function comment
79 @todo EFI_UNSUPPORTED - add return value to function comment
83 AtapiScsiPassThruDriverBindingSupported (
84 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
85 IN EFI_HANDLE Controller
,
86 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
90 EFI_PCI_IO_PROTOCOL
*PciIo
;
95 // Open the IO Abstraction(s) needed to perform the supported test
97 Status
= gBS
->OpenProtocol (
99 &gEfiPciIoProtocolGuid
,
101 This
->DriverBindingHandle
,
103 EFI_OPEN_PROTOCOL_BY_DRIVER
105 if (EFI_ERROR (Status
)) {
109 // Use the PCI I/O Protocol to see if Controller is a IDE Controller that
110 // can be managed by this driver. Read the PCI Configuration Header
113 Status
= PciIo
->Pci
.Read (
117 sizeof (Pci
) / sizeof (UINT32
),
120 if (EFI_ERROR (Status
)) {
123 &gEfiPciIoProtocolGuid
,
124 This
->DriverBindingHandle
,
127 return EFI_UNSUPPORTED
;
130 if (Pci
.Hdr
.ClassCode
[2] != PCI_CLASS_MASS_STORAGE
|| Pci
.Hdr
.ClassCode
[1] != PCI_CLASS_IDE
) {
132 Status
= EFI_UNSUPPORTED
;
137 &gEfiPciIoProtocolGuid
,
138 This
->DriverBindingHandle
,
146 Create handles for IDE channels specified by RemainingDevicePath.
147 Install SCSI Pass Thru Protocol onto each created handle.
149 (Standard DriverBinding Protocol Start() function)
153 @todo This - add argument and description to function comment
154 @todo Controller - add argument and description to function comment
155 @todo RemainingDevicePath - add argument and description to function comment
159 AtapiScsiPassThruDriverBindingStart (
160 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
161 IN EFI_HANDLE Controller
,
162 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
166 EFI_PCI_IO_PROTOCOL
*PciIo
;
168 UINT64 OriginalPciAttributes
;
171 Status
= gBS
->OpenProtocol (
173 &gEfiPciIoProtocolGuid
,
175 This
->DriverBindingHandle
,
177 EFI_OPEN_PROTOCOL_BY_DRIVER
179 if (EFI_ERROR (Status
)) {
184 // Save original PCI attributes
186 Status
= PciIo
->Attributes (
188 EfiPciIoAttributeOperationGet
,
190 &OriginalPciAttributes
193 if (EFI_ERROR (Status
)) {
197 Status
= PciIo
->Attributes (
199 EfiPciIoAttributeOperationSupported
,
203 if (!EFI_ERROR (Status
)) {
204 Supports
&= (EFI_PCI_DEVICE_ENABLE
|
205 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
|
206 EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
);
207 Status
= PciIo
->Attributes (
209 EfiPciIoAttributeOperationEnable
,
214 if (EFI_ERROR (Status
)) {
219 // Create SCSI Pass Thru instance for the IDE channel.
221 Status
= RegisterAtapiScsiPassThru (This
, Controller
, PciIo
, OriginalPciAttributes
);
224 if (EFI_ERROR (Status
)) {
226 // Restore original PCI attributes
230 EfiPciIoAttributeOperationSet
,
231 OriginalPciAttributes
,
237 &gEfiPciIoProtocolGuid
,
238 This
->DriverBindingHandle
,
249 (Standard DriverBinding Protocol Stop() function)
253 @todo This - add argument and description to function comment
254 @todo Controller - add argument and description to function comment
255 @todo NumberOfChildren - add argument and description to function comment
256 @todo ChildHandleBuffer - add argument and description to function comment
257 @todo EFI_SUCCESS - add return value to function comment
261 AtapiScsiPassThruDriverBindingStop (
262 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
263 IN EFI_HANDLE Controller
,
264 IN UINTN NumberOfChildren
,
265 IN EFI_HANDLE
*ChildHandleBuffer
269 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
270 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
272 Status
= gBS
->OpenProtocol (
274 &gEfiScsiPassThruProtocolGuid
,
275 (VOID
**) &ScsiPassThru
,
276 This
->DriverBindingHandle
,
278 EFI_OPEN_PROTOCOL_GET_PROTOCOL
280 if (EFI_ERROR (Status
)) {
284 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru
);
286 Status
= gBS
->UninstallProtocolInterface (
288 &gEfiScsiPassThruProtocolGuid
,
289 &AtapiScsiPrivate
->ScsiPassThru
291 if (EFI_ERROR (Status
)) {
296 // Restore original PCI attributes
298 AtapiScsiPrivate
->PciIo
->Attributes (
299 AtapiScsiPrivate
->PciIo
,
300 EfiPciIoAttributeOperationSet
,
301 AtapiScsiPrivate
->OriginalPciAttributes
,
307 &gEfiPciIoProtocolGuid
,
308 This
->DriverBindingHandle
,
312 gBS
->FreePool (AtapiScsiPrivate
);
318 Attaches SCSI Pass Thru Protocol for specified IDE channel.
320 @param Controller: Parent device handle to the IDE channel.
321 @param PciIo: PCI I/O protocol attached on the "Controller".
322 @param OriginalPciAttributes Original PCI attributes
325 @return EFI_SUCCESS Always returned unless installing SCSI Pass Thru Protocol failed.
327 @todo This - add argument and description to function comment
328 @todo Controller - add argument and description to function comment
329 @todo PciIo - add argument and description to function comment
330 @todo EFI_OUT_OF_RESOURCES - add return value to function comment
333 RegisterAtapiScsiPassThru (
334 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
335 IN EFI_HANDLE Controller
,
336 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
337 IN UINT64 OriginalPciAttributes
341 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
342 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[ATAPI_MAX_CHANNEL
];
344 AtapiScsiPrivate
= AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV
));
345 if (AtapiScsiPrivate
== NULL
) {
346 return EFI_OUT_OF_RESOURCES
;
349 CopyMem (AtapiScsiPrivate
->ChannelName
, gAtapiChannelString
, sizeof (gAtapiChannelString
));
351 AtapiScsiPrivate
->Signature
= ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE
;
352 AtapiScsiPrivate
->Handle
= Controller
;
355 // will reset the IoPort inside each API function.
357 AtapiScsiPrivate
->IoPort
= NULL
;
358 AtapiScsiPrivate
->PciIo
= PciIo
;
359 AtapiScsiPrivate
->OriginalPciAttributes
= OriginalPciAttributes
;
362 // Obtain IDE IO port registers' base addresses
364 Status
= GetIdeRegistersBaseAddr (PciIo
, IdeRegsBaseAddr
);
365 if (EFI_ERROR (Status
)) {
369 InitAtapiIoPortRegisters(AtapiScsiPrivate
, IdeRegsBaseAddr
);
371 // initialize SCSI Pass Thru Protocol interface
373 AtapiScsiPrivate
->ScsiPassThru
.Mode
= &AtapiScsiPrivate
->ScsiPassThruMode
;
374 AtapiScsiPrivate
->ScsiPassThru
.PassThru
= AtapiScsiPassThruFunction
;
375 AtapiScsiPrivate
->ScsiPassThru
.GetNextDevice
= AtapiScsiPassThruGetNextDevice
;
376 AtapiScsiPrivate
->ScsiPassThru
.BuildDevicePath
= AtapiScsiPassThruBuildDevicePath
;
377 AtapiScsiPrivate
->ScsiPassThru
.GetTargetLun
= AtapiScsiPassThruGetTargetLun
;
378 AtapiScsiPrivate
->ScsiPassThru
.ResetChannel
= AtapiScsiPassThruResetChannel
;
379 AtapiScsiPrivate
->ScsiPassThru
.ResetTarget
= AtapiScsiPassThruResetTarget
;
384 CopyMem (AtapiScsiPrivate
->ControllerName
, gControllerNameString
, sizeof (gControllerNameString
));
386 AtapiScsiPrivate
->ScsiPassThruMode
.ControllerName
= AtapiScsiPrivate
->ControllerName
;
387 AtapiScsiPrivate
->ScsiPassThruMode
.ChannelName
= AtapiScsiPrivate
->ChannelName
;
388 AtapiScsiPrivate
->ScsiPassThruMode
.AdapterId
= 4;
390 // non-RAID SCSI controllers should set both physical and logical attributes
392 AtapiScsiPrivate
->ScsiPassThruMode
.Attributes
= EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
393 EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
394 AtapiScsiPrivate
->ScsiPassThruMode
.IoAlign
= 0;
397 // Initialize the LatestTargetId.
399 AtapiScsiPrivate
->LatestTargetId
= 4;
400 AtapiScsiPrivate
->LatestLun
= 0;
402 Status
= gBS
->InstallProtocolInterface (
404 &gEfiScsiPassThruProtocolGuid
,
405 EFI_NATIVE_INTERFACE
,
406 &AtapiScsiPrivate
->ScsiPassThru
412 Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
414 @param This The EFI_SCSI_PASS_THRU_PROTOCOL instance.
415 @param Target The Target ID of the ATAPI device to send the SCSI
416 Request Packet. To ATAPI devices attached on an IDE
417 Channel, Target ID 0 indicates Master device;Target
418 ID 1 indicates Slave device.
419 @param Lun The LUN of the ATAPI device to send the SCSI Request
420 Packet. To the ATAPI device, Lun is always 0.
421 @param Packet The SCSI Request Packet to send to the ATAPI device
422 specified by Target and Lun.
423 @param Event If non-blocking I/O is not supported then Event is ignored,
424 and blocking I/O is performed.<br>
425 If Event is NULL, then blocking I/O is performed.<br>
426 If Event is not NULL and non blocking I/O is supported,
427 then non-blocking I/O is performed, and Event will be signaled
428 when the SCSI Request Packet completes.
430 @todo This - add argument and description to function comment
431 @todo EFI_INVALID_PARAMETER - add return value to function comment
432 @todo EFI_SUCCESS - add return value to function comment
436 AtapiScsiPassThruFunction (
437 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
440 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
441 IN EFI_EVENT Event OPTIONAL
444 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
447 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
450 // Target is not allowed beyond MAX_TARGET_ID
452 if ((Target
> MAX_TARGET_ID
) || (Lun
!= 0)) {
453 return EFI_INVALID_PARAMETER
;
457 // check the data fields in Packet parameter.
459 Status
= CheckSCSIRequestPacket (Packet
);
460 if (EFI_ERROR (Status
)) {
465 // If Request Packet targets at the IDE channel itself,
468 if (Target
== This
->Mode
->AdapterId
) {
469 Packet
->TransferLength
= 0;
474 // According to Target ID, reset the Atapi I/O Register mapping
475 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
476 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
478 if ((Target
/ 2) == 0) {
480 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
483 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
487 // the ATAPI SCSI interface does not support non-blocking I/O
488 // ignore the Event parameter
490 // Performs blocking I/O.
492 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, Packet
);
497 Used to retrieve the list of legal Target IDs for SCSI devices
500 @param This Protocol instance pointer.
501 @param Target On input, a pointer to the Target ID of a SCSI
502 device present on the SCSI channel. On output,
503 a pointer to the Target ID of the next SCSI device
504 present on a SCSI channel. An input value of
505 0xFFFFFFFF retrieves the Target ID of the first
506 SCSI device present on a SCSI channel.
507 @param Lun On input, a pointer to the LUN of a SCSI device
508 present on the SCSI channel. On output, a pointer
509 to the LUN of the next SCSI device present on
512 @retval EFI_SUCCESS The Target ID and Lun of the next SCSI device
513 on the SCSI channel was returned in Target and Lun.
514 @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
515 @retval EFI_INVALID_PARAMETER Target is not 0xFFFFFFFF,and Target and Lun were not
516 returned on a previous call to GetNextDevice().
521 AtapiScsiPassThruGetNextDevice (
522 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
523 IN OUT UINT32
*Target
,
527 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
530 // Retrieve Device Private Data Structure.
532 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
535 // Check whether Target is valid.
537 if (Target
== NULL
|| Lun
== NULL
) {
538 return EFI_INVALID_PARAMETER
;
541 if ((*Target
!= 0xFFFFFFFF) &&
542 ((*Target
!= AtapiScsiPrivate
->LatestTargetId
) ||
543 (*Lun
!= AtapiScsiPrivate
->LatestLun
))) {
544 return EFI_INVALID_PARAMETER
;
547 if (*Target
== MAX_TARGET_ID
) {
548 return EFI_NOT_FOUND
;
551 if (*Target
== 0xFFFFFFFF) {
554 *Target
= AtapiScsiPrivate
->LatestTargetId
+ 1;
560 // Update the LatestTargetId.
562 AtapiScsiPrivate
->LatestTargetId
= *Target
;
563 AtapiScsiPrivate
->LatestLun
= *Lun
;
570 Used to allocate and build a device path node for a SCSI device
571 on a SCSI channel. Would not build device path for a SCSI Host Controller.
573 @param This Protocol instance pointer.
574 @param Target The Target ID of the SCSI device for which
575 a device path node is to be allocated and built.
576 @param Lun The LUN of the SCSI device for which a device
577 path node is to be allocated and built.
578 @param DevicePath A pointer to a single device path node that
579 describes the SCSI device specified by
580 Target and Lun. This function is responsible
581 for allocating the buffer DevicePath with the boot
582 service AllocatePool(). It is the caller's
583 responsibility to free DevicePath when the caller
584 is finished with DevicePath.
586 @retval EFI_SUCCESS The device path node that describes the SCSI device
587 specified by Target and Lun was allocated and
588 returned in DevicePath.
589 @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does
590 not exist on the SCSI channel.
591 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
592 @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate
598 AtapiScsiPassThruBuildDevicePath (
599 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
602 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
609 // Validate parameters passed in.
612 if (DevicePath
== NULL
) {
613 return EFI_INVALID_PARAMETER
;
617 // can not build device path for the SCSI Host Controller.
619 if ((Target
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
620 return EFI_NOT_FOUND
;
623 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
625 return EFI_OUT_OF_RESOURCES
;
628 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
629 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
630 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
632 Node
->Atapi
.PrimarySecondary
= (UINT8
) (Target
/ 2);
633 Node
->Atapi
.SlaveMaster
= (UINT8
) (Target
% 2);
634 Node
->Atapi
.Lun
= (UINT16
) Lun
;
636 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
642 Used to translate a device path node to a Target ID and LUN.
644 @param This Protocol instance pointer.
645 @param DevicePath A pointer to the device path node that
646 describes a SCSI device on the SCSI channel.
647 @param Target A pointer to the Target ID of a SCSI device
649 @param Lun A pointer to the LUN of a SCSI device on
652 @retval EFI_SUCCESS DevicePath was successfully translated to a
653 Target ID and LUN, and they were returned
655 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
656 @retval EFI_INVALID_PARAMETER Target is NULL.
657 @retval EFI_INVALID_PARAMETER Lun is NULL.
658 @retval EFI_UNSUPPORTED This driver does not support the device path
659 node type in DevicePath.
660 @retval EFI_NOT_FOUND A valid translation from DevicePath to a
661 Target ID and LUN does not exist.
666 AtapiScsiPassThruGetTargetLun (
667 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
668 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
676 // Validate parameters passed in.
678 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
679 return EFI_INVALID_PARAMETER
;
683 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
685 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
686 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
687 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
688 return EFI_UNSUPPORTED
;
691 Node
= (EFI_DEV_PATH
*) DevicePath
;
693 *Target
= Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
;
694 *Lun
= Node
->Atapi
.Lun
;
696 if (*Target
> (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
697 return EFI_NOT_FOUND
;
704 Resets a SCSI channel.This operation resets all the
705 SCSI devices connected to the SCSI channel.
707 @param This Protocol instance pointer.
709 @retval EFI_SUCCESS The SCSI channel was reset.
710 @retval EFI_UNSUPPORTED The SCSI channel does not support
711 a channel reset operation.
712 @retval EFI_DEVICE_ERROR A device error occurred while
713 attempting to reset the SCSI channel.
714 @retval EFI_TIMEOUT A timeout occurred while attempting
715 to reset the SCSI channel.
720 AtapiScsiPassThruResetChannel (
721 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
724 UINT8 DeviceControlValue
;
725 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
729 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
733 // Reset both Primary channel and Secondary channel.
734 // so, the IoPort pointer must point to the right I/O Register group
736 for (Index
= 0; Index
< 2; Index
++) {
740 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[Index
];
742 DeviceControlValue
= 0;
744 // set SRST bit to initiate soft reset
746 DeviceControlValue
|= SRST
;
750 DeviceControlValue
|= bit (1);
752 AtapiScsiPrivate
->PciIo
,
753 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
766 DeviceControlValue
&= 0xfb;
768 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
771 // slave device needs at most 31s to clear BSY
773 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000) != EFI_TIMEOUT
) {
786 Resets a SCSI device that is connected to a SCSI channel.
788 @param This Protocol instance pointer.
789 @param Target The Target ID of the SCSI device to reset.
790 @param Lun The LUN of the SCSI device to reset.
792 @retval EFI_SUCCESS The SCSI device specified by Target and
794 @retval EFI_UNSUPPORTED The SCSI channel does not support a target
796 @retval EFI_INVALID_PARAMETER Target or Lun are invalid.
797 @retval EFI_DEVICE_ERROR A device error occurred while attempting
798 to reset the SCSI device specified by Target
800 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
801 the SCSI device specified by Target and Lun.
806 AtapiScsiPassThruResetTarget (
807 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
812 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
816 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
818 if ((Target
> MAX_TARGET_ID
) || (Lun
!= 0)) {
819 return EFI_INVALID_PARAMETER
;
822 // Directly return EFI_SUCCESS if want to reset the host controller
824 if (Target
== This
->Mode
->AdapterId
) {
829 // According to Target ID, reset the Atapi I/O Register mapping
830 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
831 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
833 if ((Target
/ 2) == 0) {
834 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[0];
836 AtapiScsiPrivate
->IoPort
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[1];
840 // for ATAPI device, no need to wait DRDY ready after device selecting.
842 // bit7 and bit5 are both set to 1 for backward compatibility
844 DeviceSelect
= (UINT8
) (((bit (7) | bit (5)) | (Target
<< 4)));
845 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
847 Command
= ATAPI_SOFT_RESET_CMD
;
848 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
851 // BSY clear is the only status return to the host by the device
852 // when reset is complete.
853 // slave device needs at most 31s to clear BSY
855 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000000))) {
860 // stall 5 seconds to make the device status stable
862 gBS
->Stall (5000000);
868 GetIdeRegistersBaseAddr (
869 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
870 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
875 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
876 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
877 the PCI IDE controller's Configuration Space.
880 PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance
881 IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to
882 receive IDE IO port registers' base addresses
893 Status
= PciIo
->Pci
.Read (
901 if (EFI_ERROR (Status
)) {
905 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
906 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
907 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
910 // The BARs should be of IO type
912 if ((PciData
.Device
.Bar
[0] & BIT0
) == 0 ||
913 (PciData
.Device
.Bar
[1] & BIT0
) == 0) {
914 return EFI_UNSUPPORTED
;
917 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
918 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
919 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
920 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
923 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
924 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
925 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
928 // The BARs should be of IO type
930 if ((PciData
.Device
.Bar
[2] & BIT0
) == 0 ||
931 (PciData
.Device
.Bar
[3] & BIT0
) == 0) {
932 return EFI_UNSUPPORTED
;
935 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
936 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
937 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
938 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
945 InitAtapiIoPortRegisters (
946 IN ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
947 IN IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
953 Initialize each Channel's Base Address of CommandBlock and ControlBlock.
957 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
958 IdeRegsBaseAddr - The pointer of IDE_REGISTERS_BASE_ADDR
968 UINT16 CommandBlockBaseAddr
;
969 UINT16 ControlBlockBaseAddr
;
970 IDE_BASE_REGISTERS
*RegisterPointer
;
973 for (IdeChannel
= 0; IdeChannel
< ATAPI_MAX_CHANNEL
; IdeChannel
++) {
975 RegisterPointer
= &AtapiScsiPrivate
->AtapiIoPortRegisters
[IdeChannel
];
978 // Initialize IDE IO port addresses, including Command Block registers
979 // and Control Block registers
981 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeChannel
].CommandBlockBaseAddr
;
982 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeChannel
].ControlBlockBaseAddr
;
984 RegisterPointer
->Data
= CommandBlockBaseAddr
;
985 (*(UINT16
*) &RegisterPointer
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
986 RegisterPointer
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
987 RegisterPointer
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
988 RegisterPointer
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
989 RegisterPointer
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
990 RegisterPointer
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
991 (*(UINT16
*) &RegisterPointer
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
993 (*(UINT16
*) &RegisterPointer
->Alt
) = ControlBlockBaseAddr
;
994 RegisterPointer
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
1001 CheckSCSIRequestPacket (
1002 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1006 Routine Description:
1008 Checks the parameters in the SCSI Request Packet to make sure
1009 they are valid for a SCSI Pass Thru request.
1013 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1021 if (Packet
== NULL
) {
1022 return EFI_INVALID_PARAMETER
;
1025 if (!ValidCdbLength (Packet
->CdbLength
)) {
1026 return EFI_INVALID_PARAMETER
;
1029 if (Packet
->Cdb
== NULL
) {
1030 return EFI_INVALID_PARAMETER
;
1034 // Checks whether the request command is supported.
1036 if (!IsCommandValid (Packet
)) {
1037 return EFI_UNSUPPORTED
;
1044 Checks the requested SCSI command:
1045 Is it supported by this driver?
1046 Is the Data transfer direction reasonable?
1048 @todo function comment is missing 'Routine Description:'
1049 @todo function comment is missing 'Arguments:'
1050 @todo function comment is missing 'Returns:'
1051 @todo Packet - add argument and description to function comment
1055 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1061 OpCode
= (UINT8
*) (Packet
->Cdb
);
1063 for (Index
= 0; CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)); Index
++) {
1065 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
1067 // Check whether the requested Command is supported by this driver
1069 if (Packet
->DataDirection
== DataIn
) {
1071 // Check whether the requested data direction conforms to
1072 // what it should be.
1074 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
1079 if (Packet
->DataDirection
== DataOut
) {
1081 // Check whether the requested data direction conforms to
1082 // what it should be.
1084 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
1097 Performs blocking I/O request.
1099 @param AtapiScsiPrivate Private data structure for the specified channel.
1100 @param Target The Target ID of the ATAPI device to send the SCSI
1101 Request Packet. To ATAPI devices attached on an IDE
1102 Channel, Target ID 0 indicates Master device;Target
1103 ID 1 indicates Slave device.
1104 @param Packet The SCSI Request Packet to send to the ATAPI device
1105 specified by Target.
1107 @todo AtapiScsiPrivate - add argument and description to function comment
1110 SubmitBlockingIoCommand (
1111 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1113 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1116 UINT8 PacketCommand
[12];
1117 UINT64 TimeoutInMicroSeconds
;
1118 EFI_STATUS PacketCommandStatus
;
1121 // Fill ATAPI Command Packet according to CDB
1123 ZeroMem (&PacketCommand
, 12);
1124 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
1127 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
1129 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
1132 // Submit ATAPI Command Packet
1134 PacketCommandStatus
= AtapiPacketCommand (
1139 &(Packet
->TransferLength
),
1140 (DATA_DIRECTION
) Packet
->DataDirection
,
1141 TimeoutInMicroSeconds
1143 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
1144 Packet
->SenseDataLength
= 0;
1145 return PacketCommandStatus
;
1149 // Check if SenseData meets the alignment requirement.
1151 if ((AtapiScsiPrivate
->ScsiPassThru
.Mode
->IoAlign
!= 0) \
1152 && (AtapiScsiPrivate
->ScsiPassThru
.Mode
->IoAlign
!= 1)) {
1153 if (((UINTN
)Packet
->SenseData
% AtapiScsiPrivate
->ScsiPassThru
.Mode
->IoAlign
) != 0) {
1154 return EFI_INVALID_PARAMETER
;
1160 // Return SenseData if PacketCommandStatus matches
1161 // the following return codes.
1163 if ((PacketCommandStatus
== EFI_BAD_BUFFER_SIZE
) ||
1164 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
1165 (PacketCommandStatus
== EFI_TIMEOUT
)) {
1168 // avoid submit request sense command continuously.
1170 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
1171 Packet
->SenseDataLength
= 0;
1172 return PacketCommandStatus
;
1175 RequestSenseCommand (
1180 &Packet
->SenseDataLength
1184 return PacketCommandStatus
;
1190 @param AtapiScsiPrivate
1194 @param SenseDataLength
1196 @todo Add function description
1197 @todo AtapiScsiPrivate TODO: add argument description
1198 @todo Target TODO: add argument description
1199 @todo Timeout TODO: add argument description
1200 @todo SenseData TODO: add argument description
1201 @todo SenseDataLength TODO: add argument description
1202 @todo add return values
1205 RequestSenseCommand (
1206 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1210 UINT8
*SenseDataLength
1213 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet
;
1217 ZeroMem (&Packet
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1220 Cdb
[0] = OP_REQUEST_SENSE
;
1221 Cdb
[4] = (UINT8
) (*SenseDataLength
);
1223 Packet
.Timeout
= Timeout
;
1224 Packet
.DataBuffer
= SenseData
;
1225 Packet
.SenseData
= NULL
;
1227 Packet
.TransferLength
= *SenseDataLength
;
1228 Packet
.CdbLength
= 12;
1229 Packet
.DataDirection
= DataIn
;
1231 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, &Packet
);
1232 *SenseDataLength
= (UINT8
) (Packet
.TransferLength
);
1237 Submits ATAPI command packet to the specified ATAPI device.
1239 @param AtapiScsiPrivate: Private data structure for the specified channel.
1240 @param Target: The Target ID of the ATAPI device to send the SCSI
1241 Request Packet. To ATAPI devices attached on an IDE
1242 Channel, Target ID 0 indicates Master device;Target
1243 ID 1 indicates Slave device.
1244 @param PacketCommand: Points to the ATAPI command packet.
1245 @param Buffer: Points to the transferred data.
1246 @param ByteCount: When input,indicates the buffer size; when output,
1247 indicates the actually transferred data size.
1248 @param Direction: Indicates the data transfer direction.
1249 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1250 to use for the execution of this ATAPI command.
1251 A TimeoutInMicroSeconds value of 0 means that
1252 this function will wait indefinitely for the ATAPI
1255 If TimeoutInMicroSeconds is greater than zero, then
1256 this function will return EFI_TIMEOUT if the time
1257 required to execute the ATAPI command is greater
1258 than TimeoutInMicroSeconds.
1261 @todo AtapiScsiPrivate - add argument and description to function comment
1262 @todo PacketCommand - add argument and description to function comment
1263 @todo Buffer - add argument and description to function comment
1264 @todo ByteCount - add argument and description to function comment
1265 @todo Direction - add argument and description to function comment
1268 AtapiPacketCommand (
1269 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1271 UINT8
*PacketCommand
,
1274 DATA_DIRECTION Direction
,
1275 UINT64 TimeoutInMicroSeconds
1279 UINT16
*CommandIndex
;
1284 // Check if the buffer meets the alignment requirement.
1286 if ((AtapiScsiPrivate
->ScsiPassThru
.Mode
->IoAlign
!= 0) \
1287 && (AtapiScsiPrivate
->ScsiPassThru
.Mode
->IoAlign
!= 1)) {
1288 if (((UINTN
)Buffer
% AtapiScsiPrivate
->ScsiPassThru
.Mode
->IoAlign
) != 0) {
1289 return EFI_INVALID_PARAMETER
;
1294 // Set all the command parameters by fill related registers.
1295 // Before write to all the following registers, BSY must be 0.
1297 Status
= StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1298 if (EFI_ERROR (Status
)) {
1299 return EFI_DEVICE_ERROR
;
1304 // Select device via Device/Head Register.
1305 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
1308 AtapiScsiPrivate
->PciIo
,
1309 AtapiScsiPrivate
->IoPort
->Head
,
1310 (UINT8
) ((Target
<< 4) | DEFAULT_CMD
) // DEFAULT_CMD: 0xa0 (1010,0000)
1314 // Set all the command parameters by fill related registers.
1315 // Before write to all the following registers, BSY DRQ must be 0.
1317 Status
= StatusDRQClear(AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1319 if (EFI_ERROR (Status
)) {
1320 if (Status
== EFI_ABORTED
) {
1321 Status
= EFI_DEVICE_ERROR
;
1328 // No OVL; No DMA (by setting feature register)
1331 AtapiScsiPrivate
->PciIo
,
1332 AtapiScsiPrivate
->IoPort
->Reg1
.Feature
,
1337 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
1338 // determine how much data should be transfered.
1341 AtapiScsiPrivate
->PciIo
,
1342 AtapiScsiPrivate
->IoPort
->CylinderLsb
,
1343 (UINT8
) (MAX_ATAPI_BYTE_COUNT
& 0x00ff)
1346 AtapiScsiPrivate
->PciIo
,
1347 AtapiScsiPrivate
->IoPort
->CylinderMsb
,
1348 (UINT8
) (MAX_ATAPI_BYTE_COUNT
>> 8)
1352 // DEFAULT_CTL:0x0a (0000,1010)
1353 // Disable interrupt
1356 AtapiScsiPrivate
->PciIo
,
1357 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
1362 // Send Packet command to inform device
1363 // that the following data bytes are command packet.
1366 AtapiScsiPrivate
->PciIo
,
1367 AtapiScsiPrivate
->IoPort
->Reg
.Command
,
1372 // Before data transfer, BSY should be 0 and DRQ should be 1.
1373 // if they are not in specified time frame,
1374 // retrieve Sense Key from Error Register before return.
1376 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1377 if (EFI_ERROR (Status
)) {
1378 if (Status
== EFI_ABORTED
) {
1379 Status
= EFI_DEVICE_ERROR
;
1387 // Send out command packet
1389 CommandIndex
= (UINT16
*) PacketCommand
;
1390 for (Count
= 0; Count
< 6; Count
++, CommandIndex
++) {
1391 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *CommandIndex
);
1395 // call AtapiPassThruPioReadWriteData() function to get
1396 // requested transfer data form device.
1398 return AtapiPassThruPioReadWriteData (
1403 TimeoutInMicroSeconds
1408 Performs data transfer between ATAPI device and host after the
1409 ATAPI command packet is sent.
1411 @param AtapiScsiPrivate: Private data structure for the specified channel.
1412 @param Buffer: Points to the transferred data.
1413 @param ByteCount: When input,indicates the buffer size; when output,
1414 indicates the actually transferred data size.
1415 @param Direction: Indicates the data transfer direction.
1416 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1417 to use for the execution of this ATAPI command.
1418 A TimeoutInMicroSeconds value of 0 means that
1419 this function will wait indefinitely for the ATAPI
1422 If TimeoutInMicroSeconds is greater than zero, then
1423 this function will return EFI_TIMEOUT if the time
1424 required to execute the ATAPI command is greater
1425 than TimeoutInMicroSeconds.
1428 @todo AtapiScsiPrivate - add argument and description to function comment
1429 @todo Buffer - add argument and description to function comment
1430 @todo ByteCount - add argument and description to function comment
1431 @todo Direction - add argument and description to function comment
1432 @todo EFI_DEVICE_ERROR - add return value to function comment
1433 @todo EFI_DEVICE_ERROR - add return value to function comment
1434 @todo EFI_WARN_BUFFER_TOO_SMALL - add return value to function comment
1437 AtapiPassThruPioReadWriteData (
1438 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1441 DATA_DIRECTION Direction
,
1442 UINT64 TimeoutInMicroSeconds
1446 UINT32 RequiredWordCount
;
1447 UINT32 ActualWordCount
;
1453 Status
= EFI_SUCCESS
;
1456 // Non Data transfer request is also supported.
1458 if (*ByteCount
== 0 || Buffer
== NULL
) {
1460 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
))) {
1461 return EFI_DEVICE_ERROR
;
1466 RequiredWordCount
= *ByteCount
/ 2;
1469 // ActuralWordCount means the word count of data really transfered.
1471 ActualWordCount
= 0;
1473 while (ActualWordCount
< RequiredWordCount
) {
1475 // before each data transfer stream, the host should poll DRQ bit ready,
1476 // which indicates device's ready for data transfer .
1478 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1479 if (EFI_ERROR (Status
)) {
1480 *ByteCount
= ActualWordCount
* 2;
1482 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
1484 if (ActualWordCount
== 0) {
1485 return EFI_DEVICE_ERROR
;
1488 // ActualWordCount > 0
1490 if (ActualWordCount
< RequiredWordCount
) {
1491 return EFI_BAD_BUFFER_SIZE
;
1495 // get current data transfer size from Cylinder Registers.
1497 WordCount
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderMsb
) << 8;
1498 WordCount
= WordCount
| ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderLsb
);
1499 WordCount
= WordCount
& 0xffff;
1503 // perform a series data In/Out.
1505 for (Index
= 0; (Index
< WordCount
) && (ActualWordCount
< RequiredWordCount
); Index
++, ActualWordCount
++) {
1507 if (Direction
== DataIn
) {
1509 *ptrBuffer
= ReadPortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
);
1512 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *ptrBuffer
);
1520 // After data transfer is completed, normally, DRQ bit should clear.
1522 StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1525 // read status register to check whether error happens.
1527 Status
= AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
1529 *ByteCount
= ActualWordCount
* 2;
1536 Read one byte from a specified I/O port.
1538 @todo function comment is missing 'Routine Description:'
1539 @todo function comment is missing 'Arguments:'
1540 @todo function comment is missing 'Returns:'
1541 @todo PciIo - add argument and description to function comment
1542 @todo Port - add argument and description to function comment
1546 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1556 EFI_PCI_IO_PASS_THROUGH_BAR
,
1566 Read one word from a specified I/O port.
1568 @todo function comment is missing 'Routine Description:'
1569 @todo function comment is missing 'Arguments:'
1570 @todo function comment is missing 'Returns:'
1571 @todo PciIo - add argument and description to function comment
1572 @todo Port - add argument and description to function comment
1576 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1585 EfiPciIoWidthUint16
,
1586 EFI_PCI_IO_PASS_THROUGH_BAR
,
1596 Write one byte to a specified I/O port.
1598 @todo function comment is missing 'Routine Description:'
1599 @todo function comment is missing 'Arguments:'
1600 @todo function comment is missing 'Returns:'
1601 @todo PciIo - add argument and description to function comment
1602 @todo Port - add argument and description to function comment
1603 @todo Data - add argument and description to function comment
1607 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1616 EFI_PCI_IO_PASS_THROUGH_BAR
,
1626 Write one word to a specified I/O port.
1628 @todo function comment is missing 'Routine Description:'
1629 @todo function comment is missing 'Arguments:'
1630 @todo function comment is missing 'Returns:'
1631 @todo PciIo - add argument and description to function comment
1632 @todo Port - add argument and description to function comment
1633 @todo Data - add argument and description to function comment
1637 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1645 EfiPciIoWidthUint16
,
1646 EFI_PCI_IO_PASS_THROUGH_BAR
,
1654 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
1655 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1656 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1659 @todo function comment is missing 'Routine Description:'
1660 @todo function comment is missing 'Arguments:'
1661 @todo function comment is missing 'Returns:'
1662 @todo AtapiScsiPrivate - add argument and description to function comment
1663 @todo TimeoutInMicroSeconds - add argument and description to function comment
1664 @todo EFI_ABORTED - add return value to function comment
1665 @todo EFI_TIMEOUT - add return value to function comment
1666 @todo EFI_SUCCESS - add return value to function comment
1670 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1671 UINT64 TimeoutInMicroSeconds
1675 UINT8 StatusRegister
;
1678 if (TimeoutInMicroSeconds
== 0) {
1681 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1686 StatusRegister
= ReadPortB (
1687 AtapiScsiPrivate
->PciIo
,
1688 AtapiScsiPrivate
->IoPort
->Reg
.Status
1692 // wait for BSY == 0 and DRQ == 0
1694 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
1698 // check whether the command is aborted by the device
1700 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1702 ErrRegister
= ReadPortB (
1703 AtapiScsiPrivate
->PciIo
,
1704 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1706 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1717 // Loop infinitely if not meeting expected condition
1719 if (TimeoutInMicroSeconds
== 0) {
1734 Check whether DRQ is clear in the Alternate Status Register.
1735 (BSY must also be cleared).
1736 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1737 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1740 @todo function comment is missing 'Routine Description:'
1741 @todo function comment is missing 'Arguments:'
1742 @todo function comment is missing 'Returns:'
1743 @todo AtapiScsiPrivate - add argument and description to function comment
1744 @todo TimeoutInMicroSeconds - add argument and description to function comment
1745 @todo EFI_ABORTED - add return value to function comment
1746 @todo EFI_TIMEOUT - add return value to function comment
1747 @todo EFI_SUCCESS - add return value to function comment
1751 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1752 UINT64 TimeoutInMicroSeconds
1756 UINT8 AltStatusRegister
;
1759 if (TimeoutInMicroSeconds
== 0) {
1762 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1767 AltStatusRegister
= ReadPortB (
1768 AtapiScsiPrivate
->PciIo
,
1769 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1773 // wait for BSY == 0 and DRQ == 0
1775 if ((AltStatusRegister
& (DRQ
| BSY
)) == 0) {
1779 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
1781 ErrRegister
= ReadPortB (
1782 AtapiScsiPrivate
->PciIo
,
1783 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1785 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1796 // Loop infinitely if not meeting expected condition
1798 if (TimeoutInMicroSeconds
== 0) {
1813 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
1814 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1815 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1818 @todo function comment is missing 'Routine Description:'
1819 @todo function comment is missing 'Arguments:'
1820 @todo function comment is missing 'Returns:'
1821 @todo AtapiScsiPrivate - add argument and description to function comment
1822 @todo TimeoutInMicroSeconds - add argument and description to function comment
1823 @todo EFI_ABORTED - add return value to function comment
1824 @todo EFI_TIMEOUT - add return value to function comment
1825 @todo EFI_SUCCESS - add return value to function comment
1829 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1830 UINT64 TimeoutInMicroSeconds
1834 UINT8 StatusRegister
;
1837 if (TimeoutInMicroSeconds
== 0) {
1840 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1845 // read Status Register will clear interrupt
1847 StatusRegister
= ReadPortB (
1848 AtapiScsiPrivate
->PciIo
,
1849 AtapiScsiPrivate
->IoPort
->Reg
.Status
1855 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1859 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1861 ErrRegister
= ReadPortB (
1862 AtapiScsiPrivate
->PciIo
,
1863 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1865 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1876 // Loop infinitely if not meeting expected condition
1878 if (TimeoutInMicroSeconds
== 0) {
1893 Check whether DRQ is ready in the Alternate Status Register.
1894 (BSY must also be cleared)
1895 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1896 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1899 @todo function comment is missing 'Routine Description:'
1900 @todo function comment is missing 'Arguments:'
1901 @todo function comment is missing 'Returns:'
1902 @todo AtapiScsiPrivate - add argument and description to function comment
1903 @todo TimeoutInMicroSeconds - add argument and description to function comment
1904 @todo EFI_ABORTED - add return value to function comment
1905 @todo EFI_TIMEOUT - add return value to function comment
1906 @todo EFI_SUCCESS - add return value to function comment
1910 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1911 UINT64 TimeoutInMicroSeconds
1915 UINT8 AltStatusRegister
;
1918 if (TimeoutInMicroSeconds
== 0) {
1921 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1926 // read Status Register will clear interrupt
1928 AltStatusRegister
= ReadPortB (
1929 AtapiScsiPrivate
->PciIo
,
1930 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1935 if ((AltStatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1939 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
1941 ErrRegister
= ReadPortB (
1942 AtapiScsiPrivate
->PciIo
,
1943 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1945 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1956 // Loop infinitely if not meeting expected condition
1958 if (TimeoutInMicroSeconds
== 0) {
1973 Check whether BSY is clear in the Status Register.
1974 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1975 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1978 @todo function comment is missing 'Routine Description:'
1979 @todo function comment is missing 'Arguments:'
1980 @todo function comment is missing 'Returns:'
1981 @todo AtapiScsiPrivate - add argument and description to function comment
1982 @todo TimeoutInMicroSeconds - add argument and description to function comment
1983 @todo EFI_TIMEOUT - add return value to function comment
1984 @todo EFI_SUCCESS - add return value to function comment
1987 StatusWaitForBSYClear (
1988 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1989 UINT64 TimeoutInMicroSeconds
1993 UINT8 StatusRegister
;
1995 if (TimeoutInMicroSeconds
== 0) {
1998 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2003 StatusRegister
= ReadPortB (
2004 AtapiScsiPrivate
->PciIo
,
2005 AtapiScsiPrivate
->IoPort
->Reg
.Status
2007 if ((StatusRegister
& BSY
) == 0x00) {
2017 // Loop infinitely if not meeting expected condition
2019 if (TimeoutInMicroSeconds
== 0) {
2034 Check whether BSY is clear in the Alternate Status Register.
2035 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2036 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2039 @todo function comment is missing 'Routine Description:'
2040 @todo function comment is missing 'Arguments:'
2041 @todo function comment is missing 'Returns:'
2042 @todo AtapiScsiPrivate - add argument and description to function comment
2043 @todo TimeoutInMicroSeconds - add argument and description to function comment
2044 @todo EFI_TIMEOUT - add return value to function comment
2045 @todo EFI_SUCCESS - add return value to function comment
2048 AltStatusWaitForBSYClear (
2049 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2050 UINT64 TimeoutInMicroSeconds
2054 UINT8 AltStatusRegister
;
2056 if (TimeoutInMicroSeconds
== 0) {
2059 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2064 AltStatusRegister
= ReadPortB (
2065 AtapiScsiPrivate
->PciIo
,
2066 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2068 if ((AltStatusRegister
& BSY
) == 0x00) {
2077 // Loop infinitely if not meeting expected condition
2079 if (TimeoutInMicroSeconds
== 0) {
2094 Check whether DRDY is ready in the Status Register.
2095 (BSY must also be cleared)
2096 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2097 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2100 @todo function comment is missing 'Routine Description:'
2101 @todo function comment is missing 'Arguments:'
2102 @todo function comment is missing 'Returns:'
2103 @todo AtapiScsiPrivate - add argument and description to function comment
2104 @todo TimeoutInMicroSeconds - add argument and description to function comment
2105 @todo EFI_ABORTED - add return value to function comment
2106 @todo EFI_TIMEOUT - add return value to function comment
2107 @todo EFI_SUCCESS - add return value to function comment
2111 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2112 UINT64 TimeoutInMicroSeconds
2116 UINT8 StatusRegister
;
2119 if (TimeoutInMicroSeconds
== 0) {
2122 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2126 StatusRegister
= ReadPortB (
2127 AtapiScsiPrivate
->PciIo
,
2128 AtapiScsiPrivate
->IoPort
->Reg
.Status
2131 // BSY == 0 , DRDY == 1
2133 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
2137 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
2139 ErrRegister
= ReadPortB (
2140 AtapiScsiPrivate
->PciIo
,
2141 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2143 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2153 // Loop infinitely if not meeting expected condition
2155 if (TimeoutInMicroSeconds
== 0) {
2170 Check whether DRDY is ready in the Alternate Status Register.
2171 (BSY must also be cleared)
2172 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2173 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2176 @todo function comment is missing 'Routine Description:'
2177 @todo function comment is missing 'Arguments:'
2178 @todo function comment is missing 'Returns:'
2179 @todo AtapiScsiPrivate - add argument and description to function comment
2180 @todo TimeoutInMicroSeconds - add argument and description to function comment
2181 @todo EFI_ABORTED - add return value to function comment
2182 @todo EFI_TIMEOUT - add return value to function comment
2183 @todo EFI_SUCCESS - add return value to function comment
2186 AltStatusDRDYReady (
2187 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2188 UINT64 TimeoutInMicroSeconds
2192 UINT8 AltStatusRegister
;
2195 if (TimeoutInMicroSeconds
== 0) {
2198 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2202 AltStatusRegister
= ReadPortB (
2203 AtapiScsiPrivate
->PciIo
,
2204 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2207 // BSY == 0 , DRDY == 1
2209 if ((AltStatusRegister
& (DRDY
| BSY
)) == DRDY
) {
2213 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2215 ErrRegister
= ReadPortB (
2216 AtapiScsiPrivate
->PciIo
,
2217 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2219 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2229 // Loop infinitely if not meeting expected condition
2231 if (TimeoutInMicroSeconds
== 0) {
2246 Check Error Register for Error Information.
2248 @todo function comment is missing 'Routine Description:'
2249 @todo function comment is missing 'Arguments:'
2250 @todo function comment is missing 'Returns:'
2251 @todo AtapiScsiPrivate - add argument and description to function comment
2252 @todo EFI_SUCCESS - add return value to function comment
2253 @todo EFI_DEVICE_ERROR - add return value to function comment
2256 AtapiPassThruCheckErrorStatus (
2257 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
2260 UINT8 StatusRegister
;
2261 UINT8 ErrorRegister
;
2263 StatusRegister
= ReadPortB (
2264 AtapiScsiPrivate
->PciIo
,
2265 AtapiScsiPrivate
->IoPort
->Reg
.Status
2268 DEBUG_CODE_BEGIN ();
2270 if (StatusRegister
& DWF
) {
2273 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
2278 if (StatusRegister
& CORR
) {
2281 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
2286 if (StatusRegister
& ERR
) {
2287 ErrorRegister
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg1
.Error
);
2290 if (ErrorRegister
& BBK_ERR
) {
2293 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
2298 if (ErrorRegister
& UNC_ERR
) {
2301 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
2306 if (ErrorRegister
& MC_ERR
) {
2309 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
2314 if (ErrorRegister
& ABRT_ERR
) {
2317 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
2322 if (ErrorRegister
& TK0NF_ERR
) {
2325 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
2330 if (ErrorRegister
& AMNF_ERR
) {
2333 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
2341 if ((StatusRegister
& (ERR
| DWF
| CORR
)) == 0) {
2346 return EFI_DEVICE_ERROR
;
2350 The user Entry Point for module AtapiPassThru. The user code starts with this function.
2352 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2353 @param[in] SystemTable A pointer to the EFI System Table.
2355 @retval EFI_SUCCESS The entry point is executed successfully.
2356 @retval other Some error occurs when executing this entry point.
2361 InitializeAtapiPassThru(
2362 IN EFI_HANDLE ImageHandle
,
2363 IN EFI_SYSTEM_TABLE
*SystemTable
2369 // Install driver model protocol(s).
2371 Status
= EfiLibInstallDriverBindingComponentName2 (
2374 &gAtapiScsiPassThruDriverBinding
,
2376 &gAtapiScsiPassThruComponentName
,
2377 &gAtapiScsiPassThruComponentName2
2379 ASSERT_EFI_ERROR (Status
);