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 /// IDE registers' fixed address
18 static IDE_BASE_REGISTERS gAtapiIoPortRegisters
[2] = {
19 { 0x1f0, { 0x1f1 }, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, { 0x1f7 }, { 0x3f6 }, 0x3f7, 0 },
20 { 0x170, { 0x171 }, 0x172, 0x173, 0x174, 0x175, 0x176, { 0x177 }, { 0x376 }, 0x377, 0 }
23 static SCSI_COMMAND_SET gEndTable
= { 0xff, (DATA_DIRECTION
) 0xff };
26 /// This table contains all the supported ATAPI commands.
28 static SCSI_COMMAND_SET gSupportedATAPICommands
[] = {
29 { OP_INQUIRY
, DataIn
},
30 { OP_LOAD_UNLOAD_CD
, NoData
},
31 { OP_MECHANISM_STATUS
, DataIn
},
32 { OP_MODE_SELECT_10
, DataOut
},
33 { OP_MODE_SENSE_10
, DataIn
},
34 { OP_PAUSE_RESUME
, NoData
},
35 { OP_PLAY_AUDIO_10
, DataIn
},
36 { OP_PLAY_AUDIO_MSF
, DataIn
},
37 { OP_PLAY_CD
, DataIn
},
38 { OP_PLAY_CD_MSF
, DataIn
},
39 { OP_PREVENT_ALLOW_MEDIUM_REMOVAL
,NoData
},
40 { OP_READ_10
, DataIn
},
41 { OP_READ_12
, DataIn
},
42 { OP_READ_CAPACITY
, DataIn
},
43 { OP_READ_CD
, DataIn
},
44 { OP_READ_CD_MSF
, DataIn
},
45 { OP_READ_HEADER
, DataIn
},
46 { OP_READ_SUB_CHANNEL
, DataIn
},
47 { OP_READ_TOC
, DataIn
},
48 { OP_REQUEST_SENSE
, DataIn
},
50 { OP_SEEK_10
, NoData
},
51 { OP_SET_CD_SPEED
, DataOut
},
52 { OP_STOPPLAY_SCAN
, NoData
},
53 { OP_START_STOP_UNIT
, NoData
},
54 { OP_TEST_UNIT_READY
, NoData
},
55 { OP_FORMAT_UNIT
, DataOut
},
56 { OP_READ_FORMAT_CAPACITIES
, DataIn
},
57 { OP_VERIFY
, DataOut
},
58 { OP_WRITE_10
, DataOut
},
59 { OP_WRITE_12
, DataOut
},
60 { OP_WRITE_AND_VERIFY
, DataOut
},
61 { 0xff, (DATA_DIRECTION
) 0xff }
64 static CHAR16
*gControllerNameString
= (CHAR16
*) L
"ATAPI Controller";
65 static CHAR16
*gAtapiChannelString
= (CHAR16
*) L
"ATAPI Channel";
67 EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding
= {
68 AtapiScsiPassThruDriverBindingSupported
,
69 AtapiScsiPassThruDriverBindingStart
,
70 AtapiScsiPassThruDriverBindingStop
,
79 (Standard DriverBinding Protocol Supported() function)
83 @todo This - add argument and description to function comment
84 @todo Controller - add argument and description to function comment
85 @todo RemainingDevicePath - add argument and description to function comment
86 @todo EFI_UNSUPPORTED - add return value to function comment
90 AtapiScsiPassThruDriverBindingSupported (
91 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
92 IN EFI_HANDLE Controller
,
93 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
97 EFI_PCI_IO_PROTOCOL
*PciIo
;
101 // Open the IO Abstraction(s) needed to perform the supported test
103 Status
= gBS
->OpenProtocol (
105 &gEfiPciIoProtocolGuid
,
107 This
->DriverBindingHandle
,
109 EFI_OPEN_PROTOCOL_BY_DRIVER
111 if (EFI_ERROR (Status
)) {
115 // Use the PCI I/O Protocol to see if Controller is a IDE Controller that
116 // can be managed by this driver. Read the PCI Configuration Header
119 Status
= PciIo
->Pci
.Read (
123 sizeof (Pci
) / sizeof (UINT32
),
126 if (EFI_ERROR (Status
)) {
129 &gEfiPciIoProtocolGuid
,
130 This
->DriverBindingHandle
,
133 return EFI_UNSUPPORTED
;
136 if (Pci
.Hdr
.ClassCode
[2] != PCI_CLASS_MASS_STORAGE
|| Pci
.Hdr
.ClassCode
[1] != PCI_CLASS_IDE
) {
138 Status
= EFI_UNSUPPORTED
;
143 &gEfiPciIoProtocolGuid
,
144 This
->DriverBindingHandle
,
152 Create handles for IDE channels specified by RemainingDevicePath.
153 Install SCSI Pass Thru Protocol onto each created handle.
155 (Standard DriverBinding Protocol Start() function)
159 @todo This - add argument and description to function comment
160 @todo Controller - add argument and description to function comment
161 @todo RemainingDevicePath - add argument and description to function comment
165 AtapiScsiPassThruDriverBindingStart (
166 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
167 IN EFI_HANDLE Controller
,
168 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
172 EFI_PCI_IO_PROTOCOL
*PciIo
;
175 Status
= gBS
->OpenProtocol (
177 &gEfiPciIoProtocolGuid
,
179 This
->DriverBindingHandle
,
181 EFI_OPEN_PROTOCOL_BY_DRIVER
183 if (EFI_ERROR (Status
)) {
187 Status
= PciIo
->Attributes (
189 EfiPciIoAttributeOperationEnable
,
190 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
,
193 if (EFI_ERROR (Status
)) {
198 // Create SCSI Pass Thru instance for the IDE channel.
200 Status
= RegisterAtapiScsiPassThru (This
, Controller
, PciIo
);
203 if (EFI_ERROR (Status
)) {
207 EfiPciIoAttributeOperationDisable
,
208 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
,
215 &gEfiPciIoProtocolGuid
,
216 This
->DriverBindingHandle
,
227 (Standard DriverBinding Protocol Stop() function)
231 @todo This - add argument and description to function comment
232 @todo Controller - add argument and description to function comment
233 @todo NumberOfChildren - add argument and description to function comment
234 @todo ChildHandleBuffer - add argument and description to function comment
235 @todo EFI_SUCCESS - add return value to function comment
239 AtapiScsiPassThruDriverBindingStop (
240 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
241 IN EFI_HANDLE Controller
,
242 IN UINTN NumberOfChildren
,
243 IN EFI_HANDLE
*ChildHandleBuffer
247 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
248 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
250 Status
= gBS
->OpenProtocol (
252 &gEfiScsiPassThruProtocolGuid
,
253 (VOID
**) &ScsiPassThru
,
254 This
->DriverBindingHandle
,
256 EFI_OPEN_PROTOCOL_GET_PROTOCOL
258 if (EFI_ERROR (Status
)) {
262 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru
);
264 Status
= gBS
->UninstallProtocolInterface (
266 &gEfiScsiPassThruProtocolGuid
,
267 &AtapiScsiPrivate
->ScsiPassThru
269 if (EFI_ERROR (Status
)) {
273 // Release Pci Io protocol on the controller handle.
275 AtapiScsiPrivate
->PciIo
->Attributes (
276 AtapiScsiPrivate
->PciIo
,
277 EfiPciIoAttributeOperationDisable
,
278 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
,
284 &gEfiPciIoProtocolGuid
,
285 This
->DriverBindingHandle
,
289 gBS
->FreePool (AtapiScsiPrivate
);
295 Attaches SCSI Pass Thru Protocol for specified IDE channel.
297 @param Controller: Parent device handle to the IDE channel.
298 @param PciIo: PCI I/O protocol attached on the "Controller".
300 @return EFI_SUCCESS Always returned unless installing SCSI Pass Thru Protocol failed.
302 @todo This - add argument and description to function comment
303 @todo Controller - add argument and description to function comment
304 @todo PciIo - add argument and description to function comment
305 @todo EFI_OUT_OF_RESOURCES - add return value to function comment
308 RegisterAtapiScsiPassThru (
309 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
310 IN EFI_HANDLE Controller
,
311 IN EFI_PCI_IO_PROTOCOL
*PciIo
315 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
318 AtapiScsiPrivate
= AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV
));
319 if (AtapiScsiPrivate
== NULL
) {
320 return EFI_OUT_OF_RESOURCES
;
323 Attributes
= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
;
324 CopyMem (AtapiScsiPrivate
->ChannelName
, gAtapiChannelString
, sizeof (gAtapiChannelString
));
329 PciIo
->Attributes (PciIo
, EfiPciIoAttributeOperationSet
, Attributes
, NULL
);
331 AtapiScsiPrivate
->Signature
= ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE
;
332 AtapiScsiPrivate
->Handle
= Controller
;
335 // will reset the IoPort inside each API function.
337 AtapiScsiPrivate
->IoPort
= gAtapiIoPortRegisters
;
338 AtapiScsiPrivate
->PciIo
= PciIo
;
341 // initialize SCSI Pass Thru Protocol interface
343 AtapiScsiPrivate
->ScsiPassThru
.Mode
= &AtapiScsiPrivate
->ScsiPassThruMode
;
344 AtapiScsiPrivate
->ScsiPassThru
.PassThru
= AtapiScsiPassThruFunction
;
345 AtapiScsiPrivate
->ScsiPassThru
.GetNextDevice
= AtapiScsiPassThruGetNextDevice
;
346 AtapiScsiPrivate
->ScsiPassThru
.BuildDevicePath
= AtapiScsiPassThruBuildDevicePath
;
347 AtapiScsiPrivate
->ScsiPassThru
.GetTargetLun
= AtapiScsiPassThruGetTargetLun
;
348 AtapiScsiPrivate
->ScsiPassThru
.ResetChannel
= AtapiScsiPassThruResetChannel
;
349 AtapiScsiPrivate
->ScsiPassThru
.ResetTarget
= AtapiScsiPassThruResetTarget
;
354 CopyMem (AtapiScsiPrivate
->ControllerName
, gControllerNameString
, sizeof (gControllerNameString
));
356 AtapiScsiPrivate
->ScsiPassThruMode
.ControllerName
= AtapiScsiPrivate
->ControllerName
;
357 AtapiScsiPrivate
->ScsiPassThruMode
.ChannelName
= AtapiScsiPrivate
->ChannelName
;
358 AtapiScsiPrivate
->ScsiPassThruMode
.AdapterId
= 4;
360 // non-RAID SCSI controllers should set both physical and logical attributes
362 AtapiScsiPrivate
->ScsiPassThruMode
.Attributes
= EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
363 EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
364 AtapiScsiPrivate
->ScsiPassThruMode
.IoAlign
= 0;
367 // Initialize the LatestTargetId to 0xFFFFFFFF (for the GetNextDevice() call).
369 AtapiScsiPrivate
->LatestTargetId
= 0xFFFFFFFF;
370 AtapiScsiPrivate
->LatestLun
= 0;
372 Status
= gBS
->InstallProtocolInterface (
374 &gEfiScsiPassThruProtocolGuid
,
375 EFI_NATIVE_INTERFACE
,
376 &AtapiScsiPrivate
->ScsiPassThru
382 Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
384 @param This The EFI_SCSI_PASS_THRU_PROTOCOL instance.
385 @param Target The Target ID of the ATAPI device to send the SCSI
386 Request Packet. To ATAPI devices attached on an IDE
387 Channel, Target ID 0 indicates Master device;Target
388 ID 1 indicates Slave device.
389 @param Lun The LUN of the ATAPI device to send the SCSI Request
390 Packet. To the ATAPI device, Lun is always 0.
391 @param Packet The SCSI Request Packet to send to the ATAPI device
392 specified by Target and Lun.
393 @param Event If non-blocking I/O is not supported then Event is ignored,
394 and blocking I/O is performed.<br>
395 If Event is NULL, then blocking I/O is performed.<br>
396 If Event is not NULL and non blocking I/O is supported,
397 then non-blocking I/O is performed, and Event will be signaled
398 when the SCSI Request Packet completes.
400 @todo This - add argument and description to function comment
401 @todo EFI_INVALID_PARAMETER - add return value to function comment
402 @todo EFI_SUCCESS - add return value to function comment
406 AtapiScsiPassThruFunction (
407 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
410 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
411 IN EFI_EVENT Event OPTIONAL
414 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
417 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
420 // Target is not allowed beyond MAX_TARGET_ID
422 if (Target
> MAX_TARGET_ID
) {
423 return EFI_INVALID_PARAMETER
;
427 // check the data fields in Packet parameter.
429 Status
= CheckSCSIRequestPacket (Packet
);
430 if (EFI_ERROR (Status
)) {
435 // If Request Packet targets at the IDE channel itself,
438 if (Target
== This
->Mode
->AdapterId
) {
439 Packet
->TransferLength
= 0;
444 // According to Target ID, reset the Atapi I/O Register mapping
445 // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],
446 // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]
448 if ((Target
/ 2) == 0) {
449 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[0];
451 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[1];
455 // the ATAPI SCSI interface does not support non-blocking I/O
456 // ignore the Event parameter
458 // Performs blocking I/O.
460 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, Packet
);
465 Used to retrieve the list of legal Target IDs for SCSI devices
468 @param This Protocol instance pointer.
469 @param Target On input, a pointer to the Target ID of a SCSI
470 device present on the SCSI channel. On output,
471 a pointer to the Target ID of the next SCSI device
472 present on a SCSI channel. An input value of
473 0xFFFFFFFF retrieves the Target ID of the first
474 SCSI device present on a SCSI channel.
475 @param Lun On input, a pointer to the LUN of a SCSI device
476 present on the SCSI channel. On output, a pointer
477 to the LUN of the next SCSI device present on
480 @retval EFI_SUCCESS The Target ID and Lun of the next SCSI device
481 on the SCSI channel was returned in Target and Lun.
482 @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
483 @retval EFI_INVALID_PARAMETER Target is not 0xFFFFFFFF,and Target and Lun were not
484 returned on a previous call to GetNextDevice().
489 AtapiScsiPassThruGetNextDevice (
490 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
491 IN OUT UINT32
*Target
,
495 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
498 // Retrieve Device Private Data Structure.
500 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
503 // Check whether Target is valid.
505 if (Target
== NULL
|| Lun
== NULL
) {
506 return EFI_INVALID_PARAMETER
;
509 if ((*Target
!= 0xFFFFFFFF) &&
510 ((*Target
!= AtapiScsiPrivate
->LatestTargetId
) ||
511 (*Lun
!= AtapiScsiPrivate
->LatestLun
))) {
512 return EFI_INVALID_PARAMETER
;
515 if (*Target
== MAX_TARGET_ID
) {
516 return EFI_NOT_FOUND
;
519 if (*Target
== 0xFFFFFFFF) {
522 *Target
= AtapiScsiPrivate
->LatestTargetId
+ 1;
528 // Update the LatestTargetId.
530 AtapiScsiPrivate
->LatestTargetId
= *Target
;
531 AtapiScsiPrivate
->LatestLun
= *Lun
;
538 Used to allocate and build a device path node for a SCSI device
539 on a SCSI channel. Would not build device path for a SCSI Host Controller.
541 @param This Protocol instance pointer.
542 @param Target The Target ID of the SCSI device for which
543 a device path node is to be allocated and built.
544 @param Lun The LUN of the SCSI device for which a device
545 path node is to be allocated and built.
546 @param DevicePath A pointer to a single device path node that
547 describes the SCSI device specified by
548 Target and Lun. This function is responsible
549 for allocating the buffer DevicePath with the boot
550 service AllocatePool(). It is the caller's
551 responsibility to free DevicePath when the caller
552 is finished with DevicePath.
554 @retval EFI_SUCCESS The device path node that describes the SCSI device
555 specified by Target and Lun was allocated and
556 returned in DevicePath.
557 @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does
558 not exist on the SCSI channel.
559 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
560 @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate
566 AtapiScsiPassThruBuildDevicePath (
567 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
570 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
576 // Validate parameters passed in.
579 if (DevicePath
== NULL
) {
580 return EFI_INVALID_PARAMETER
;
584 // can not build device path for the SCSI Host Controller.
586 if ((Target
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
587 return EFI_NOT_FOUND
;
590 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
592 return EFI_OUT_OF_RESOURCES
;
595 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
596 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
597 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
599 Node
->Atapi
.PrimarySecondary
= (UINT8
) (Target
/ 2);
600 Node
->Atapi
.SlaveMaster
= (UINT8
) (Target
% 2);
601 Node
->Atapi
.Lun
= (UINT16
) Lun
;
603 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
609 Used to translate a device path node to a Target ID and LUN.
611 @param This Protocol instance pointer.
612 @param DevicePath A pointer to the device path node that
613 describes a SCSI device on the SCSI channel.
614 @param Target A pointer to the Target ID of a SCSI device
616 @param Lun A pointer to the LUN of a SCSI device on
619 @retval EFI_SUCCESS DevicePath was successfully translated to a
620 Target ID and LUN, and they were returned
622 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
623 @retval EFI_INVALID_PARAMETER Target is NULL.
624 @retval EFI_INVALID_PARAMETER Lun is NULL.
625 @retval EFI_UNSUPPORTED This driver does not support the device path
626 node type in DevicePath.
627 @retval EFI_NOT_FOUND A valid translation from DevicePath to a
628 Target ID and LUN does not exist.
633 AtapiScsiPassThruGetTargetLun (
634 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
635 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
643 // Validate parameters passed in.
645 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
646 return EFI_INVALID_PARAMETER
;
650 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
652 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
653 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
654 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
655 return EFI_UNSUPPORTED
;
658 Node
= (EFI_DEV_PATH
*) DevicePath
;
660 *Target
= Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
;
661 *Lun
= Node
->Atapi
.Lun
;
663 if (*Target
> (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
664 return EFI_NOT_FOUND
;
671 Resets a SCSI channel.This operation resets all the
672 SCSI devices connected to the SCSI channel.
674 @param This Protocol instance pointer.
676 @retval EFI_SUCCESS The SCSI channel was reset.
677 @retval EFI_UNSUPPORTED The SCSI channel does not support
678 a channel reset operation.
679 @retval EFI_DEVICE_ERROR A device error occurred while
680 attempting to reset the SCSI channel.
681 @retval EFI_TIMEOUT A timeout occurred while attempting
682 to reset the SCSI channel.
687 AtapiScsiPassThruResetChannel (
688 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
691 UINT8 DeviceControlValue
;
692 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
695 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
698 // Reset both Primary channel and Secondary channel.
699 // so, the IoPort pointer must point to the right I/O Register group
701 for (Index
= 0; Index
< 2; Index
++) {
705 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[Index
];
707 DeviceControlValue
= 0;
709 // set SRST bit to initiate soft reset
711 DeviceControlValue
|= SRST
;
715 DeviceControlValue
|= bit (1);
717 AtapiScsiPrivate
->PciIo
,
718 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
731 DeviceControlValue
&= 0xfb;
733 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
736 // slave device needs at most 31s to clear BSY
738 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000) == EFI_TIMEOUT
) {
739 return EFI_DEVICE_ERROR
;
747 Resets a SCSI device that is connected to a SCSI channel.
749 @param This Protocol instance pointer.
750 @param Target The Target ID of the SCSI device to reset.
751 @param Lun The LUN of the SCSI device to reset.
753 @retval EFI_SUCCESS The SCSI device specified by Target and
755 @retval EFI_UNSUPPORTED The SCSI channel does not support a target
757 @retval EFI_INVALID_PARAMETER Target or Lun are invalid.
758 @retval EFI_DEVICE_ERROR A device error occurred while attempting
759 to reset the SCSI device specified by Target
761 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
762 the SCSI device specified by Target and Lun.
767 AtapiScsiPassThruResetTarget (
768 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
773 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
777 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
779 if (Target
> MAX_TARGET_ID
) {
780 return EFI_INVALID_PARAMETER
;
783 // Directly return EFI_SUCCESS if want to reset the host controller
785 if (Target
== This
->Mode
->AdapterId
) {
790 // According to Target ID, reset the Atapi I/O Register mapping
791 // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],
792 // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]
794 if ((Target
/ 2) == 0) {
795 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[0];
797 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[1];
801 // for ATAPI device, no need to wait DRDY ready after device selecting.
803 // bit7 and bit5 are both set to 1 for backward compatibility
805 DeviceSelect
= (UINT8
) (((bit (7) | bit (5)) | (Target
<< 4)));
806 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
808 Command
= ATAPI_SOFT_RESET_CMD
;
809 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
812 // BSY clear is the only status return to the host by the device
813 // when reset is complete.
814 // slave device needs at most 31s to clear BSY
816 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000))) {
817 return EFI_DEVICE_ERROR
;
821 // stall 5 seconds to make the device status stable
823 gBS
->Stall (5000000);
830 Checks the parameters in the SCSI Request Packet to make sure
831 they are valid for a SCSI Pass Thru request.
833 @todo function comment is missing 'Routine Description:'
834 @todo function comment is missing 'Arguments:'
835 @todo function comment is missing 'Returns:'
836 @todo Packet - add argument and description to function comment
837 @todo EFI_INVALID_PARAMETER - add return value to function comment
838 @todo EFI_INVALID_PARAMETER - add return value to function comment
839 @todo EFI_INVALID_PARAMETER - add return value to function comment
840 @todo EFI_UNSUPPORTED - add return value to function comment
841 @todo EFI_SUCCESS - add return value to function comment
844 CheckSCSIRequestPacket (
845 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
848 if (Packet
== NULL
) {
849 return EFI_INVALID_PARAMETER
;
852 if (!ValidCdbLength (Packet
->CdbLength
)) {
853 return EFI_INVALID_PARAMETER
;
856 if (Packet
->Cdb
== NULL
) {
857 return EFI_INVALID_PARAMETER
;
861 // Checks whether the request command is supported.
863 if (!IsCommandValid (Packet
)) {
864 return EFI_UNSUPPORTED
;
871 Checks the requested SCSI command:
872 Is it supported by this driver?
873 Is the Data transfer direction reasonable?
875 @todo function comment is missing 'Routine Description:'
876 @todo function comment is missing 'Arguments:'
877 @todo function comment is missing 'Returns:'
878 @todo Packet - add argument and description to function comment
882 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
888 OpCode
= (UINT8
*) (Packet
->Cdb
);
890 for (Index
= 0; CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)); Index
++) {
892 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
894 // Check whether the requested Command is supported by this driver
896 if (Packet
->DataDirection
== DataIn
) {
898 // Check whether the requested data direction conforms to
899 // what it should be.
901 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
906 if (Packet
->DataDirection
== DataOut
) {
908 // Check whether the requested data direction conforms to
909 // what it should be.
911 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
924 Performs blocking I/O request.
926 @param AtapiScsiPrivate Private data structure for the specified channel.
927 @param Target The Target ID of the ATAPI device to send the SCSI
928 Request Packet. To ATAPI devices attached on an IDE
929 Channel, Target ID 0 indicates Master device;Target
930 ID 1 indicates Slave device.
931 @param Packet The SCSI Request Packet to send to the ATAPI device
934 @todo AtapiScsiPrivate - add argument and description to function comment
937 SubmitBlockingIoCommand (
938 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
940 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
943 UINT8 PacketCommand
[12];
944 UINT64 TimeoutInMicroSeconds
;
945 EFI_STATUS PacketCommandStatus
;
948 // Fill ATAPI Command Packet according to CDB
950 ZeroMem (&PacketCommand
, 12);
951 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
954 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
956 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
959 // Submit ATAPI Command Packet
961 PacketCommandStatus
= AtapiPacketCommand (
966 &(Packet
->TransferLength
),
967 (DATA_DIRECTION
) Packet
->DataDirection
,
968 TimeoutInMicroSeconds
970 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
971 Packet
->SenseDataLength
= 0;
972 return PacketCommandStatus
;
975 // Return SenseData if PacketCommandStatus matches
976 // the following return codes.
978 if ((PacketCommandStatus
== EFI_WARN_BUFFER_TOO_SMALL
) ||
979 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
980 (PacketCommandStatus
== EFI_TIMEOUT
)) {
983 // avoid submit request sense command continuously.
985 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
986 Packet
->SenseDataLength
= 0;
987 return PacketCommandStatus
;
990 RequestSenseCommand (
995 &Packet
->SenseDataLength
999 return PacketCommandStatus
;
1005 @param AtapiScsiPrivate
1009 @param SenseDataLength
1011 @todo Add function description
1012 @todo AtapiScsiPrivate TODO: add argument description
1013 @todo Target TODO: add argument description
1014 @todo Timeout TODO: add argument description
1015 @todo SenseData TODO: add argument description
1016 @todo SenseDataLength TODO: add argument description
1017 @todo add return values
1020 RequestSenseCommand (
1021 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1025 UINT8
*SenseDataLength
1028 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet
;
1032 ZeroMem (&Packet
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1035 Cdb
[0] = OP_REQUEST_SENSE
;
1036 Cdb
[4] = (UINT8
) (*SenseDataLength
);
1038 Packet
.Timeout
= Timeout
;
1039 Packet
.DataBuffer
= SenseData
;
1040 Packet
.SenseData
= NULL
;
1042 Packet
.TransferLength
= *SenseDataLength
;
1043 Packet
.CdbLength
= 12;
1044 Packet
.DataDirection
= DataIn
;
1046 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, &Packet
);
1047 *SenseDataLength
= (UINT8
) (Packet
.TransferLength
);
1052 Submits ATAPI command packet to the specified ATAPI device.
1054 @param AtapiScsiPrivate: Private data structure for the specified channel.
1055 @param Target: The Target ID of the ATAPI device to send the SCSI
1056 Request Packet. To ATAPI devices attached on an IDE
1057 Channel, Target ID 0 indicates Master device;Target
1058 ID 1 indicates Slave device.
1059 @param PacketCommand: Points to the ATAPI command packet.
1060 @param Buffer: Points to the transferred data.
1061 @param ByteCount: When input,indicates the buffer size; when output,
1062 indicates the actually transferred data size.
1063 @param Direction: Indicates the data transfer direction.
1064 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1065 to use for the execution of this ATAPI command.
1066 A TimeoutInMicroSeconds value of 0 means that
1067 this function will wait indefinitely for the ATAPI
1070 If TimeoutInMicroSeconds is greater than zero, then
1071 this function will return EFI_TIMEOUT if the time
1072 required to execute the ATAPI command is greater
1073 than TimeoutInMicroSeconds.
1076 @todo AtapiScsiPrivate - add argument and description to function comment
1077 @todo PacketCommand - add argument and description to function comment
1078 @todo Buffer - add argument and description to function comment
1079 @todo ByteCount - add argument and description to function comment
1080 @todo Direction - add argument and description to function comment
1083 AtapiPacketCommand (
1084 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1086 UINT8
*PacketCommand
,
1089 DATA_DIRECTION Direction
,
1090 UINT64 TimeoutInMicroSeconds
1094 UINT16
*CommandIndex
;
1099 // Set all the command parameters by fill related registers.
1100 // Before write to all the following registers, BSY and DRQ must be 0.
1102 Status
= StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1103 if (EFI_ERROR (Status
)) {
1104 if (Status
== EFI_ABORTED
) {
1105 Status
= EFI_DEVICE_ERROR
;
1112 // Select device via Device/Head Register.
1113 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
1116 AtapiScsiPrivate
->PciIo
,
1117 AtapiScsiPrivate
->IoPort
->Head
,
1118 (UINT8
) ((Target
<< 4) | DEFAULT_CMD
) // DEFAULT_CMD: 0xa0 (1010,0000)
1122 // No OVL; No DMA (by setting feature register)
1125 AtapiScsiPrivate
->PciIo
,
1126 AtapiScsiPrivate
->IoPort
->Reg1
.Feature
,
1131 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
1132 // determine how much data should be transfered.
1135 AtapiScsiPrivate
->PciIo
,
1136 AtapiScsiPrivate
->IoPort
->CylinderLsb
,
1137 (UINT8
) (MAX_ATAPI_BYTE_COUNT
& 0x00ff)
1140 AtapiScsiPrivate
->PciIo
,
1141 AtapiScsiPrivate
->IoPort
->CylinderMsb
,
1142 (UINT8
) (MAX_ATAPI_BYTE_COUNT
>> 8)
1146 // DEFAULT_CTL:0x0a (0000,1010)
1147 // Disable interrupt
1150 AtapiScsiPrivate
->PciIo
,
1151 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
1156 // Send Packet command to inform device
1157 // that the following data bytes are command packet.
1160 AtapiScsiPrivate
->PciIo
,
1161 AtapiScsiPrivate
->IoPort
->Reg
.Command
,
1166 // Before data transfer, BSY should be 0 and DRQ should be 1.
1167 // if they are not in specified time frame,
1168 // retrieve Sense Key from Error Register before return.
1170 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1171 if (EFI_ERROR (Status
)) {
1172 if (Status
== EFI_ABORTED
) {
1173 Status
= EFI_DEVICE_ERROR
;
1181 // Send out command packet
1183 CommandIndex
= (UINT16
*) PacketCommand
;
1184 for (Count
= 0; Count
< 6; Count
++, CommandIndex
++) {
1185 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *CommandIndex
);
1189 // call AtapiPassThruPioReadWriteData() function to get
1190 // requested transfer data form device.
1192 return AtapiPassThruPioReadWriteData (
1197 TimeoutInMicroSeconds
1202 Performs data transfer between ATAPI device and host after the
1203 ATAPI command packet is sent.
1205 @param AtapiScsiPrivate: Private data structure for the specified channel.
1206 @param Buffer: Points to the transferred data.
1207 @param ByteCount: When input,indicates the buffer size; when output,
1208 indicates the actually transferred data size.
1209 @param Direction: Indicates the data transfer direction.
1210 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1211 to use for the execution of this ATAPI command.
1212 A TimeoutInMicroSeconds value of 0 means that
1213 this function will wait indefinitely for the ATAPI
1216 If TimeoutInMicroSeconds is greater than zero, then
1217 this function will return EFI_TIMEOUT if the time
1218 required to execute the ATAPI command is greater
1219 than TimeoutInMicroSeconds.
1222 @todo AtapiScsiPrivate - add argument and description to function comment
1223 @todo Buffer - add argument and description to function comment
1224 @todo ByteCount - add argument and description to function comment
1225 @todo Direction - add argument and description to function comment
1226 @todo EFI_DEVICE_ERROR - add return value to function comment
1227 @todo EFI_DEVICE_ERROR - add return value to function comment
1228 @todo EFI_WARN_BUFFER_TOO_SMALL - add return value to function comment
1231 AtapiPassThruPioReadWriteData (
1232 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1235 DATA_DIRECTION Direction
,
1236 UINT64 TimeoutInMicroSeconds
1240 UINT32 RequiredWordCount
;
1241 UINT32 ActualWordCount
;
1247 Status
= EFI_SUCCESS
;
1250 // Non Data transfer request is also supported.
1252 if (*ByteCount
== 0 || Buffer
== NULL
) {
1254 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
))) {
1255 return EFI_DEVICE_ERROR
;
1260 RequiredWordCount
= *ByteCount
/ 2;
1263 // ActuralWordCount means the word count of data really transfered.
1265 ActualWordCount
= 0;
1267 while (ActualWordCount
< RequiredWordCount
) {
1269 // before each data transfer stream, the host should poll DRQ bit ready,
1270 // which indicates device's ready for data transfer .
1272 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1273 if (EFI_ERROR (Status
)) {
1274 *ByteCount
= ActualWordCount
* 2;
1276 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
1278 if (ActualWordCount
== 0) {
1279 return EFI_DEVICE_ERROR
;
1282 // ActualWordCount > 0
1284 if (ActualWordCount
< RequiredWordCount
) {
1285 return EFI_WARN_BUFFER_TOO_SMALL
;
1289 // get current data transfer size from Cylinder Registers.
1291 WordCount
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderMsb
) << 8;
1292 WordCount
= WordCount
| ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderLsb
);
1293 WordCount
= WordCount
& 0xffff;
1297 // perform a series data In/Out.
1299 for (Index
= 0; (Index
< WordCount
) && (ActualWordCount
< RequiredWordCount
); Index
++, ActualWordCount
++) {
1301 if (Direction
== DataIn
) {
1303 *ptrBuffer
= ReadPortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
);
1306 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *ptrBuffer
);
1314 // After data transfer is completed, normally, DRQ bit should clear.
1316 StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1319 // read status register to check whether error happens.
1321 Status
= AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
1323 *ByteCount
= ActualWordCount
* 2;
1330 Read one byte from a specified I/O port.
1332 @todo function comment is missing 'Routine Description:'
1333 @todo function comment is missing 'Arguments:'
1334 @todo function comment is missing 'Returns:'
1335 @todo PciIo - add argument and description to function comment
1336 @todo Port - add argument and description to function comment
1340 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1350 EFI_PCI_IO_PASS_THROUGH_BAR
,
1360 Read one word from a specified I/O port.
1362 @todo function comment is missing 'Routine Description:'
1363 @todo function comment is missing 'Arguments:'
1364 @todo function comment is missing 'Returns:'
1365 @todo PciIo - add argument and description to function comment
1366 @todo Port - add argument and description to function comment
1370 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1379 EfiPciIoWidthUint16
,
1380 EFI_PCI_IO_PASS_THROUGH_BAR
,
1390 Write one byte to a specified I/O port.
1392 @todo function comment is missing 'Routine Description:'
1393 @todo function comment is missing 'Arguments:'
1394 @todo function comment is missing 'Returns:'
1395 @todo PciIo - add argument and description to function comment
1396 @todo Port - add argument and description to function comment
1397 @todo Data - add argument and description to function comment
1401 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1410 EFI_PCI_IO_PASS_THROUGH_BAR
,
1420 Write one word to a specified I/O port.
1422 @todo function comment is missing 'Routine Description:'
1423 @todo function comment is missing 'Arguments:'
1424 @todo function comment is missing 'Returns:'
1425 @todo PciIo - add argument and description to function comment
1426 @todo Port - add argument and description to function comment
1427 @todo Data - add argument and description to function comment
1431 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1439 EfiPciIoWidthUint16
,
1440 EFI_PCI_IO_PASS_THROUGH_BAR
,
1448 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
1449 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1450 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1453 @todo function comment is missing 'Routine Description:'
1454 @todo function comment is missing 'Arguments:'
1455 @todo function comment is missing 'Returns:'
1456 @todo AtapiScsiPrivate - add argument and description to function comment
1457 @todo TimeoutInMicroSeconds - add argument and description to function comment
1458 @todo EFI_ABORTED - add return value to function comment
1459 @todo EFI_TIMEOUT - add return value to function comment
1460 @todo EFI_SUCCESS - add return value to function comment
1464 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1465 UINT64 TimeoutInMicroSeconds
1469 UINT8 StatusRegister
;
1472 if (TimeoutInMicroSeconds
== 0) {
1475 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1480 StatusRegister
= ReadPortB (
1481 AtapiScsiPrivate
->PciIo
,
1482 AtapiScsiPrivate
->IoPort
->Reg
.Status
1486 // wait for BSY == 0 and DRQ == 0
1488 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
1492 // check whether the command is aborted by the device
1494 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1496 ErrRegister
= ReadPortB (
1497 AtapiScsiPrivate
->PciIo
,
1498 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1500 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1511 // Loop infinitely if not meeting expected condition
1513 if (TimeoutInMicroSeconds
== 0) {
1528 Check whether DRQ is clear in the Alternate Status Register.
1529 (BSY must also be cleared).
1530 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1531 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1534 @todo function comment is missing 'Routine Description:'
1535 @todo function comment is missing 'Arguments:'
1536 @todo function comment is missing 'Returns:'
1537 @todo AtapiScsiPrivate - add argument and description to function comment
1538 @todo TimeoutInMicroSeconds - add argument and description to function comment
1539 @todo EFI_ABORTED - add return value to function comment
1540 @todo EFI_TIMEOUT - add return value to function comment
1541 @todo EFI_SUCCESS - add return value to function comment
1545 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1546 UINT64 TimeoutInMicroSeconds
1550 UINT8 AltStatusRegister
;
1553 if (TimeoutInMicroSeconds
== 0) {
1556 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1561 AltStatusRegister
= ReadPortB (
1562 AtapiScsiPrivate
->PciIo
,
1563 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1567 // wait for BSY == 0 and DRQ == 0
1569 if ((AltStatusRegister
& (DRQ
| BSY
)) == 0) {
1573 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
1575 ErrRegister
= ReadPortB (
1576 AtapiScsiPrivate
->PciIo
,
1577 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1579 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1590 // Loop infinitely if not meeting expected condition
1592 if (TimeoutInMicroSeconds
== 0) {
1607 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
1608 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1609 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1612 @todo function comment is missing 'Routine Description:'
1613 @todo function comment is missing 'Arguments:'
1614 @todo function comment is missing 'Returns:'
1615 @todo AtapiScsiPrivate - add argument and description to function comment
1616 @todo TimeoutInMicroSeconds - add argument and description to function comment
1617 @todo EFI_ABORTED - add return value to function comment
1618 @todo EFI_TIMEOUT - add return value to function comment
1619 @todo EFI_SUCCESS - add return value to function comment
1623 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1624 UINT64 TimeoutInMicroSeconds
1628 UINT8 StatusRegister
;
1631 if (TimeoutInMicroSeconds
== 0) {
1634 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1639 // read Status Register will clear interrupt
1641 StatusRegister
= ReadPortB (
1642 AtapiScsiPrivate
->PciIo
,
1643 AtapiScsiPrivate
->IoPort
->Reg
.Status
1649 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1653 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1655 ErrRegister
= ReadPortB (
1656 AtapiScsiPrivate
->PciIo
,
1657 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1659 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1670 // Loop infinitely if not meeting expected condition
1672 if (TimeoutInMicroSeconds
== 0) {
1687 Check whether DRQ is ready in the Alternate Status Register.
1688 (BSY must also be cleared)
1689 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1690 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1693 @todo function comment is missing 'Routine Description:'
1694 @todo function comment is missing 'Arguments:'
1695 @todo function comment is missing 'Returns:'
1696 @todo AtapiScsiPrivate - add argument and description to function comment
1697 @todo TimeoutInMicroSeconds - add argument and description to function comment
1698 @todo EFI_ABORTED - add return value to function comment
1699 @todo EFI_TIMEOUT - add return value to function comment
1700 @todo EFI_SUCCESS - add return value to function comment
1704 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1705 UINT64 TimeoutInMicroSeconds
1709 UINT8 AltStatusRegister
;
1712 if (TimeoutInMicroSeconds
== 0) {
1715 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1720 // read Status Register will clear interrupt
1722 AltStatusRegister
= ReadPortB (
1723 AtapiScsiPrivate
->PciIo
,
1724 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1729 if ((AltStatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1733 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
1735 ErrRegister
= ReadPortB (
1736 AtapiScsiPrivate
->PciIo
,
1737 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1739 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1750 // Loop infinitely if not meeting expected condition
1752 if (TimeoutInMicroSeconds
== 0) {
1767 Check whether BSY is clear in the Status Register.
1768 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1769 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1772 @todo function comment is missing 'Routine Description:'
1773 @todo function comment is missing 'Arguments:'
1774 @todo function comment is missing 'Returns:'
1775 @todo AtapiScsiPrivate - add argument and description to function comment
1776 @todo TimeoutInMicroSeconds - add argument and description to function comment
1777 @todo EFI_TIMEOUT - add return value to function comment
1778 @todo EFI_SUCCESS - add return value to function comment
1781 StatusWaitForBSYClear (
1782 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1783 UINT64 TimeoutInMicroSeconds
1787 UINT8 StatusRegister
;
1789 if (TimeoutInMicroSeconds
== 0) {
1792 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1797 StatusRegister
= ReadPortB (
1798 AtapiScsiPrivate
->PciIo
,
1799 AtapiScsiPrivate
->IoPort
->Reg
.Status
1801 if ((StatusRegister
& BSY
) == 0x00) {
1811 // Loop infinitely if not meeting expected condition
1813 if (TimeoutInMicroSeconds
== 0) {
1828 Check whether BSY is clear in the Alternate Status Register.
1829 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1830 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1833 @todo function comment is missing 'Routine Description:'
1834 @todo function comment is missing 'Arguments:'
1835 @todo function comment is missing 'Returns:'
1836 @todo AtapiScsiPrivate - add argument and description to function comment
1837 @todo TimeoutInMicroSeconds - add argument and description to function comment
1838 @todo EFI_TIMEOUT - add return value to function comment
1839 @todo EFI_SUCCESS - add return value to function comment
1842 AltStatusWaitForBSYClear (
1843 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1844 UINT64 TimeoutInMicroSeconds
1848 UINT8 AltStatusRegister
;
1850 if (TimeoutInMicroSeconds
== 0) {
1853 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1858 AltStatusRegister
= ReadPortB (
1859 AtapiScsiPrivate
->PciIo
,
1860 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1862 if ((AltStatusRegister
& BSY
) == 0x00) {
1871 // Loop infinitely if not meeting expected condition
1873 if (TimeoutInMicroSeconds
== 0) {
1888 Check whether DRDY is ready in the Status Register.
1889 (BSY must also be cleared)
1890 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1891 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1894 @todo function comment is missing 'Routine Description:'
1895 @todo function comment is missing 'Arguments:'
1896 @todo function comment is missing 'Returns:'
1897 @todo AtapiScsiPrivate - add argument and description to function comment
1898 @todo TimeoutInMicroSeconds - add argument and description to function comment
1899 @todo EFI_ABORTED - add return value to function comment
1900 @todo EFI_TIMEOUT - add return value to function comment
1901 @todo EFI_SUCCESS - add return value to function comment
1905 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1906 UINT64 TimeoutInMicroSeconds
1910 UINT8 StatusRegister
;
1913 if (TimeoutInMicroSeconds
== 0) {
1916 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1920 StatusRegister
= ReadPortB (
1921 AtapiScsiPrivate
->PciIo
,
1922 AtapiScsiPrivate
->IoPort
->Reg
.Status
1925 // BSY == 0 , DRDY == 1
1927 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
1931 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1933 ErrRegister
= ReadPortB (
1934 AtapiScsiPrivate
->PciIo
,
1935 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1937 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1947 // Loop infinitely if not meeting expected condition
1949 if (TimeoutInMicroSeconds
== 0) {
1964 Check whether DRDY is ready in the Alternate Status Register.
1965 (BSY must also be cleared)
1966 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1967 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1970 @todo function comment is missing 'Routine Description:'
1971 @todo function comment is missing 'Arguments:'
1972 @todo function comment is missing 'Returns:'
1973 @todo AtapiScsiPrivate - add argument and description to function comment
1974 @todo TimeoutInMicroSeconds - add argument and description to function comment
1975 @todo EFI_ABORTED - add return value to function comment
1976 @todo EFI_TIMEOUT - add return value to function comment
1977 @todo EFI_SUCCESS - add return value to function comment
1980 AltStatusDRDYReady (
1981 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1982 UINT64 TimeoutInMicroSeconds
1986 UINT8 AltStatusRegister
;
1989 if (TimeoutInMicroSeconds
== 0) {
1992 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1996 AltStatusRegister
= ReadPortB (
1997 AtapiScsiPrivate
->PciIo
,
1998 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2001 // BSY == 0 , DRDY == 1
2003 if ((AltStatusRegister
& (DRDY
| BSY
)) == DRDY
) {
2007 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2009 ErrRegister
= ReadPortB (
2010 AtapiScsiPrivate
->PciIo
,
2011 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2013 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2023 // Loop infinitely if not meeting expected condition
2025 if (TimeoutInMicroSeconds
== 0) {
2040 Check Error Register for Error Information.
2042 @todo function comment is missing 'Routine Description:'
2043 @todo function comment is missing 'Arguments:'
2044 @todo function comment is missing 'Returns:'
2045 @todo AtapiScsiPrivate - add argument and description to function comment
2046 @todo EFI_SUCCESS - add return value to function comment
2047 @todo EFI_DEVICE_ERROR - add return value to function comment
2050 AtapiPassThruCheckErrorStatus (
2051 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
2054 UINT8 StatusRegister
;
2055 UINT8 ErrorRegister
;
2057 StatusRegister
= ReadPortB (
2058 AtapiScsiPrivate
->PciIo
,
2059 AtapiScsiPrivate
->IoPort
->Reg
.Status
2062 DEBUG_CODE_BEGIN ();
2064 if (StatusRegister
& DWF
) {
2067 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
2072 if (StatusRegister
& CORR
) {
2075 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
2080 if (StatusRegister
& ERR
) {
2081 ErrorRegister
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg1
.Error
);
2084 if (ErrorRegister
& BBK_ERR
) {
2087 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
2092 if (ErrorRegister
& UNC_ERR
) {
2095 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
2100 if (ErrorRegister
& MC_ERR
) {
2103 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
2108 if (ErrorRegister
& ABRT_ERR
) {
2111 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
2116 if (ErrorRegister
& TK0NF_ERR
) {
2119 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
2124 if (ErrorRegister
& AMNF_ERR
) {
2127 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
2135 if ((StatusRegister
& (ERR
| DWF
| CORR
)) == 0) {
2140 return EFI_DEVICE_ERROR
;
2144 The user Entry Point for module AtapiPassThru. The user code starts with this function.
2146 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2147 @param[in] SystemTable A pointer to the EFI System Table.
2149 @retval EFI_SUCCESS The entry point is executed successfully.
2150 @retval other Some error occurs when executing this entry point.
2155 InitializeAtapiPassThru(
2156 IN EFI_HANDLE ImageHandle
,
2157 IN EFI_SYSTEM_TABLE
*SystemTable
2163 // Install driver model protocol(s).
2165 Status
= EfiLibInstallAllDriverProtocols (
2168 &gAtapiScsiPassThruDriverBinding
,
2170 &gAtapiScsiPassThruComponentName
,
2174 ASSERT_EFI_ERROR (Status
);