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, (DATA_DIRECTION
) 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
},
86 { 0xff, (DATA_DIRECTION
) 0xff }
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
601 // Validate parameters passed in.
604 if (DevicePath
== NULL
) {
605 return EFI_INVALID_PARAMETER
;
609 // can not build device path for the SCSI Host Controller.
611 if ((Target
> (MAX_TARGET_ID
- 1)) || (Lun
!= 0)) {
612 return EFI_NOT_FOUND
;
615 Node
= AllocateZeroPool (sizeof (EFI_DEV_PATH
));
617 return EFI_OUT_OF_RESOURCES
;
620 Node
->DevPath
.Type
= MESSAGING_DEVICE_PATH
;
621 Node
->DevPath
.SubType
= MSG_ATAPI_DP
;
622 SetDevicePathNodeLength (&Node
->DevPath
, sizeof (ATAPI_DEVICE_PATH
));
624 Node
->Atapi
.PrimarySecondary
= (UINT8
) (Target
/ 2);
625 Node
->Atapi
.SlaveMaster
= (UINT8
) (Target
% 2);
626 Node
->Atapi
.Lun
= (UINT16
) Lun
;
628 *DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Node
;
634 Used to translate a device path node to a Target ID and LUN.
636 @param This Protocol instance pointer.
637 @param DevicePath A pointer to the device path node that
638 describes a SCSI device on the SCSI channel.
639 @param Target A pointer to the Target ID of a SCSI device
641 @param Lun A pointer to the LUN of a SCSI device on
644 @retval EFI_SUCCESS DevicePath was successfully translated to a
645 Target ID and LUN, and they were returned
647 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
648 @retval EFI_INVALID_PARAMETER Target is NULL.
649 @retval EFI_INVALID_PARAMETER Lun is NULL.
650 @retval EFI_UNSUPPORTED This driver does not support the device path
651 node type in DevicePath.
652 @retval EFI_NOT_FOUND A valid translation from DevicePath to a
653 Target ID and LUN does not exist.
658 AtapiScsiPassThruGetTargetLun (
659 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
660 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
668 // Validate parameters passed in.
670 if (DevicePath
== NULL
|| Target
== NULL
|| Lun
== NULL
) {
671 return EFI_INVALID_PARAMETER
;
675 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
677 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
678 (DevicePath
->SubType
!= MSG_ATAPI_DP
) ||
679 (DevicePathNodeLength(DevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
680 return EFI_UNSUPPORTED
;
683 Node
= (EFI_DEV_PATH
*) DevicePath
;
685 *Target
= Node
->Atapi
.PrimarySecondary
* 2 + Node
->Atapi
.SlaveMaster
;
686 *Lun
= Node
->Atapi
.Lun
;
688 if (*Target
> (MAX_TARGET_ID
- 1) || *Lun
!= 0) {
689 return EFI_NOT_FOUND
;
696 Resets a SCSI channel.This operation resets all the
697 SCSI devices connected to the SCSI channel.
699 @param This Protocol instance pointer.
701 @retval EFI_SUCCESS The SCSI channel was reset.
702 @retval EFI_UNSUPPORTED The SCSI channel does not support
703 a channel reset operation.
704 @retval EFI_DEVICE_ERROR A device error occurred while
705 attempting to reset the SCSI channel.
706 @retval EFI_TIMEOUT A timeout occurred while attempting
707 to reset the SCSI channel.
712 AtapiScsiPassThruResetChannel (
713 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
716 UINT8 DeviceControlValue
;
717 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
720 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
723 // Reset both Primary channel and Secondary channel.
724 // so, the IoPort pointer must point to the right I/O Register group
726 for (Index
= 0; Index
< 2; Index
++) {
730 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[Index
];
732 DeviceControlValue
= 0;
734 // set SRST bit to initiate soft reset
736 DeviceControlValue
|= SRST
;
740 DeviceControlValue
|= bit (1);
742 AtapiScsiPrivate
->PciIo
,
743 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
756 DeviceControlValue
&= 0xfb;
758 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
, DeviceControlValue
);
761 // slave device needs at most 31s to clear BSY
763 if (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000) == EFI_TIMEOUT
) {
764 return EFI_DEVICE_ERROR
;
772 Resets a SCSI device that is connected to a SCSI channel.
774 @param This Protocol instance pointer.
775 @param Target The Target ID of the SCSI device to reset.
776 @param Lun The LUN of the SCSI device to reset.
778 @retval EFI_SUCCESS The SCSI device specified by Target and
780 @retval EFI_UNSUPPORTED The SCSI channel does not support a target
782 @retval EFI_INVALID_PARAMETER Target or Lun are invalid.
783 @retval EFI_DEVICE_ERROR A device error occurred while attempting
784 to reset the SCSI device specified by Target
786 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
787 the SCSI device specified by Target and Lun.
792 AtapiScsiPassThruResetTarget (
793 IN EFI_SCSI_PASS_THRU_PROTOCOL
*This
,
798 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
;
802 AtapiScsiPrivate
= ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This
);
804 if (Target
> MAX_TARGET_ID
) {
805 return EFI_INVALID_PARAMETER
;
808 // Directly return EFI_SUCCESS if want to reset the host controller
810 if (Target
== This
->Mode
->AdapterId
) {
815 // According to Target ID, reset the Atapi I/O Register mapping
816 // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],
817 // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]
819 if ((Target
/ 2) == 0) {
820 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[0];
822 AtapiScsiPrivate
->IoPort
= &gAtapiIoPortRegisters
[1];
826 // for ATAPI device, no need to wait DRDY ready after device selecting.
828 // bit7 and bit5 are both set to 1 for backward compatibility
830 DeviceSelect
= (UINT8
) (((bit (7) | bit (5)) | (Target
<< 4)));
831 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Head
, DeviceSelect
);
833 Command
= ATAPI_SOFT_RESET_CMD
;
834 WritePortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg
.Command
, Command
);
837 // BSY clear is the only status return to the host by the device
838 // when reset is complete.
839 // slave device needs at most 31s to clear BSY
841 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, 31000))) {
842 return EFI_DEVICE_ERROR
;
846 // stall 5 seconds to make the device status stable
848 gBS
->Stall (5000000);
855 Checks the parameters in the SCSI Request Packet to make sure
856 they are valid for a SCSI Pass Thru request.
858 @todo function comment is missing 'Routine Description:'
859 @todo function comment is missing 'Arguments:'
860 @todo function comment is missing 'Returns:'
861 @todo Packet - add argument and description to function comment
862 @todo EFI_INVALID_PARAMETER - add return value to function comment
863 @todo EFI_INVALID_PARAMETER - add return value to function comment
864 @todo EFI_INVALID_PARAMETER - add return value to function comment
865 @todo EFI_UNSUPPORTED - add return value to function comment
866 @todo EFI_SUCCESS - add return value to function comment
869 CheckSCSIRequestPacket (
870 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
873 if (Packet
== NULL
) {
874 return EFI_INVALID_PARAMETER
;
877 if (!ValidCdbLength (Packet
->CdbLength
)) {
878 return EFI_INVALID_PARAMETER
;
881 if (Packet
->Cdb
== NULL
) {
882 return EFI_INVALID_PARAMETER
;
886 // Checks whether the request command is supported.
888 if (!IsCommandValid (Packet
)) {
889 return EFI_UNSUPPORTED
;
896 Checks the requested SCSI command:
897 Is it supported by this driver?
898 Is the Data transfer direction reasonable?
900 @todo function comment is missing 'Routine Description:'
901 @todo function comment is missing 'Arguments:'
902 @todo function comment is missing 'Returns:'
903 @todo Packet - add argument and description to function comment
907 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
913 OpCode
= (UINT8
*) (Packet
->Cdb
);
915 for (Index
= 0; CompareMem (&gSupportedATAPICommands
[Index
], &gEndTable
, sizeof (SCSI_COMMAND_SET
)); Index
++) {
917 if (*OpCode
== gSupportedATAPICommands
[Index
].OpCode
) {
919 // Check whether the requested Command is supported by this driver
921 if (Packet
->DataDirection
== DataIn
) {
923 // Check whether the requested data direction conforms to
924 // what it should be.
926 if (gSupportedATAPICommands
[Index
].Direction
== DataOut
) {
931 if (Packet
->DataDirection
== DataOut
) {
933 // Check whether the requested data direction conforms to
934 // what it should be.
936 if (gSupportedATAPICommands
[Index
].Direction
== DataIn
) {
949 Performs blocking I/O request.
951 @param AtapiScsiPrivate Private data structure for the specified channel.
952 @param Target The Target ID of the ATAPI device to send the SCSI
953 Request Packet. To ATAPI devices attached on an IDE
954 Channel, Target ID 0 indicates Master device;Target
955 ID 1 indicates Slave device.
956 @param Packet The SCSI Request Packet to send to the ATAPI device
959 @todo AtapiScsiPrivate - add argument and description to function comment
962 SubmitBlockingIoCommand (
963 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
965 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
968 UINT8 PacketCommand
[12];
969 UINT64 TimeoutInMicroSeconds
;
970 EFI_STATUS PacketCommandStatus
;
973 // Fill ATAPI Command Packet according to CDB
975 ZeroMem (&PacketCommand
, 12);
976 CopyMem (&PacketCommand
, Packet
->Cdb
, Packet
->CdbLength
);
979 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
981 TimeoutInMicroSeconds
= DivU64x32 (Packet
->Timeout
, (UINT32
) 10);
984 // Submit ATAPI Command Packet
986 PacketCommandStatus
= AtapiPacketCommand (
991 &(Packet
->TransferLength
),
992 (DATA_DIRECTION
) Packet
->DataDirection
,
993 TimeoutInMicroSeconds
995 if (!EFI_ERROR (PacketCommandStatus
) || (Packet
->SenseData
== NULL
)) {
996 Packet
->SenseDataLength
= 0;
997 return PacketCommandStatus
;
1000 // Return SenseData if PacketCommandStatus matches
1001 // the following return codes.
1003 if ((PacketCommandStatus
== EFI_WARN_BUFFER_TOO_SMALL
) ||
1004 (PacketCommandStatus
== EFI_DEVICE_ERROR
) ||
1005 (PacketCommandStatus
== EFI_TIMEOUT
)) {
1008 // avoid submit request sense command continuously.
1010 if (PacketCommand
[0] == OP_REQUEST_SENSE
) {
1011 Packet
->SenseDataLength
= 0;
1012 return PacketCommandStatus
;
1015 RequestSenseCommand (
1020 &Packet
->SenseDataLength
1024 return PacketCommandStatus
;
1030 @param AtapiScsiPrivate
1034 @param SenseDataLength
1036 @todo Add function description
1037 @todo AtapiScsiPrivate TODO: add argument description
1038 @todo Target TODO: add argument description
1039 @todo Timeout TODO: add argument description
1040 @todo SenseData TODO: add argument description
1041 @todo SenseDataLength TODO: add argument description
1042 @todo add return values
1045 RequestSenseCommand (
1046 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1050 UINT8
*SenseDataLength
1053 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet
;
1057 ZeroMem (&Packet
, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
));
1060 Cdb
[0] = OP_REQUEST_SENSE
;
1061 Cdb
[4] = (UINT8
) (*SenseDataLength
);
1063 Packet
.Timeout
= Timeout
;
1064 Packet
.DataBuffer
= SenseData
;
1065 Packet
.SenseData
= NULL
;
1067 Packet
.TransferLength
= *SenseDataLength
;
1068 Packet
.CdbLength
= 12;
1069 Packet
.DataDirection
= DataIn
;
1071 Status
= SubmitBlockingIoCommand (AtapiScsiPrivate
, Target
, &Packet
);
1072 *SenseDataLength
= (UINT8
) (Packet
.TransferLength
);
1077 Submits ATAPI command packet to the specified ATAPI device.
1079 @param AtapiScsiPrivate: Private data structure for the specified channel.
1080 @param Target: The Target ID of the ATAPI device to send the SCSI
1081 Request Packet. To ATAPI devices attached on an IDE
1082 Channel, Target ID 0 indicates Master device;Target
1083 ID 1 indicates Slave device.
1084 @param PacketCommand: Points to the ATAPI command packet.
1085 @param Buffer: Points to the transferred data.
1086 @param ByteCount: When input,indicates the buffer size; when output,
1087 indicates the actually transferred data size.
1088 @param Direction: Indicates the data transfer direction.
1089 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1090 to use for the execution of this ATAPI command.
1091 A TimeoutInMicroSeconds value of 0 means that
1092 this function will wait indefinitely for the ATAPI
1095 If TimeoutInMicroSeconds is greater than zero, then
1096 this function will return EFI_TIMEOUT if the time
1097 required to execute the ATAPI command is greater
1098 than TimeoutInMicroSeconds.
1101 @todo AtapiScsiPrivate - add argument and description to function comment
1102 @todo PacketCommand - add argument and description to function comment
1103 @todo Buffer - add argument and description to function comment
1104 @todo ByteCount - add argument and description to function comment
1105 @todo Direction - add argument and description to function comment
1108 AtapiPacketCommand (
1109 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1111 UINT8
*PacketCommand
,
1114 DATA_DIRECTION Direction
,
1115 UINT64 TimeoutInMicroSeconds
1119 UINT16
*CommandIndex
;
1124 // Set all the command parameters by fill related registers.
1125 // Before write to all the following registers, BSY and DRQ must be 0.
1127 Status
= StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1128 if (EFI_ERROR (Status
)) {
1129 if (Status
== EFI_ABORTED
) {
1130 Status
= EFI_DEVICE_ERROR
;
1137 // Select device via Device/Head Register.
1138 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
1141 AtapiScsiPrivate
->PciIo
,
1142 AtapiScsiPrivate
->IoPort
->Head
,
1143 (UINT8
) ((Target
<< 4) | DEFAULT_CMD
) // DEFAULT_CMD: 0xa0 (1010,0000)
1147 // No OVL; No DMA (by setting feature register)
1150 AtapiScsiPrivate
->PciIo
,
1151 AtapiScsiPrivate
->IoPort
->Reg1
.Feature
,
1156 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
1157 // determine how much data should be transfered.
1160 AtapiScsiPrivate
->PciIo
,
1161 AtapiScsiPrivate
->IoPort
->CylinderLsb
,
1162 (UINT8
) (MAX_ATAPI_BYTE_COUNT
& 0x00ff)
1165 AtapiScsiPrivate
->PciIo
,
1166 AtapiScsiPrivate
->IoPort
->CylinderMsb
,
1167 (UINT8
) (MAX_ATAPI_BYTE_COUNT
>> 8)
1171 // DEFAULT_CTL:0x0a (0000,1010)
1172 // Disable interrupt
1175 AtapiScsiPrivate
->PciIo
,
1176 AtapiScsiPrivate
->IoPort
->Alt
.DeviceControl
,
1181 // Send Packet command to inform device
1182 // that the following data bytes are command packet.
1185 AtapiScsiPrivate
->PciIo
,
1186 AtapiScsiPrivate
->IoPort
->Reg
.Command
,
1191 // Before data transfer, BSY should be 0 and DRQ should be 1.
1192 // if they are not in specified time frame,
1193 // retrieve Sense Key from Error Register before return.
1195 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1196 if (EFI_ERROR (Status
)) {
1197 if (Status
== EFI_ABORTED
) {
1198 Status
= EFI_DEVICE_ERROR
;
1206 // Send out command packet
1208 CommandIndex
= (UINT16
*) PacketCommand
;
1209 for (Count
= 0; Count
< 6; Count
++, CommandIndex
++) {
1210 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *CommandIndex
);
1214 // call AtapiPassThruPioReadWriteData() function to get
1215 // requested transfer data form device.
1217 return AtapiPassThruPioReadWriteData (
1222 TimeoutInMicroSeconds
1227 Performs data transfer between ATAPI device and host after the
1228 ATAPI command packet is sent.
1230 @param AtapiScsiPrivate: Private data structure for the specified channel.
1231 @param Buffer: Points to the transferred data.
1232 @param ByteCount: When input,indicates the buffer size; when output,
1233 indicates the actually transferred data size.
1234 @param Direction: Indicates the data transfer direction.
1235 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1236 to use for the execution of this ATAPI command.
1237 A TimeoutInMicroSeconds value of 0 means that
1238 this function will wait indefinitely for the ATAPI
1241 If TimeoutInMicroSeconds is greater than zero, then
1242 this function will return EFI_TIMEOUT if the time
1243 required to execute the ATAPI command is greater
1244 than TimeoutInMicroSeconds.
1247 @todo AtapiScsiPrivate - add argument and description to function comment
1248 @todo Buffer - add argument and description to function comment
1249 @todo ByteCount - add argument and description to function comment
1250 @todo Direction - add argument and description to function comment
1251 @todo EFI_DEVICE_ERROR - add return value to function comment
1252 @todo EFI_DEVICE_ERROR - add return value to function comment
1253 @todo EFI_WARN_BUFFER_TOO_SMALL - add return value to function comment
1256 AtapiPassThruPioReadWriteData (
1257 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1260 DATA_DIRECTION Direction
,
1261 UINT64 TimeoutInMicroSeconds
1265 UINT32 RequiredWordCount
;
1266 UINT32 ActualWordCount
;
1272 Status
= EFI_SUCCESS
;
1275 // Non Data transfer request is also supported.
1277 if (*ByteCount
== 0 || Buffer
== NULL
) {
1279 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
))) {
1280 return EFI_DEVICE_ERROR
;
1285 RequiredWordCount
= *ByteCount
/ 2;
1288 // ActuralWordCount means the word count of data really transfered.
1290 ActualWordCount
= 0;
1292 while (ActualWordCount
< RequiredWordCount
) {
1294 // before each data transfer stream, the host should poll DRQ bit ready,
1295 // which indicates device's ready for data transfer .
1297 Status
= StatusDRQReady (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1298 if (EFI_ERROR (Status
)) {
1299 *ByteCount
= ActualWordCount
* 2;
1301 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
1303 if (ActualWordCount
== 0) {
1304 return EFI_DEVICE_ERROR
;
1307 // ActualWordCount > 0
1309 if (ActualWordCount
< RequiredWordCount
) {
1310 return EFI_WARN_BUFFER_TOO_SMALL
;
1314 // get current data transfer size from Cylinder Registers.
1316 WordCount
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderMsb
) << 8;
1317 WordCount
= WordCount
| ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->CylinderLsb
);
1318 WordCount
= WordCount
& 0xffff;
1322 // perform a series data In/Out.
1324 for (Index
= 0; (Index
< WordCount
) && (ActualWordCount
< RequiredWordCount
); Index
++, ActualWordCount
++) {
1326 if (Direction
== DataIn
) {
1328 *ptrBuffer
= ReadPortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
);
1331 WritePortW (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Data
, *ptrBuffer
);
1339 // After data transfer is completed, normally, DRQ bit should clear.
1341 StatusDRQClear (AtapiScsiPrivate
, TimeoutInMicroSeconds
);
1344 // read status register to check whether error happens.
1346 Status
= AtapiPassThruCheckErrorStatus (AtapiScsiPrivate
);
1348 *ByteCount
= ActualWordCount
* 2;
1355 Read one byte from a specified I/O port.
1357 @todo function comment is missing 'Routine Description:'
1358 @todo function comment is missing 'Arguments:'
1359 @todo function comment is missing 'Returns:'
1360 @todo PciIo - add argument and description to function comment
1361 @todo Port - add argument and description to function comment
1365 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1375 EFI_PCI_IO_PASS_THROUGH_BAR
,
1385 Read one word from a specified I/O port.
1387 @todo function comment is missing 'Routine Description:'
1388 @todo function comment is missing 'Arguments:'
1389 @todo function comment is missing 'Returns:'
1390 @todo PciIo - add argument and description to function comment
1391 @todo Port - add argument and description to function comment
1395 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1404 EfiPciIoWidthUint16
,
1405 EFI_PCI_IO_PASS_THROUGH_BAR
,
1415 Write one byte to a specified I/O port.
1417 @todo function comment is missing 'Routine Description:'
1418 @todo function comment is missing 'Arguments:'
1419 @todo function comment is missing 'Returns:'
1420 @todo PciIo - add argument and description to function comment
1421 @todo Port - add argument and description to function comment
1422 @todo Data - add argument and description to function comment
1426 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1435 EFI_PCI_IO_PASS_THROUGH_BAR
,
1445 Write one word to a specified I/O port.
1447 @todo function comment is missing 'Routine Description:'
1448 @todo function comment is missing 'Arguments:'
1449 @todo function comment is missing 'Returns:'
1450 @todo PciIo - add argument and description to function comment
1451 @todo Port - add argument and description to function comment
1452 @todo Data - add argument and description to function comment
1456 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1464 EfiPciIoWidthUint16
,
1465 EFI_PCI_IO_PASS_THROUGH_BAR
,
1473 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
1474 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1475 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1478 @todo function comment is missing 'Routine Description:'
1479 @todo function comment is missing 'Arguments:'
1480 @todo function comment is missing 'Returns:'
1481 @todo AtapiScsiPrivate - add argument and description to function comment
1482 @todo TimeoutInMicroSeconds - add argument and description to function comment
1483 @todo EFI_ABORTED - add return value to function comment
1484 @todo EFI_TIMEOUT - add return value to function comment
1485 @todo EFI_SUCCESS - add return value to function comment
1489 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1490 UINT64 TimeoutInMicroSeconds
1494 UINT8 StatusRegister
;
1497 if (TimeoutInMicroSeconds
== 0) {
1500 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1505 StatusRegister
= ReadPortB (
1506 AtapiScsiPrivate
->PciIo
,
1507 AtapiScsiPrivate
->IoPort
->Reg
.Status
1511 // wait for BSY == 0 and DRQ == 0
1513 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
1517 // check whether the command is aborted by the device
1519 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1521 ErrRegister
= ReadPortB (
1522 AtapiScsiPrivate
->PciIo
,
1523 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1525 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1536 // Loop infinitely if not meeting expected condition
1538 if (TimeoutInMicroSeconds
== 0) {
1553 Check whether DRQ is clear in the Alternate Status Register.
1554 (BSY must also be cleared).
1555 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1556 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1559 @todo function comment is missing 'Routine Description:'
1560 @todo function comment is missing 'Arguments:'
1561 @todo function comment is missing 'Returns:'
1562 @todo AtapiScsiPrivate - add argument and description to function comment
1563 @todo TimeoutInMicroSeconds - add argument and description to function comment
1564 @todo EFI_ABORTED - add return value to function comment
1565 @todo EFI_TIMEOUT - add return value to function comment
1566 @todo EFI_SUCCESS - add return value to function comment
1570 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1571 UINT64 TimeoutInMicroSeconds
1575 UINT8 AltStatusRegister
;
1578 if (TimeoutInMicroSeconds
== 0) {
1581 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1586 AltStatusRegister
= ReadPortB (
1587 AtapiScsiPrivate
->PciIo
,
1588 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1592 // wait for BSY == 0 and DRQ == 0
1594 if ((AltStatusRegister
& (DRQ
| BSY
)) == 0) {
1598 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
1600 ErrRegister
= ReadPortB (
1601 AtapiScsiPrivate
->PciIo
,
1602 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1604 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1615 // Loop infinitely if not meeting expected condition
1617 if (TimeoutInMicroSeconds
== 0) {
1632 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
1633 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1634 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1637 @todo function comment is missing 'Routine Description:'
1638 @todo function comment is missing 'Arguments:'
1639 @todo function comment is missing 'Returns:'
1640 @todo AtapiScsiPrivate - add argument and description to function comment
1641 @todo TimeoutInMicroSeconds - add argument and description to function comment
1642 @todo EFI_ABORTED - add return value to function comment
1643 @todo EFI_TIMEOUT - add return value to function comment
1644 @todo EFI_SUCCESS - add return value to function comment
1648 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1649 UINT64 TimeoutInMicroSeconds
1653 UINT8 StatusRegister
;
1656 if (TimeoutInMicroSeconds
== 0) {
1659 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1664 // read Status Register will clear interrupt
1666 StatusRegister
= ReadPortB (
1667 AtapiScsiPrivate
->PciIo
,
1668 AtapiScsiPrivate
->IoPort
->Reg
.Status
1674 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1678 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1680 ErrRegister
= ReadPortB (
1681 AtapiScsiPrivate
->PciIo
,
1682 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1684 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1695 // Loop infinitely if not meeting expected condition
1697 if (TimeoutInMicroSeconds
== 0) {
1712 Check whether DRQ is ready in the Alternate Status Register.
1713 (BSY must also be cleared)
1714 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1715 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1718 @todo function comment is missing 'Routine Description:'
1719 @todo function comment is missing 'Arguments:'
1720 @todo function comment is missing 'Returns:'
1721 @todo AtapiScsiPrivate - add argument and description to function comment
1722 @todo TimeoutInMicroSeconds - add argument and description to function comment
1723 @todo EFI_ABORTED - add return value to function comment
1724 @todo EFI_TIMEOUT - add return value to function comment
1725 @todo EFI_SUCCESS - add return value to function comment
1729 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1730 UINT64 TimeoutInMicroSeconds
1734 UINT8 AltStatusRegister
;
1737 if (TimeoutInMicroSeconds
== 0) {
1740 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1745 // read Status Register will clear interrupt
1747 AltStatusRegister
= ReadPortB (
1748 AtapiScsiPrivate
->PciIo
,
1749 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1754 if ((AltStatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1758 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
1760 ErrRegister
= ReadPortB (
1761 AtapiScsiPrivate
->PciIo
,
1762 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1764 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1775 // Loop infinitely if not meeting expected condition
1777 if (TimeoutInMicroSeconds
== 0) {
1792 Check whether BSY is clear in the Status Register.
1793 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1794 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1797 @todo function comment is missing 'Routine Description:'
1798 @todo function comment is missing 'Arguments:'
1799 @todo function comment is missing 'Returns:'
1800 @todo AtapiScsiPrivate - add argument and description to function comment
1801 @todo TimeoutInMicroSeconds - add argument and description to function comment
1802 @todo EFI_TIMEOUT - add return value to function comment
1803 @todo EFI_SUCCESS - add return value to function comment
1806 StatusWaitForBSYClear (
1807 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1808 UINT64 TimeoutInMicroSeconds
1812 UINT8 StatusRegister
;
1814 if (TimeoutInMicroSeconds
== 0) {
1817 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1822 StatusRegister
= ReadPortB (
1823 AtapiScsiPrivate
->PciIo
,
1824 AtapiScsiPrivate
->IoPort
->Reg
.Status
1826 if ((StatusRegister
& BSY
) == 0x00) {
1836 // Loop infinitely if not meeting expected condition
1838 if (TimeoutInMicroSeconds
== 0) {
1853 Check whether BSY is clear in the Alternate Status Register.
1854 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1855 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1858 @todo function comment is missing 'Routine Description:'
1859 @todo function comment is missing 'Arguments:'
1860 @todo function comment is missing 'Returns:'
1861 @todo AtapiScsiPrivate - add argument and description to function comment
1862 @todo TimeoutInMicroSeconds - add argument and description to function comment
1863 @todo EFI_TIMEOUT - add return value to function comment
1864 @todo EFI_SUCCESS - add return value to function comment
1867 AltStatusWaitForBSYClear (
1868 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1869 UINT64 TimeoutInMicroSeconds
1873 UINT8 AltStatusRegister
;
1875 if (TimeoutInMicroSeconds
== 0) {
1878 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1883 AltStatusRegister
= ReadPortB (
1884 AtapiScsiPrivate
->PciIo
,
1885 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
1887 if ((AltStatusRegister
& BSY
) == 0x00) {
1896 // Loop infinitely if not meeting expected condition
1898 if (TimeoutInMicroSeconds
== 0) {
1913 Check whether DRDY is ready in the Status Register.
1914 (BSY must also be cleared)
1915 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1916 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1919 @todo function comment is missing 'Routine Description:'
1920 @todo function comment is missing 'Arguments:'
1921 @todo function comment is missing 'Returns:'
1922 @todo AtapiScsiPrivate - add argument and description to function comment
1923 @todo TimeoutInMicroSeconds - add argument and description to function comment
1924 @todo EFI_ABORTED - add return value to function comment
1925 @todo EFI_TIMEOUT - add return value to function comment
1926 @todo EFI_SUCCESS - add return value to function comment
1930 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
1931 UINT64 TimeoutInMicroSeconds
1935 UINT8 StatusRegister
;
1938 if (TimeoutInMicroSeconds
== 0) {
1941 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
1945 StatusRegister
= ReadPortB (
1946 AtapiScsiPrivate
->PciIo
,
1947 AtapiScsiPrivate
->IoPort
->Reg
.Status
1950 // BSY == 0 , DRDY == 1
1952 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
1956 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1958 ErrRegister
= ReadPortB (
1959 AtapiScsiPrivate
->PciIo
,
1960 AtapiScsiPrivate
->IoPort
->Reg1
.Error
1962 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
1972 // Loop infinitely if not meeting expected condition
1974 if (TimeoutInMicroSeconds
== 0) {
1989 Check whether DRDY is ready in the Alternate Status Register.
1990 (BSY must also be cleared)
1991 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1992 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1995 @todo function comment is missing 'Routine Description:'
1996 @todo function comment is missing 'Arguments:'
1997 @todo function comment is missing 'Returns:'
1998 @todo AtapiScsiPrivate - add argument and description to function comment
1999 @todo TimeoutInMicroSeconds - add argument and description to function comment
2000 @todo EFI_ABORTED - add return value to function comment
2001 @todo EFI_TIMEOUT - add return value to function comment
2002 @todo EFI_SUCCESS - add return value to function comment
2005 AltStatusDRDYReady (
2006 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
,
2007 UINT64 TimeoutInMicroSeconds
2011 UINT8 AltStatusRegister
;
2014 if (TimeoutInMicroSeconds
== 0) {
2017 Delay
= DivU64x32 (TimeoutInMicroSeconds
, (UINT32
) 30) + 1;
2021 AltStatusRegister
= ReadPortB (
2022 AtapiScsiPrivate
->PciIo
,
2023 AtapiScsiPrivate
->IoPort
->Alt
.AltStatus
2026 // BSY == 0 , DRDY == 1
2028 if ((AltStatusRegister
& (DRDY
| BSY
)) == DRDY
) {
2032 if ((AltStatusRegister
& (BSY
| ERR
)) == ERR
) {
2034 ErrRegister
= ReadPortB (
2035 AtapiScsiPrivate
->PciIo
,
2036 AtapiScsiPrivate
->IoPort
->Reg1
.Error
2038 if ((ErrRegister
& ABRT_ERR
) == ABRT_ERR
) {
2048 // Loop infinitely if not meeting expected condition
2050 if (TimeoutInMicroSeconds
== 0) {
2065 Check Error Register for Error Information.
2067 @todo function comment is missing 'Routine Description:'
2068 @todo function comment is missing 'Arguments:'
2069 @todo function comment is missing 'Returns:'
2070 @todo AtapiScsiPrivate - add argument and description to function comment
2071 @todo EFI_SUCCESS - add return value to function comment
2072 @todo EFI_DEVICE_ERROR - add return value to function comment
2075 AtapiPassThruCheckErrorStatus (
2076 ATAPI_SCSI_PASS_THRU_DEV
*AtapiScsiPrivate
2079 UINT8 StatusRegister
;
2080 UINT8 ErrorRegister
;
2082 StatusRegister
= ReadPortB (
2083 AtapiScsiPrivate
->PciIo
,
2084 AtapiScsiPrivate
->IoPort
->Reg
.Status
2087 DEBUG_CODE_BEGIN ();
2089 if (StatusRegister
& DWF
) {
2092 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
2097 if (StatusRegister
& CORR
) {
2100 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
2105 if (StatusRegister
& ERR
) {
2106 ErrorRegister
= ReadPortB (AtapiScsiPrivate
->PciIo
, AtapiScsiPrivate
->IoPort
->Reg1
.Error
);
2109 if (ErrorRegister
& BBK_ERR
) {
2112 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
2117 if (ErrorRegister
& UNC_ERR
) {
2120 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
2125 if (ErrorRegister
& MC_ERR
) {
2128 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
2133 if (ErrorRegister
& ABRT_ERR
) {
2136 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
2141 if (ErrorRegister
& TK0NF_ERR
) {
2144 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
2149 if (ErrorRegister
& AMNF_ERR
) {
2152 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
2160 if ((StatusRegister
& (ERR
| DWF
| CORR
)) == 0) {
2165 return EFI_DEVICE_ERROR
;