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"
17 AtapiScsiPassThruDriverBindingSupported (
18 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
19 IN EFI_HANDLE Controller
,
20 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
25 AtapiScsiPassThruDriverBindingStart (
26 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
27 IN EFI_HANDLE Controller
,
28 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
33 AtapiScsiPassThruDriverBindingStop (
34 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
35 IN EFI_HANDLE Controller
,
36 IN UINTN NumberOfChildren
,
37 IN EFI_HANDLE
*ChildHandleBuffer
41 /// IDE registers' fixed address
43 static IDE_BASE_REGISTERS gAtapiIoPortRegisters
[2] = {
44 { 0x1f0, { 0x1f1 }, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, { 0x1f7 }, { 0x3f6 }, 0x3f7, 0 },
45 { 0x170, { 0x171 }, 0x172, 0x173, 0x174, 0x175, 0x176, { 0x177 }, { 0x376 }, 0x377, 0 }
48 static SCSI_COMMAND_SET gEndTable
= { 0xff, 0xff };
51 /// This table contains all the supported ATAPI commands.
53 static SCSI_COMMAND_SET gSupportedATAPICommands
[] = {
54 { OP_INQUIRY
, DataIn
},
55 { OP_LOAD_UNLOAD_CD
, NoData
},
56 { OP_MECHANISM_STATUS
, DataIn
},
57 { OP_MODE_SELECT_10
, DataOut
},
58 { OP_MODE_SENSE_10
, DataIn
},
59 { OP_PAUSE_RESUME
, NoData
},
60 { OP_PLAY_AUDIO_10
, DataIn
},
61 { OP_PLAY_AUDIO_MSF
, DataIn
},
62 { OP_PLAY_CD
, DataIn
},
63 { OP_PLAY_CD_MSF
, DataIn
},
64 { OP_PREVENT_ALLOW_MEDIUM_REMOVAL
,NoData
},
65 { OP_READ_10
, DataIn
},
66 { OP_READ_12
, DataIn
},
67 { OP_READ_CAPACITY
, DataIn
},
68 { OP_READ_CD
, DataIn
},
69 { OP_READ_CD_MSF
, DataIn
},
70 { OP_READ_HEADER
, DataIn
},
71 { OP_READ_SUB_CHANNEL
, DataIn
},
72 { OP_READ_TOC
, DataIn
},
73 { OP_REQUEST_SENSE
, DataIn
},
75 { OP_SEEK_10
, NoData
},
76 { OP_SET_CD_SPEED
, DataOut
},
77 { OP_STOPPLAY_SCAN
, NoData
},
78 { OP_START_STOP_UNIT
, NoData
},
79 { OP_TEST_UNIT_READY
, NoData
},
80 { OP_FORMAT_UNIT
, DataOut
},
81 { OP_READ_FORMAT_CAPACITIES
, DataIn
},
82 { OP_VERIFY
, DataOut
},
83 { OP_WRITE_10
, DataOut
},
84 { OP_WRITE_12
, DataOut
},
85 { OP_WRITE_AND_VERIFY
, DataOut
},
89 static CHAR16
*gControllerNameString
= (CHAR16
*) L
"ATAPI Controller";
90 static CHAR16
*gAtapiChannelString
= (CHAR16
*) L
"ATAPI Channel";
92 EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding
= {
93 AtapiScsiPassThruDriverBindingSupported
,
94 AtapiScsiPassThruDriverBindingStart
,
95 AtapiScsiPassThruDriverBindingStop
,
104 (Standard DriverBinding Protocol Supported() function)
108 @todo This - add argument and description to function comment
109 @todo Controller - add argument and description to function comment
110 @todo RemainingDevicePath - add argument and description to function comment
111 @todo EFI_UNSUPPORTED - add return value to function comment
115 AtapiScsiPassThruDriverBindingSupported (
116 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
117 IN EFI_HANDLE Controller
,
118 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
122 EFI_PCI_IO_PROTOCOL
*PciIo
;
126 // Open the IO Abstraction(s) needed to perform the supported test
128 Status
= gBS
->OpenProtocol (
130 &gEfiPciIoProtocolGuid
,
132 This
->DriverBindingHandle
,
134 EFI_OPEN_PROTOCOL_BY_DRIVER
136 if (EFI_ERROR (Status
)) {
140 // Use the PCI I/O Protocol to see if Controller is a IDE Controller that
141 // can be managed by this driver. Read the PCI Configuration Header
144 Status
= PciIo
->Pci
.Read (
148 sizeof (Pci
) / sizeof (UINT32
),
151 if (EFI_ERROR (Status
)) {
154 &gEfiPciIoProtocolGuid
,
155 This
->DriverBindingHandle
,
158 return EFI_UNSUPPORTED
;
161 if (Pci
.Hdr
.ClassCode
[2] != PCI_CLASS_MASS_STORAGE
|| Pci
.Hdr
.ClassCode
[1] != PCI_CLASS_IDE
) {
163 Status
= EFI_UNSUPPORTED
;
168 &gEfiPciIoProtocolGuid
,
169 This
->DriverBindingHandle
,
177 Create handles for IDE channels specified by RemainingDevicePath.
178 Install SCSI Pass Thru Protocol onto each created handle.
180 (Standard DriverBinding Protocol Start() function)
184 @todo This - add argument and description to function comment
185 @todo Controller - add argument and description to function comment
186 @todo RemainingDevicePath - add argument and description to function comment
190 AtapiScsiPassThruDriverBindingStart (
191 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
192 IN EFI_HANDLE Controller
,
193 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
197 EFI_PCI_IO_PROTOCOL
*PciIo
;
200 Status
= gBS
->OpenProtocol (
202 &gEfiPciIoProtocolGuid
,
204 This
->DriverBindingHandle
,
206 EFI_OPEN_PROTOCOL_BY_DRIVER
208 if (EFI_ERROR (Status
)) {
212 Status
= PciIo
->Attributes (
214 EfiPciIoAttributeOperationEnable
,
215 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
,
218 if (EFI_ERROR (Status
)) {
223 // Create SCSI Pass Thru instance for the IDE channel.
225 Status
= RegisterAtapiScsiPassThru (This
, Controller
, PciIo
);
228 if (EFI_ERROR (Status
)) {
232 EfiPciIoAttributeOperationDisable
,
233 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
,
240 &gEfiPciIoProtocolGuid
,
241 This
->DriverBindingHandle
,
252 (Standard DriverBinding Protocol Stop() function)
256 @todo This - add argument and description to function comment
257 @todo Controller - add argument and description to function comment
258 @todo NumberOfChildren - add argument and description to function comment
259 @todo ChildHandleBuffer - add argument and description to function comment
260 @todo EFI_SUCCESS - add return value to function comment
264 AtapiScsiPassThruDriverBindingStop (
265 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
266 IN EFI_HANDLE Controller
,
267 IN UINTN NumberOfChildren
,
268 IN EFI_HANDLE
*ChildHandleBuffer
272 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
273 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
275 Status
= gBS
->OpenProtocol (
277 &gEfiScsiPassThruProtocolGuid
,
278 (VOID
**) &ScsiPassThru
,
279 This
->DriverBindingHandle
,
281 EFI_OPEN_PROTOCOL_GET_PROTOCOL
283 if (EFI_ERROR (Status
)) {
287 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru
);
289 Status
= gBS
->UninstallProtocolInterface (
291 &gEfiScsiPassThruProtocolGuid
,
292 &AtapiScsiPrivate
->ScsiPassThru
294 if (EFI_ERROR (Status
)) {
298 // Release Pci Io protocol on the controller handle.
300 AtapiScsiPrivate
->PciIo
->Attributes (
301 AtapiScsiPrivate
->PciIo
,
302 EfiPciIoAttributeOperationDisable
,
303 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
,
309 &gEfiPciIoProtocolGuid
,
310 This
->DriverBindingHandle
,
314 gBS
->FreePool (AtapiScsiPrivate
);
320 Attaches SCSI Pass Thru Protocol for specified IDE channel.
322 @param Controller: Parent device handle to the IDE channel.
323 @param PciIo: PCI I/O protocol attached on the "Controller".
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
340 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
343 AtapiScsiPrivate
= AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV
));
344 if (AtapiScsiPrivate
== NULL
) {
345 return EFI_OUT_OF_RESOURCES
;
348 Attributes
= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO
| EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO
| EFI_PCI_DEVICE_ENABLE
;
349 CopyMem (AtapiScsiPrivate
->ChannelName
, gAtapiChannelString
, sizeof (gAtapiChannelString
));
354 PciIo
->Attributes (PciIo
, EfiPciIoAttributeOperationSet
, Attributes
, NULL
);
356 AtapiScsiPrivate
->Signature
= ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE
;
357 AtapiScsiPrivate
->Handle
= Controller
;
360 // will reset the IoPort inside each API function.
362 AtapiScsiPrivate
->IoPort
= gAtapiIoPortRegisters
;
363 AtapiScsiPrivate
->PciIo
= PciIo
;
366 // initialize SCSI Pass Thru Protocol interface
368 AtapiScsiPrivate
->ScsiPassThru
.Mode
= &AtapiScsiPrivate
->ScsiPassThruMode
;
369 AtapiScsiPrivate
->ScsiPassThru
.PassThru
= AtapiScsiPassThruFunction
;
370 AtapiScsiPrivate
->ScsiPassThru
.GetNextDevice
= AtapiScsiPassThruGetNextDevice
;
371 AtapiScsiPrivate
->ScsiPassThru
.BuildDevicePath
= AtapiScsiPassThruBuildDevicePath
;
372 AtapiScsiPrivate
->ScsiPassThru
.GetTargetLun
= AtapiScsiPassThruGetTargetLun
;
373 AtapiScsiPrivate
->ScsiPassThru
.ResetChannel
= AtapiScsiPassThruResetChannel
;
374 AtapiScsiPrivate
->ScsiPassThru
.ResetTarget
= AtapiScsiPassThruResetTarget
;
379 CopyMem (AtapiScsiPrivate
->ControllerName
, gControllerNameString
, sizeof (gControllerNameString
));
381 AtapiScsiPrivate
->ScsiPassThruMode
.ControllerName
= AtapiScsiPrivate
->ControllerName
;
382 AtapiScsiPrivate
->ScsiPassThruMode
.ChannelName
= AtapiScsiPrivate
->ChannelName
;
383 AtapiScsiPrivate
->ScsiPassThruMode
.AdapterId
= 4;
385 // non-RAID SCSI controllers should set both physical and logical attributes
387 AtapiScsiPrivate
->ScsiPassThruMode
.Attributes
= EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
|
388 EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
;
389 AtapiScsiPrivate
->ScsiPassThruMode
.IoAlign
= 0;
392 // Initialize the LatestTargetId to 0xFFFFFFFF (for the GetNextDevice() call).
394 AtapiScsiPrivate
->LatestTargetId
= 0xFFFFFFFF;
395 AtapiScsiPrivate
->LatestLun
= 0;
397 Status
= gBS
->InstallProtocolInterface (
399 &gEfiScsiPassThruProtocolGuid
,
400 EFI_NATIVE_INTERFACE
,
401 &AtapiScsiPrivate
->ScsiPassThru
407 Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
409 @param This The EFI_SCSI_PASS_THRU_PROTOCOL instance.
410 @param Target The Target ID of the ATAPI device to send the SCSI
411 Request Packet. To ATAPI devices attached on an IDE
412 Channel, Target ID 0 indicates Master device;Target
413 ID 1 indicates Slave device.
414 @param Lun The LUN of the ATAPI device to send the SCSI Request
415 Packet. To the ATAPI device, Lun is always 0.
416 @param Packet The SCSI Request Packet to send to the ATAPI device
417 specified by Target and Lun.
418 @param Event If non-blocking I/O is not supported then Event is ignored,
419 and blocking I/O is performed.<br>
420 If Event is NULL, then blocking I/O is performed.<br>
421 If Event is not NULL and non blocking I/O is supported,
422 then non-blocking I/O is performed, and Event will be signaled
423 when the SCSI Request Packet completes.
425 @todo This - add argument and description to function comment
426 @todo EFI_INVALID_PARAMETER - add return value to function comment
427 @todo EFI_SUCCESS - add return value to function comment
431 AtapiScsiPassThruFunction (
432 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
435 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
436 IN EFI_EVENT Event OPTIONAL
439 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
442 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
445 // Target is not allowed beyond MAX_TARGET_ID
447 if (Target
> MAX_TARGET_ID
) {
448 return EFI_INVALID_PARAMETER
;
452 // check the data fields in Packet parameter.
454 Status
= CheckSCSIRequestPacket (Packet
);
455 if (EFI_ERROR (Status
)) {
460 // If Request Packet targets at the IDE channel itself,
463 if (Target
== This
->Mode
->AdapterId
) {
464 Packet
->TransferLength
= 0;
469 // According to Target ID, reset the Atapi I/O Register mapping
470 // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],
471 // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]
473 if ((Target
/ 2) == 0) {
474 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[0];
476 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[1];
480 // the ATAPI SCSI interface does not support non-blocking I/O
481 // ignore the Event parameter
483 // Performs blocking I/O.
485 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, Packet
);
490 Used to retrieve the list of legal Target IDs for SCSI devices
493 @param This Protocol instance pointer.
494 @param Target On input, a pointer to the Target ID of a SCSI
495 device present on the SCSI channel. On output,
496 a pointer to the Target ID of the next SCSI device
497 present on a SCSI channel. An input value of
498 0xFFFFFFFF retrieves the Target ID of the first
499 SCSI device present on a SCSI channel.
500 @param Lun On input, a pointer to the LUN of a SCSI device
501 present on the SCSI channel. On output, a pointer
502 to the LUN of the next SCSI device present on
505 @retval EFI_SUCCESS The Target ID and Lun of the next SCSI device
506 on the SCSI channel was returned in Target and Lun.
507 @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
508 @retval EFI_INVALID_PARAMETER Target is not 0xFFFFFFFF,and Target and Lun were not
509 returned on a previous call to GetNextDevice().
514 AtapiScsiPassThruGetNextDevice (
515 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
516 IN OUT UINT32
*Target
,
520 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
523 // Retrieve Device Private Data Structure.
525 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
528 // Check whether Target is valid.
530 if (Target
== NULL
|| Lun
== NULL
) {
531 return EFI_INVALID_PARAMETER
;
534 if ((*Target
!= 0xFFFFFFFF) &&
535 ((*Target
!= AtapiScsiPrivate
->LatestTargetId
) ||
536 (*Lun
!= AtapiScsiPrivate
->LatestLun
))) {
537 return EFI_INVALID_PARAMETER
;
540 if (*Target
== MAX_TARGET_ID
) {
541 return EFI_NOT_FOUND
;
544 if (*Target
== 0xFFFFFFFF) {
547 *Target
= AtapiScsiPrivate
->LatestTargetId
+ 1;
553 // Update the LatestTargetId.
555 AtapiScsiPrivate
->LatestTargetId
= *Target
;
556 AtapiScsiPrivate
->LatestLun
= *Lun
;
563 Used to allocate and build a device path node for a SCSI device
564 on a SCSI channel. Would not build device path for a SCSI Host Controller.
566 @param This Protocol instance pointer.
567 @param Target The Target ID of the SCSI device for which
568 a device path node is to be allocated and built.
569 @param Lun The LUN of the SCSI device for which a device
570 path node is to be allocated and built.
571 @param DevicePath A pointer to a single device path node that
572 describes the SCSI device specified by
573 Target and Lun. This function is responsible
574 for allocating the buffer DevicePath with the boot
575 service AllocatePool(). It is the caller's
576 responsibility to free DevicePath when the caller
577 is finished with DevicePath.
579 @retval EFI_SUCCESS The device path node that describes the SCSI device
580 specified by Target and Lun was allocated and
581 returned in DevicePath.
582 @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does
583 not exist on the SCSI channel.
584 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
585 @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate
591 AtapiScsiPassThruBuildDevicePath (
592 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
595 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
598 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
602 // Retrieve Device Private Data Structure.
604 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
607 // Validate parameters passed in.
610 if (DevicePath
== NULL
) {
611 return EFI_INVALID_PARAMETER
;
615 // can not build device path for the SCSI Host Controller.
617 if ((Target
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
618 return EFI_NOT_FOUND
;
621 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
623 return EFI_OUT_OF_RESOURCES
;
626 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
627 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
628 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
630 Node
->Atapi
.PrimarySecondary
= (UINT8
) (Target
/ 2);
631 Node
->Atapi
.SlaveMaster
= (UINT8
) (Target
% 2);
632 Node
->Atapi
.Lun
= (UINT16
) Lun
;
634 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
640 Used to translate a device path node to a Target ID and LUN.
642 @param This Protocol instance pointer.
643 @param DevicePath A pointer to the device path node that
644 describes a SCSI device on the SCSI channel.
645 @param Target A pointer to the Target ID of a SCSI device
647 @param Lun A pointer to the LUN of a SCSI device on
650 @retval EFI_SUCCESS DevicePath was successfully translated to a
651 Target ID and LUN, and they were returned
653 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
654 @retval EFI_INVALID_PARAMETER Target is NULL.
655 @retval EFI_INVALID_PARAMETER Lun is NULL.
656 @retval EFI_UNSUPPORTED This driver does not support the device path
657 node type in DevicePath.
658 @retval EFI_NOT_FOUND A valid translation from DevicePath to a
659 Target ID and LUN does not exist.
664 AtapiScsiPassThruGetTargetLun (
665 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
666 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
674 // Validate parameters passed in.
676 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
677 return EFI_INVALID_PARAMETER
;
681 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
683 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
684 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
685 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
686 return EFI_UNSUPPORTED
;
689 Node
= (EFI_DEV_PATH
*) DevicePath
;
691 *Target
= Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
;
692 *Lun
= Node
->Atapi
.Lun
;
694 if (*Target
> (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
695 return EFI_NOT_FOUND
;
702 Resets a SCSI channel.This operation resets all the
703 SCSI devices connected to the SCSI channel.
705 @param This Protocol instance pointer.
707 @retval EFI_SUCCESS The SCSI channel was reset.
708 @retval EFI_UNSUPPORTED The SCSI channel does not support
709 a channel reset operation.
710 @retval EFI_DEVICE_ERROR A device error occurred while
711 attempting to reset the SCSI channel.
712 @retval EFI_TIMEOUT A timeout occurred while attempting
713 to reset the SCSI channel.
718 AtapiScsiPassThruResetChannel (
719 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
722 UINT8 DeviceControlValue
;
723 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
726 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
729 // Reset both Primary channel and Secondary channel.
730 // so, the IoPort pointer must point to the right I/O Register group
732 for (Index
= 0; Index
< 2; Index
++) {
736 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[Index
];
738 DeviceControlValue
= 0;
740 // set SRST bit to initiate soft reset
742 DeviceControlValue
|= SRST
;
746 DeviceControlValue
|= bit (1);
748 AtapiScsiPrivate
->PciIo
,
749 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
762 DeviceControlValue
&= 0xfb;
764 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
767 // slave device needs at most 31s to clear BSY
769 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000) == EFI_TIMEOUT
) {
770 return EFI_DEVICE_ERROR
;
778 Resets a SCSI device that is connected to a SCSI channel.
780 @param This Protocol instance pointer.
781 @param Target The Target ID of the SCSI device to reset.
782 @param Lun The LUN of the SCSI device to reset.
784 @retval EFI_SUCCESS The SCSI device specified by Target and
786 @retval EFI_UNSUPPORTED The SCSI channel does not support a target
788 @retval EFI_INVALID_PARAMETER Target or Lun are invalid.
789 @retval EFI_DEVICE_ERROR A device error occurred while attempting
790 to reset the SCSI device specified by Target
792 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
793 the SCSI device specified by Target and Lun.
798 AtapiScsiPassThruResetTarget (
799 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
804 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
808 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
810 if (Target
> MAX_TARGET_ID
) {
811 return EFI_INVALID_PARAMETER
;
814 // Directly return EFI_SUCCESS if want to reset the host controller
816 if (Target
== This
->Mode
->AdapterId
) {
821 // According to Target ID, reset the Atapi I/O Register mapping
822 // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],
823 // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]
825 if ((Target
/ 2) == 0) {
826 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[0];
828 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[1];
832 // for ATAPI device, no need to wait DRDY ready after device selecting.
834 // bit7 and bit5 are both set to 1 for backward compatibility
836 DeviceSelect
= (UINT8
) (((bit (7) | bit (5)) | (Target
<< 4)));
837 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
839 Command
= ATAPI_SOFT_RESET_CMD
;
840 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
843 // BSY clear is the only status return to the host by the device
844 // when reset is complete.
845 // slave device needs at most 31s to clear BSY
847 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000))) {
848 return EFI_DEVICE_ERROR
;
852 // stall 5 seconds to make the device status stable
854 gBS
->Stall (5000000);
861 Checks the parameters in the SCSI Request Packet to make sure
862 they are valid for a SCSI Pass Thru request.
864 @todo function comment is missing 'Routine Description:'
865 @todo function comment is missing 'Arguments:'
866 @todo function comment is missing 'Returns:'
867 @todo Packet - add argument and description to function comment
868 @todo EFI_INVALID_PARAMETER - add return value to function comment
869 @todo EFI_INVALID_PARAMETER - add return value to function comment
870 @todo EFI_INVALID_PARAMETER - add return value to function comment
871 @todo EFI_UNSUPPORTED - add return value to function comment
872 @todo EFI_SUCCESS - add return value to function comment
875 CheckSCSIRequestPacket (
876 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
879 if (Packet
== NULL
) {
880 return EFI_INVALID_PARAMETER
;
883 if (!ValidCdbLength (Packet
->CdbLength
)) {
884 return EFI_INVALID_PARAMETER
;
887 if (Packet
->Cdb
== NULL
) {
888 return EFI_INVALID_PARAMETER
;
892 // Checks whether the request command is supported.
894 if (!IsCommandValid (Packet
)) {
895 return EFI_UNSUPPORTED
;
902 Checks the requested SCSI command:
903 Is it supported by this driver?
904 Is the Data transfer direction reasonable?
906 @todo function comment is missing 'Routine Description:'
907 @todo function comment is missing 'Arguments:'
908 @todo function comment is missing 'Returns:'
909 @todo Packet - add argument and description to function comment
913 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
919 OpCode
= (UINT8
*) (Packet
->Cdb
);
921 for (Index
= 0; CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)); Index
++) {
923 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
925 // Check whether the requested Command is supported by this driver
927 if (Packet
->DataDirection
== DataIn
) {
929 // Check whether the requested data direction conforms to
930 // what it should be.
932 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
937 if (Packet
->DataDirection
== DataOut
) {
939 // Check whether the requested data direction conforms to
940 // what it should be.
942 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
955 Performs blocking I/O request.
957 @param AtapiScsiPrivate Private data structure for the specified channel.
958 @param Target The Target ID of the ATAPI device to send the SCSI
959 Request Packet. To ATAPI devices attached on an IDE
960 Channel, Target ID 0 indicates Master device;Target
961 ID 1 indicates Slave device.
962 @param Packet The SCSI Request Packet to send to the ATAPI device
965 @todo AtapiScsiPrivate - add argument and description to function comment
968 SubmitBlockingIoCommand (
969 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
971 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
974 UINT8 PacketCommand
[12];
975 UINT64 TimeoutInMicroSeconds
;
976 EFI_STATUS PacketCommandStatus
;
979 // Fill ATAPI Command Packet according to CDB
981 ZeroMem (&PacketCommand
, 12);
982 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
985 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
987 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
990 // Submit ATAPI Command Packet
992 PacketCommandStatus
= AtapiPacketCommand (
997 &(Packet
->TransferLength
),
998 Packet
->DataDirection
,
999 TimeoutInMicroSeconds
1001 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
1002 Packet
->SenseDataLength
= 0;
1003 return PacketCommandStatus
;
1006 // Return SenseData if PacketCommandStatus matches
1007 // the following return codes.
1009 if ((PacketCommandStatus
== EFI_WARN_BUFFER_TOO_SMALL
) ||
1010 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
1011 (PacketCommandStatus
== EFI_TIMEOUT
)) {
1014 // avoid submit request sense command continuously.
1016 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
1017 Packet
->SenseDataLength
= 0;
1018 return PacketCommandStatus
;
1021 RequestSenseCommand (
1026 &Packet
->SenseDataLength
1030 return PacketCommandStatus
;
1036 @param AtapiScsiPrivate
1040 @param SenseDataLength
1042 @todo Add function description
1043 @todo AtapiScsiPrivate TODO: add argument description
1044 @todo Target TODO: add argument description
1045 @todo Timeout TODO: add argument description
1046 @todo SenseData TODO: add argument description
1047 @todo SenseDataLength TODO: add argument description
1048 @todo add return values
1051 RequestSenseCommand (
1052 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1056 UINT8
*SenseDataLength
1059 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet
;
1063 ZeroMem (&Packet
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1066 Cdb
[0] = OP_REQUEST_SENSE
;
1067 Cdb
[4] = (UINT8
) (*SenseDataLength
);
1069 Packet
.Timeout
= Timeout
;
1070 Packet
.DataBuffer
= SenseData
;
1071 Packet
.SenseData
= NULL
;
1073 Packet
.TransferLength
= *SenseDataLength
;
1074 Packet
.CdbLength
= 12;
1075 Packet
.DataDirection
= DataIn
;
1077 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, &Packet
);
1078 *SenseDataLength
= (UINT8
) (Packet
.TransferLength
);
1083 Submits ATAPI command packet to the specified ATAPI device.
1085 @param AtapiScsiPrivate: Private data structure for the specified channel.
1086 @param Target: The Target ID of the ATAPI device to send the SCSI
1087 Request Packet. To ATAPI devices attached on an IDE
1088 Channel, Target ID 0 indicates Master device;Target
1089 ID 1 indicates Slave device.
1090 @param PacketCommand: Points to the ATAPI command packet.
1091 @param Buffer: Points to the transferred data.
1092 @param ByteCount: When input,indicates the buffer size; when output,
1093 indicates the actually transferred data size.
1094 @param Direction: Indicates the data transfer direction.
1095 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1096 to use for the execution of this ATAPI command.
1097 A TimeoutInMicroSeconds value of 0 means that
1098 this function will wait indefinitely for the ATAPI
1101 If TimeoutInMicroSeconds is greater than zero, then
1102 this function will return EFI_TIMEOUT if the time
1103 required to execute the ATAPI command is greater
1104 than TimeoutInMicroSeconds.
1107 @todo AtapiScsiPrivate - add argument and description to function comment
1108 @todo PacketCommand - add argument and description to function comment
1109 @todo Buffer - add argument and description to function comment
1110 @todo ByteCount - add argument and description to function comment
1111 @todo Direction - add argument and description to function comment
1114 AtapiPacketCommand (
1115 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1117 UINT8
*PacketCommand
,
1120 DATA_DIRECTION Direction
,
1121 UINT64 TimeoutInMicroSeconds
1125 UINT16
*CommandIndex
;
1130 // Set all the command parameters by fill related registers.
1131 // Before write to all the following registers, BSY and DRQ must be 0.
1133 Status
= StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1134 if (EFI_ERROR (Status
)) {
1135 if (Status
== EFI_ABORTED
) {
1136 Status
= EFI_DEVICE_ERROR
;
1143 // Select device via Device/Head Register.
1144 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
1147 AtapiScsiPrivate
->PciIo
,
1148 AtapiScsiPrivate
->IoPort
->Head
,
1149 (UINT8
) ((Target
<< 4) | DEFAULT_CMD
) // DEFAULT_CMD: 0xa0 (1010,0000)
1153 // No OVL; No DMA (by setting feature register)
1156 AtapiScsiPrivate
->PciIo
,
1157 AtapiScsiPrivate
->IoPort
->Reg1
.Feature
,
1162 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
1163 // determine how much data should be transfered.
1166 AtapiScsiPrivate
->PciIo
,
1167 AtapiScsiPrivate
->IoPort
->CylinderLsb
,
1168 (UINT8
) (MAX_ATAPI_BYTE_COUNT
& 0x00ff)
1171 AtapiScsiPrivate
->PciIo
,
1172 AtapiScsiPrivate
->IoPort
->CylinderMsb
,
1173 (UINT8
) (MAX_ATAPI_BYTE_COUNT
>> 8)
1177 // DEFAULT_CTL:0x0a (0000,1010)
1178 // Disable interrupt
1181 AtapiScsiPrivate
->PciIo
,
1182 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
1187 // Send Packet command to inform device
1188 // that the following data bytes are command packet.
1191 AtapiScsiPrivate
->PciIo
,
1192 AtapiScsiPrivate
->IoPort
->Reg
.Command
,
1197 // Before data transfer, BSY should be 0 and DRQ should be 1.
1198 // if they are not in specified time frame,
1199 // retrieve Sense Key from Error Register before return.
1201 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1202 if (EFI_ERROR (Status
)) {
1203 if (Status
== EFI_ABORTED
) {
1204 Status
= EFI_DEVICE_ERROR
;
1212 // Send out command packet
1214 CommandIndex
= (UINT16
*) PacketCommand
;
1215 for (Count
= 0; Count
< 6; Count
++, CommandIndex
++) {
1216 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *CommandIndex
);
1220 // call AtapiPassThruPioReadWriteData() function to get
1221 // requested transfer data form device.
1223 return AtapiPassThruPioReadWriteData (
1228 TimeoutInMicroSeconds
1233 Performs data transfer between ATAPI device and host after the
1234 ATAPI command packet is sent.
1236 @param AtapiScsiPrivate: Private data structure for the specified channel.
1237 @param Buffer: Points to the transferred data.
1238 @param ByteCount: When input,indicates the buffer size; when output,
1239 indicates the actually transferred data size.
1240 @param Direction: Indicates the data transfer direction.
1241 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1242 to use for the execution of this ATAPI command.
1243 A TimeoutInMicroSeconds value of 0 means that
1244 this function will wait indefinitely for the ATAPI
1247 If TimeoutInMicroSeconds is greater than zero, then
1248 this function will return EFI_TIMEOUT if the time
1249 required to execute the ATAPI command is greater
1250 than TimeoutInMicroSeconds.
1253 @todo AtapiScsiPrivate - add argument and description to function comment
1254 @todo Buffer - add argument and description to function comment
1255 @todo ByteCount - add argument and description to function comment
1256 @todo Direction - add argument and description to function comment
1257 @todo EFI_DEVICE_ERROR - add return value to function comment
1258 @todo EFI_DEVICE_ERROR - add return value to function comment
1259 @todo EFI_WARN_BUFFER_TOO_SMALL - add return value to function comment
1262 AtapiPassThruPioReadWriteData (
1263 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1266 DATA_DIRECTION Direction
,
1267 UINT64 TimeoutInMicroSeconds
1271 UINT32 RequiredWordCount
;
1272 UINT32 ActualWordCount
;
1278 Status
= EFI_SUCCESS
;
1281 // Non Data transfer request is also supported.
1283 if (*ByteCount
== 0 || Buffer
== NULL
) {
1285 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
))) {
1286 return EFI_DEVICE_ERROR
;
1291 RequiredWordCount
= *ByteCount
/ 2;
1294 // ActuralWordCount means the word count of data really transfered.
1296 ActualWordCount
= 0;
1298 while (ActualWordCount
< RequiredWordCount
) {
1300 // before each data transfer stream, the host should poll DRQ bit ready,
1301 // which indicates device's ready for data transfer .
1303 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1304 if (EFI_ERROR (Status
)) {
1305 *ByteCount
= ActualWordCount
* 2;
1307 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
1309 if (ActualWordCount
== 0) {
1310 return EFI_DEVICE_ERROR
;
1313 // ActualWordCount > 0
1315 if (ActualWordCount
< RequiredWordCount
) {
1316 return EFI_WARN_BUFFER_TOO_SMALL
;
1320 // get current data transfer size from Cylinder Registers.
1324 (ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderMsb
) << 8) |
1325 ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderLsb
)
1330 // perform a series data In/Out.
1332 for (Index
= 0; (Index
< WordCount
) && (ActualWordCount
< RequiredWordCount
); Index
++, ActualWordCount
++) {
1334 if (Direction
== DataIn
) {
1336 *ptrBuffer
= ReadPortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
);
1339 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *ptrBuffer
);
1347 // After data transfer is completed, normally, DRQ bit should clear.
1349 StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1352 // read status register to check whether error happens.
1354 Status
= AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
1356 *ByteCount
= ActualWordCount
* 2;
1363 Read one byte from a specified I/O port.
1365 @todo function comment is missing 'Routine Description:'
1366 @todo function comment is missing 'Arguments:'
1367 @todo function comment is missing 'Returns:'
1368 @todo PciIo - add argument and description to function comment
1369 @todo Port - add argument and description to function comment
1373 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1383 EFI_PCI_IO_PASS_THROUGH_BAR
,
1393 Read one word from a specified I/O port.
1395 @todo function comment is missing 'Routine Description:'
1396 @todo function comment is missing 'Arguments:'
1397 @todo function comment is missing 'Returns:'
1398 @todo PciIo - add argument and description to function comment
1399 @todo Port - add argument and description to function comment
1403 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1412 EfiPciIoWidthUint16
,
1413 EFI_PCI_IO_PASS_THROUGH_BAR
,
1423 Write one byte to a specified I/O port.
1425 @todo function comment is missing 'Routine Description:'
1426 @todo function comment is missing 'Arguments:'
1427 @todo function comment is missing 'Returns:'
1428 @todo PciIo - add argument and description to function comment
1429 @todo Port - add argument and description to function comment
1430 @todo Data - add argument and description to function comment
1434 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1443 EFI_PCI_IO_PASS_THROUGH_BAR
,
1453 Write one word to a specified I/O port.
1455 @todo function comment is missing 'Routine Description:'
1456 @todo function comment is missing 'Arguments:'
1457 @todo function comment is missing 'Returns:'
1458 @todo PciIo - add argument and description to function comment
1459 @todo Port - add argument and description to function comment
1460 @todo Data - add argument and description to function comment
1464 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1472 EfiPciIoWidthUint16
,
1473 EFI_PCI_IO_PASS_THROUGH_BAR
,
1481 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
1482 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1483 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1486 @todo function comment is missing 'Routine Description:'
1487 @todo function comment is missing 'Arguments:'
1488 @todo function comment is missing 'Returns:'
1489 @todo AtapiScsiPrivate - add argument and description to function comment
1490 @todo TimeoutInMicroSeconds - add argument and description to function comment
1491 @todo EFI_ABORTED - add return value to function comment
1492 @todo EFI_TIMEOUT - add return value to function comment
1493 @todo EFI_SUCCESS - add return value to function comment
1497 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1498 UINT64 TimeoutInMicroSeconds
1502 UINT8 StatusRegister
;
1505 if (TimeoutInMicroSeconds
== 0) {
1508 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1513 StatusRegister
= ReadPortB (
1514 AtapiScsiPrivate
->PciIo
,
1515 AtapiScsiPrivate
->IoPort
->Reg
.Status
1519 // wait for BSY == 0 and DRQ == 0
1521 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
1525 // check whether the command is aborted by the device
1527 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1529 ErrRegister
= ReadPortB (
1530 AtapiScsiPrivate
->PciIo
,
1531 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1533 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1544 // Loop infinitely if not meeting expected condition
1546 if (TimeoutInMicroSeconds
== 0) {
1561 Check whether DRQ is clear in the Alternate Status Register.
1562 (BSY must also be cleared).
1563 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1564 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1567 @todo function comment is missing 'Routine Description:'
1568 @todo function comment is missing 'Arguments:'
1569 @todo function comment is missing 'Returns:'
1570 @todo AtapiScsiPrivate - add argument and description to function comment
1571 @todo TimeoutInMicroSeconds - add argument and description to function comment
1572 @todo EFI_ABORTED - add return value to function comment
1573 @todo EFI_TIMEOUT - add return value to function comment
1574 @todo EFI_SUCCESS - add return value to function comment
1578 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1579 UINT64 TimeoutInMicroSeconds
1583 UINT8 AltStatusRegister
;
1586 if (TimeoutInMicroSeconds
== 0) {
1589 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1594 AltStatusRegister
= ReadPortB (
1595 AtapiScsiPrivate
->PciIo
,
1596 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1600 // wait for BSY == 0 and DRQ == 0
1602 if ((AltStatusRegister
& (DRQ
| BSY
)) == 0) {
1606 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
1608 ErrRegister
= ReadPortB (
1609 AtapiScsiPrivate
->PciIo
,
1610 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1612 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1623 // Loop infinitely if not meeting expected condition
1625 if (TimeoutInMicroSeconds
== 0) {
1640 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
1641 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1642 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1645 @todo function comment is missing 'Routine Description:'
1646 @todo function comment is missing 'Arguments:'
1647 @todo function comment is missing 'Returns:'
1648 @todo AtapiScsiPrivate - add argument and description to function comment
1649 @todo TimeoutInMicroSeconds - add argument and description to function comment
1650 @todo EFI_ABORTED - add return value to function comment
1651 @todo EFI_TIMEOUT - add return value to function comment
1652 @todo EFI_SUCCESS - add return value to function comment
1656 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1657 UINT64 TimeoutInMicroSeconds
1661 UINT8 StatusRegister
;
1664 if (TimeoutInMicroSeconds
== 0) {
1667 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1672 // read Status Register will clear interrupt
1674 StatusRegister
= ReadPortB (
1675 AtapiScsiPrivate
->PciIo
,
1676 AtapiScsiPrivate
->IoPort
->Reg
.Status
1682 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1686 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1688 ErrRegister
= ReadPortB (
1689 AtapiScsiPrivate
->PciIo
,
1690 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1692 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1703 // Loop infinitely if not meeting expected condition
1705 if (TimeoutInMicroSeconds
== 0) {
1720 Check whether DRQ is ready in the Alternate Status Register.
1721 (BSY must also be cleared)
1722 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1723 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1726 @todo function comment is missing 'Routine Description:'
1727 @todo function comment is missing 'Arguments:'
1728 @todo function comment is missing 'Returns:'
1729 @todo AtapiScsiPrivate - add argument and description to function comment
1730 @todo TimeoutInMicroSeconds - add argument and description to function comment
1731 @todo EFI_ABORTED - add return value to function comment
1732 @todo EFI_TIMEOUT - add return value to function comment
1733 @todo EFI_SUCCESS - add return value to function comment
1737 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1738 UINT64 TimeoutInMicroSeconds
1742 UINT8 AltStatusRegister
;
1745 if (TimeoutInMicroSeconds
== 0) {
1748 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1753 // read Status Register will clear interrupt
1755 AltStatusRegister
= ReadPortB (
1756 AtapiScsiPrivate
->PciIo
,
1757 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1762 if ((AltStatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1766 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
1768 ErrRegister
= ReadPortB (
1769 AtapiScsiPrivate
->PciIo
,
1770 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1772 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1783 // Loop infinitely if not meeting expected condition
1785 if (TimeoutInMicroSeconds
== 0) {
1800 Check whether BSY is clear in the Status Register.
1801 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1802 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1805 @todo function comment is missing 'Routine Description:'
1806 @todo function comment is missing 'Arguments:'
1807 @todo function comment is missing 'Returns:'
1808 @todo AtapiScsiPrivate - add argument and description to function comment
1809 @todo TimeoutInMicroSeconds - add argument and description to function comment
1810 @todo EFI_TIMEOUT - add return value to function comment
1811 @todo EFI_SUCCESS - add return value to function comment
1814 StatusWaitForBSYClear (
1815 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1816 UINT64 TimeoutInMicroSeconds
1820 UINT8 StatusRegister
;
1822 if (TimeoutInMicroSeconds
== 0) {
1825 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1830 StatusRegister
= ReadPortB (
1831 AtapiScsiPrivate
->PciIo
,
1832 AtapiScsiPrivate
->IoPort
->Reg
.Status
1834 if ((StatusRegister
& BSY
) == 0x00) {
1844 // Loop infinitely if not meeting expected condition
1846 if (TimeoutInMicroSeconds
== 0) {
1861 Check whether BSY is clear in the Alternate Status Register.
1862 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1863 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1866 @todo function comment is missing 'Routine Description:'
1867 @todo function comment is missing 'Arguments:'
1868 @todo function comment is missing 'Returns:'
1869 @todo AtapiScsiPrivate - add argument and description to function comment
1870 @todo TimeoutInMicroSeconds - add argument and description to function comment
1871 @todo EFI_TIMEOUT - add return value to function comment
1872 @todo EFI_SUCCESS - add return value to function comment
1875 AltStatusWaitForBSYClear (
1876 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1877 UINT64 TimeoutInMicroSeconds
1881 UINT8 AltStatusRegister
;
1883 if (TimeoutInMicroSeconds
== 0) {
1886 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1891 AltStatusRegister
= ReadPortB (
1892 AtapiScsiPrivate
->PciIo
,
1893 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1895 if ((AltStatusRegister
& BSY
) == 0x00) {
1904 // Loop infinitely if not meeting expected condition
1906 if (TimeoutInMicroSeconds
== 0) {
1921 Check whether DRDY is ready in the Status Register.
1922 (BSY must also be cleared)
1923 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1924 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1927 @todo function comment is missing 'Routine Description:'
1928 @todo function comment is missing 'Arguments:'
1929 @todo function comment is missing 'Returns:'
1930 @todo AtapiScsiPrivate - add argument and description to function comment
1931 @todo TimeoutInMicroSeconds - add argument and description to function comment
1932 @todo EFI_ABORTED - add return value to function comment
1933 @todo EFI_TIMEOUT - add return value to function comment
1934 @todo EFI_SUCCESS - add return value to function comment
1938 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1939 UINT64 TimeoutInMicroSeconds
1943 UINT8 StatusRegister
;
1946 if (TimeoutInMicroSeconds
== 0) {
1949 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1953 StatusRegister
= ReadPortB (
1954 AtapiScsiPrivate
->PciIo
,
1955 AtapiScsiPrivate
->IoPort
->Reg
.Status
1958 // BSY == 0 , DRDY == 1
1960 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
1964 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1966 ErrRegister
= ReadPortB (
1967 AtapiScsiPrivate
->PciIo
,
1968 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1970 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1980 // Loop infinitely if not meeting expected condition
1982 if (TimeoutInMicroSeconds
== 0) {
1997 Check whether DRDY is ready in the Alternate Status Register.
1998 (BSY must also be cleared)
1999 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2000 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2003 @todo function comment is missing 'Routine Description:'
2004 @todo function comment is missing 'Arguments:'
2005 @todo function comment is missing 'Returns:'
2006 @todo AtapiScsiPrivate - add argument and description to function comment
2007 @todo TimeoutInMicroSeconds - add argument and description to function comment
2008 @todo EFI_ABORTED - add return value to function comment
2009 @todo EFI_TIMEOUT - add return value to function comment
2010 @todo EFI_SUCCESS - add return value to function comment
2013 AltStatusDRDYReady (
2014 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2015 UINT64 TimeoutInMicroSeconds
2019 UINT8 AltStatusRegister
;
2022 if (TimeoutInMicroSeconds
== 0) {
2025 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2029 AltStatusRegister
= ReadPortB (
2030 AtapiScsiPrivate
->PciIo
,
2031 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2034 // BSY == 0 , DRDY == 1
2036 if ((AltStatusRegister
& (DRDY
| BSY
)) == DRDY
) {
2040 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2042 ErrRegister
= ReadPortB (
2043 AtapiScsiPrivate
->PciIo
,
2044 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2046 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2056 // Loop infinitely if not meeting expected condition
2058 if (TimeoutInMicroSeconds
== 0) {
2073 Check Error Register for Error Information.
2075 @todo function comment is missing 'Routine Description:'
2076 @todo function comment is missing 'Arguments:'
2077 @todo function comment is missing 'Returns:'
2078 @todo AtapiScsiPrivate - add argument and description to function comment
2079 @todo EFI_SUCCESS - add return value to function comment
2080 @todo EFI_DEVICE_ERROR - add return value to function comment
2083 AtapiPassThruCheckErrorStatus (
2084 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
2087 UINT8 StatusRegister
;
2091 UINT8 ErrorRegister
;
2095 StatusRegister
= ReadPortB (
2096 AtapiScsiPrivate
->PciIo
,
2097 AtapiScsiPrivate
->IoPort
->Reg
.Status
2101 if (StatusRegister
& DWF
) {
2104 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
2109 if (StatusRegister
& CORR
) {
2112 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
2117 if (StatusRegister
& ERR
) {
2118 ErrorRegister
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg1
.Error
);
2120 if (ErrorRegister
& BBK_ERR
) {
2123 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
2128 if (ErrorRegister
& UNC_ERR
) {
2131 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
2136 if (ErrorRegister
& MC_ERR
) {
2139 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
2144 if (ErrorRegister
& ABRT_ERR
) {
2147 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
2152 if (ErrorRegister
& TK0NF_ERR
) {
2155 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
2160 if (ErrorRegister
& AMNF_ERR
) {
2163 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
2171 if ((StatusRegister
& (ERR
| DWF
| CORR
)) == 0) {
2176 return EFI_DEVICE_ERROR
;