+++ /dev/null
-/** @file\r
- Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "AtapiPassThru.h"\r
-\r
-\r
-SCSI_COMMAND_SET gEndTable = { 0xff, (DATA_DIRECTION) 0xff };\r
-\r
-///\r
-/// This table contains all the supported ATAPI commands.\r
-///\r
-SCSI_COMMAND_SET gSupportedATAPICommands[] = {\r
- { OP_INQUIRY, DataIn },\r
- { OP_LOAD_UNLOAD_CD, NoData },\r
- { OP_MECHANISM_STATUS, DataIn },\r
- { OP_MODE_SELECT_10, DataOut },\r
- { OP_MODE_SENSE_10, DataIn },\r
- { OP_PAUSE_RESUME, NoData },\r
- { OP_PLAY_AUDIO_10, DataIn },\r
- { OP_PLAY_AUDIO_MSF, DataIn },\r
- { OP_PLAY_CD, DataIn },\r
- { OP_PLAY_CD_MSF, DataIn },\r
- { OP_PREVENT_ALLOW_MEDIUM_REMOVAL,NoData },\r
- { OP_READ_10, DataIn },\r
- { OP_READ_12, DataIn },\r
- { OP_READ_CAPACITY, DataIn },\r
- { OP_READ_CD, DataIn },\r
- { OP_READ_CD_MSF, DataIn },\r
- { OP_READ_HEADER, DataIn },\r
- { OP_READ_SUB_CHANNEL, DataIn },\r
- { OP_READ_TOC, DataIn },\r
- { OP_REQUEST_SENSE, DataIn },\r
- { OP_SCAN, NoData },\r
- { OP_SEEK_10, NoData },\r
- { OP_SET_CD_SPEED, DataOut },\r
- { OP_STOPPLAY_SCAN, NoData },\r
- { OP_START_STOP_UNIT, NoData },\r
- { OP_TEST_UNIT_READY, NoData },\r
- { OP_FORMAT_UNIT, DataOut },\r
- { OP_READ_FORMAT_CAPACITIES, DataIn },\r
- { OP_VERIFY, DataOut },\r
- { OP_WRITE_10, DataOut },\r
- { OP_WRITE_12, DataOut },\r
- { OP_WRITE_AND_VERIFY, DataOut },\r
- { 0xff, (DATA_DIRECTION) 0xff }\r
-};\r
-\r
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_MODE gScsiPassThruMode = {\r
- L"ATAPI Controller",\r
- L"ATAPI Channel",\r
- 4,\r
- EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,\r
- 0\r
-};\r
-\r
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_PROTOCOL gScsiPassThruProtocolTemplate = {\r
- &gScsiPassThruMode,\r
- AtapiScsiPassThruFunction,\r
- AtapiScsiPassThruGetNextDevice,\r
- AtapiScsiPassThruBuildDevicePath,\r
- AtapiScsiPassThruGetTargetLun,\r
- AtapiScsiPassThruResetChannel,\r
- AtapiScsiPassThruResetTarget\r
-};\r
-\r
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_MODE gExtScsiPassThruMode = {\r
- 4,\r
- EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,\r
- 0\r
-};\r
-\r
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_PROTOCOL gExtScsiPassThruProtocolTemplate = {\r
- &gExtScsiPassThruMode,\r
- AtapiExtScsiPassThruFunction,\r
- AtapiExtScsiPassThruGetNextTargetLun,\r
- AtapiExtScsiPassThruBuildDevicePath,\r
- AtapiExtScsiPassThruGetTargetLun,\r
- AtapiExtScsiPassThruResetChannel,\r
- AtapiExtScsiPassThruResetTarget,\r
- AtapiExtScsiPassThruGetNextTarget\r
-};\r
-\r
-EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = {\r
- AtapiScsiPassThruDriverBindingSupported,\r
- AtapiScsiPassThruDriverBindingStart,\r
- AtapiScsiPassThruDriverBindingStop,\r
- 0x10,\r
- NULL,\r
- NULL\r
-};\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiScsiPassThruDriverBindingSupported (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE Controller,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
- that has gEfiPciIoProtocolGuid installed and is IDE Controller it will be supported.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- Controller - Handle of device to test\r
- RemainingDevicePath - Not used\r
-\r
-Returns:\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- PCI_TYPE00 Pci;\r
-\r
-\r
- //\r
- // Open the IO Abstraction(s) needed to perform the supported test\r
- //\r
- Status = gBS->OpenProtocol (\r
- Controller,\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo,\r
- This->DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_BY_DRIVER\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Use the PCI I/O Protocol to see if Controller is a IDE Controller that\r
- // can be managed by this driver. Read the PCI Configuration Header\r
- // for this device.\r
- //\r
- Status = PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- 0,\r
- sizeof (Pci) / sizeof (UINT32),\r
- &Pci\r
- );\r
- if (EFI_ERROR (Status)) {\r
- gBS->CloseProtocol (\r
- Controller,\r
- &gEfiPciIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- if (Pci.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE || Pci.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE) {\r
-\r
- Status = EFI_UNSUPPORTED;\r
- }\r
-\r
- gBS->CloseProtocol (\r
- Controller,\r
- &gEfiPciIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
-\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiScsiPassThruDriverBindingStart (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE Controller,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Create handles for IDE channels specified by RemainingDevicePath.\r
- Install SCSI Pass Thru Protocol onto each created handle.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- Controller - Handle of device to test\r
- RemainingDevicePath - Not used\r
-\r
-Returns:\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- UINT64 Supports;\r
- UINT64 OriginalPciAttributes;\r
- BOOLEAN PciAttributesSaved;\r
-\r
- PciIo = NULL;\r
- Status = gBS->OpenProtocol (\r
- Controller,\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo,\r
- This->DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_BY_DRIVER\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- PciAttributesSaved = FALSE;\r
- //\r
- // Save original PCI attributes\r
- //\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationGet,\r
- 0,\r
- &OriginalPciAttributes\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- PciAttributesSaved = TRUE;\r
-\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationSupported,\r
- 0,\r
- &Supports\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- Supports &= (EFI_PCI_DEVICE_ENABLE |\r
- EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO |\r
- EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO);\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationEnable,\r
- Supports,\r
- NULL\r
- );\r
- }\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- //\r
- // Create SCSI Pass Thru instance for the IDE channel.\r
- //\r
- Status = RegisterAtapiScsiPassThru (This, Controller, PciIo, OriginalPciAttributes);\r
-\r
-Done:\r
- if (EFI_ERROR (Status)) {\r
- if (PciAttributesSaved == TRUE) {\r
- //\r
- // Restore original PCI attributes\r
- //\r
- PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationSet,\r
- OriginalPciAttributes,\r
- NULL\r
- );\r
- }\r
-\r
- gBS->CloseProtocol (\r
- Controller,\r
- &gEfiPciIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiScsiPassThruDriverBindingStop (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE Controller,\r
- IN UINTN NumberOfChildren,\r
- IN EFI_HANDLE *ChildHandleBuffer\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Stop this driver on ControllerHandle. Support stopping any child handles\r
- created by this driver.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- Controller - Handle of device to stop driver on\r
- NumberOfChildren - Number of Children in the ChildHandleBuffer\r
- ChildHandleBuffer - List of handles for the children we need to stop.\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;\r
- EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
-\r
- if (FeaturePcdGet (PcdSupportScsiPassThru)) {\r
- Status = gBS->OpenProtocol (\r
- Controller,\r
- &gEfiScsiPassThruProtocolGuid,\r
- (VOID **) &ScsiPassThru,\r
- This->DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru);\r
- if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {\r
- Status = gBS->UninstallMultipleProtocolInterfaces (\r
- Controller,\r
- &gEfiScsiPassThruProtocolGuid,\r
- &AtapiScsiPrivate->ScsiPassThru,\r
- &gEfiExtScsiPassThruProtocolGuid,\r
- &AtapiScsiPrivate->ExtScsiPassThru,\r
- NULL\r
- );\r
- } else {\r
- Status = gBS->UninstallMultipleProtocolInterfaces (\r
- Controller,\r
- &gEfiScsiPassThruProtocolGuid,\r
- &AtapiScsiPrivate->ScsiPassThru,\r
- NULL\r
- );\r
- }\r
- } else {\r
- Status = gBS->OpenProtocol (\r
- Controller,\r
- &gEfiExtScsiPassThruProtocolGuid,\r
- (VOID **) &ExtScsiPassThru,\r
- This->DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (ExtScsiPassThru);\r
- Status = gBS->UninstallMultipleProtocolInterfaces (\r
- Controller,\r
- &gEfiExtScsiPassThruProtocolGuid,\r
- &AtapiScsiPrivate->ExtScsiPassThru,\r
- NULL\r
- );\r
- }\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Restore original PCI attributes\r
- //\r
- AtapiScsiPrivate->PciIo->Attributes (\r
- AtapiScsiPrivate->PciIo,\r
- EfiPciIoAttributeOperationSet,\r
- AtapiScsiPrivate->OriginalPciAttributes,\r
- NULL\r
- );\r
-\r
- gBS->CloseProtocol (\r
- Controller,\r
- &gEfiPciIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
-\r
- gBS->FreePool (AtapiScsiPrivate);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-RegisterAtapiScsiPassThru (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE Controller,\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT64 OriginalPciAttributes\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Attaches SCSI Pass Thru Protocol for specified IDE channel.\r
-\r
-Arguments:\r
- This - Protocol instance pointer.\r
- Controller - Parent device handle to the IDE channel.\r
- PciIo - PCI I/O protocol attached on the "Controller".\r
-\r
-Returns:\r
- Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
- IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[ATAPI_MAX_CHANNEL];\r
-\r
- AtapiScsiPrivate = AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV));\r
- if (AtapiScsiPrivate == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- AtapiScsiPrivate->Signature = ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE;\r
- AtapiScsiPrivate->Handle = Controller;\r
-\r
- //\r
- // will reset the IoPort inside each API function.\r
- //\r
- AtapiScsiPrivate->IoPort = NULL;\r
- AtapiScsiPrivate->PciIo = PciIo;\r
- AtapiScsiPrivate->OriginalPciAttributes = OriginalPciAttributes;\r
-\r
- //\r
- // Obtain IDE IO port registers' base addresses\r
- //\r
- Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- InitAtapiIoPortRegisters(AtapiScsiPrivate, IdeRegsBaseAddr);\r
-\r
- //\r
- // Initialize the LatestTargetId to MAX_TARGET_ID.\r
- //\r
- AtapiScsiPrivate->LatestTargetId = MAX_TARGET_ID;\r
- AtapiScsiPrivate->LatestLun = 0;\r
-\r
- Status = InstallScsiPassThruProtocols (&Controller, AtapiScsiPrivate);\r
-\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiScsiPassThruFunction (\r
- IN EFI_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN UINT32 Target,\r
- IN UINT64 Lun,\r
- IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
- IN EFI_EVENT Event OPTIONAL\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.\r
-\r
-Arguments:\r
-\r
- This: The EFI_SCSI_PASS_THRU_PROTOCOL instance.\r
- Target: The Target ID of the ATAPI device to send the SCSI\r
- Request Packet. To ATAPI devices attached on an IDE\r
- Channel, Target ID 0 indicates Master device;Target\r
- ID 1 indicates Slave device.\r
- Lun: The LUN of the ATAPI device to send the SCSI Request\r
- Packet. To the ATAPI device, Lun is always 0.\r
- Packet: The SCSI Request Packet to send to the ATAPI device\r
- specified by Target and Lun.\r
- Event: If non-blocking I/O is not supported then Event is ignored,\r
- and blocking I/O is performed.\r
- If Event is NULL, then blocking I/O is performed.\r
- If Event is not NULL and non blocking I/O is supported,\r
- then non-blocking I/O is performed, and Event will be signaled\r
- when the SCSI Request Packet completes.\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
- EFI_STATUS Status;\r
-\r
- AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
-\r
- //\r
- // Target is not allowed beyond MAX_TARGET_ID\r
- //\r
- if ((Target > MAX_TARGET_ID) || (Lun != 0)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // check the data fields in Packet parameter.\r
- //\r
- Status = CheckSCSIRequestPacket (Packet);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // If Request Packet targets at the IDE channel itself,\r
- // do nothing.\r
- //\r
- if (Target == This->Mode->AdapterId) {\r
- Packet->TransferLength = 0;\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // According to Target ID, reset the Atapi I/O Register mapping\r
- // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],\r
- // Target Id in [2,3] area, using AtapiIoPortRegisters[1]\r
- //\r
- if ((Target / 2) == 0) {\r
- Target = Target % 2;\r
- AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];\r
- } else {\r
- Target = Target % 2;\r
- AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];\r
- }\r
-\r
- //\r
- // the ATAPI SCSI interface does not support non-blocking I/O\r
- // ignore the Event parameter\r
- //\r
- // Performs blocking I/O.\r
- //\r
- Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, Packet);\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiScsiPassThruGetNextDevice (\r
- IN EFI_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN OUT UINT32 *Target,\r
- IN OUT UINT64 *Lun\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Used to retrieve the list of legal Target IDs for SCSI devices\r
- on a SCSI channel.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- Target - On input, a pointer to the Target ID of a SCSI\r
- device present on the SCSI channel. On output,\r
- a pointer to the Target ID of the next SCSI device\r
- present on a SCSI channel. An input value of\r
- 0xFFFFFFFF retrieves the Target ID of the first\r
- SCSI device present on a SCSI channel.\r
- Lun - On input, a pointer to the LUN of a SCSI device\r
- present on the SCSI channel. On output, a pointer\r
- to the LUN of the next SCSI device present on\r
- a SCSI channel.\r
-Returns:\r
-\r
- EFI_SUCCESS - The Target ID and Lun of the next SCSI device\r
- on the SCSI channel was returned in Target and Lun.\r
- EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.\r
- EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
- returned on a previous call to GetNextDevice().\r
---*/\r
-{\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
-\r
- //\r
- // Retrieve Device Private Data Structure.\r
- //\r
- AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
-\r
- //\r
- // Check whether Target is valid.\r
- //\r
- if (Target == NULL || Lun == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if ((*Target != 0xFFFFFFFF) &&\r
- ((*Target != AtapiScsiPrivate->LatestTargetId) ||\r
- (*Lun != AtapiScsiPrivate->LatestLun))) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (*Target == MAX_TARGET_ID) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- if (*Target == 0xFFFFFFFF) {\r
- *Target = 0;\r
- } else {\r
- *Target = AtapiScsiPrivate->LatestTargetId + 1;\r
- }\r
-\r
- *Lun = 0;\r
-\r
- //\r
- // Update the LatestTargetId.\r
- //\r
- AtapiScsiPrivate->LatestTargetId = *Target;\r
- AtapiScsiPrivate->LatestLun = *Lun;\r
-\r
- return EFI_SUCCESS;\r
-\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiScsiPassThruBuildDevicePath (\r
- IN EFI_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN UINT32 Target,\r
- IN UINT64 Lun,\r
- IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Used to allocate and build a device path node for a SCSI device\r
- on a SCSI channel. Would not build device path for a SCSI Host Controller.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- Target - The Target ID of the SCSI device for which\r
- a device path node is to be allocated and built.\r
- Lun - The LUN of the SCSI device for which a device\r
- path node is to be allocated and built.\r
- DevicePath - A pointer to a single device path node that\r
- describes the SCSI device specified by\r
- Target and Lun. This function is responsible\r
- for allocating the buffer DevicePath with the boot\r
- service AllocatePool(). It is the caller's\r
- responsibility to free DevicePath when the caller\r
- is finished with DevicePath.\r
- Returns:\r
- EFI_SUCCESS - The device path node that describes the SCSI device\r
- specified by Target and Lun was allocated and\r
- returned in DevicePath.\r
- EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does\r
- not exist on the SCSI channel.\r
- EFI_INVALID_PARAMETER - DevicePath is NULL.\r
- EFI_OUT_OF_RESOURCES - There are not enough resources to allocate\r
- DevicePath.\r
---*/\r
-{\r
- EFI_DEV_PATH *Node;\r
-\r
-\r
- //\r
- // Validate parameters passed in.\r
- //\r
-\r
- if (DevicePath == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // can not build device path for the SCSI Host Controller.\r
- //\r
- if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));\r
- if (Node == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Node->DevPath.Type = MESSAGING_DEVICE_PATH;\r
- Node->DevPath.SubType = MSG_ATAPI_DP;\r
- SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));\r
-\r
- Node->Atapi.PrimarySecondary = (UINT8) (Target / 2);\r
- Node->Atapi.SlaveMaster = (UINT8) (Target % 2);\r
- Node->Atapi.Lun = (UINT16) Lun;\r
-\r
- *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiScsiPassThruGetTargetLun (\r
- IN EFI_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
- OUT UINT32 *Target,\r
- OUT UINT64 *Lun\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Used to translate a device path node to a Target ID and LUN.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- DevicePath - A pointer to the device path node that\r
- describes a SCSI device on the SCSI channel.\r
- Target - A pointer to the Target ID of a SCSI device\r
- on the SCSI channel.\r
- Lun - A pointer to the LUN of a SCSI device on\r
- the SCSI channel.\r
-Returns:\r
-\r
- EFI_SUCCESS - DevicePath was successfully translated to a\r
- Target ID and LUN, and they were returned\r
- in Target and Lun.\r
- EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.\r
- EFI_UNSUPPORTED - This driver does not support the device path\r
- node type in DevicePath.\r
- EFI_NOT_FOUND - A valid translation from DevicePath to a\r
- Target ID and LUN does not exist.\r
---*/\r
-{\r
- EFI_DEV_PATH *Node;\r
-\r
- //\r
- // Validate parameters passed in.\r
- //\r
- if (DevicePath == NULL || Target == NULL || Lun == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Check whether the DevicePath belongs to SCSI_DEVICE_PATH\r
- //\r
- if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
- (DevicePath->SubType != MSG_ATAPI_DP) ||\r
- (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- Node = (EFI_DEV_PATH *) DevicePath;\r
-\r
- *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;\r
- *Lun = Node->Atapi.Lun;\r
-\r
- if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiScsiPassThruResetChannel (\r
- IN EFI_SCSI_PASS_THRU_PROTOCOL *This\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Resets a SCSI channel.This operation resets all the\r
- SCSI devices connected to the SCSI channel.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS - The SCSI channel was reset.\r
- EFI_UNSUPPORTED - The SCSI channel does not support\r
- a channel reset operation.\r
- EFI_DEVICE_ERROR - A device error occurred while\r
- attempting to reset the SCSI channel.\r
- EFI_TIMEOUT - A timeout occurred while attempting\r
- to reset the SCSI channel.\r
---*/\r
-{\r
- UINT8 DeviceControlValue;\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
- UINT8 Index;\r
- BOOLEAN ResetFlag;\r
-\r
- AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
- ResetFlag = FALSE;\r
-\r
- //\r
- // Reset both Primary channel and Secondary channel.\r
- // so, the IoPort pointer must point to the right I/O Register group\r
- //\r
- for (Index = 0; Index < 2; Index++) {\r
- //\r
- // Reset\r
- //\r
- AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];\r
-\r
- DeviceControlValue = 0;\r
- //\r
- // set SRST bit to initiate soft reset\r
- //\r
- DeviceControlValue |= SRST;\r
- //\r
- // disable Interrupt\r
- //\r
- DeviceControlValue |= BIT1;\r
- WritePortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Alt.DeviceControl,\r
- DeviceControlValue\r
- );\r
-\r
- //\r
- // Wait 10us\r
- //\r
- gBS->Stall (10);\r
-\r
- //\r
- // Clear SRST bit\r
- // 0xfb:1111,1011\r
- //\r
- DeviceControlValue &= 0xfb;\r
-\r
- WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);\r
-\r
- //\r
- // slave device needs at most 31s to clear BSY\r
- //\r
- if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {\r
- ResetFlag = TRUE;\r
- }\r
- }\r
-\r
- if (ResetFlag) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- return EFI_TIMEOUT;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiScsiPassThruResetTarget (\r
- IN EFI_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN UINT32 Target,\r
- IN UINT64 Lun\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Resets a SCSI device that is connected to a SCSI channel.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- Target - The Target ID of the SCSI device to reset.\r
- Lun - The LUN of the SCSI device to reset.\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS - The SCSI device specified by Target and\r
- Lun was reset.\r
- EFI_UNSUPPORTED - The SCSI channel does not support a target\r
- reset operation.\r
- EFI_INVALID_PARAMETER - Target or Lun are invalid.\r
- EFI_DEVICE_ERROR - A device error occurred while attempting\r
- to reset the SCSI device specified by Target\r
- and Lun.\r
- EFI_TIMEOUT - A timeout occurred while attempting to reset\r
- the SCSI device specified by Target and Lun.\r
---*/\r
-{\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
- UINT8 Command;\r
- UINT8 DeviceSelect;\r
-\r
- AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
-\r
- if ((Target > MAX_TARGET_ID) || (Lun != 0)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- //\r
- // Directly return EFI_SUCCESS if want to reset the host controller\r
- //\r
- if (Target == This->Mode->AdapterId) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // According to Target ID, reset the Atapi I/O Register mapping\r
- // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],\r
- // Target Id in [2,3] area, using AtapiIoPortRegisters[1]\r
- //\r
- if ((Target / 2) == 0) {\r
- AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];\r
- } else {\r
- AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];\r
- }\r
-\r
- //\r
- // for ATAPI device, no need to wait DRDY ready after device selecting.\r
- //\r
- // bit7 and bit5 are both set to 1 for backward compatibility\r
- //\r
- DeviceSelect = (UINT8) (((BIT7 | BIT5) | (Target << 4)));\r
- WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);\r
-\r
- Command = ATAPI_SOFT_RESET_CMD;\r
- WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);\r
-\r
- //\r
- // BSY clear is the only status return to the host by the device\r
- // when reset is complete.\r
- // slave device needs at most 31s to clear BSY\r
- //\r
- if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- //\r
- // stall 5 seconds to make the device status stable\r
- //\r
- gBS->Stall (5000000);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiExtScsiPassThruFunction (\r
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN UINT8 *Target,\r
- IN UINT64 Lun,\r
- IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
- IN EFI_EVENT Event OPTIONAL\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.\r
-\r
-Arguments:\r
-\r
- This: The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
- Target: The Target ID of the ATAPI device to send the SCSI\r
- Request Packet. To ATAPI devices attached on an IDE\r
- Channel, Target ID 0 indicates Master device;Target\r
- ID 1 indicates Slave device.\r
- Lun: The LUN of the ATAPI device to send the SCSI Request\r
- Packet. To the ATAPI device, Lun is always 0.\r
- Packet: The SCSI Request Packet to send to the ATAPI device\r
- specified by Target and Lun.\r
- Event: If non-blocking I/O is not supported then Event is ignored,\r
- and blocking I/O is performed.\r
- If Event is NULL, then blocking I/O is performed.\r
- If Event is not NULL and non blocking I/O is supported,\r
- then non-blocking I/O is performed, and Event will be signaled\r
- when the SCSI Request Packet completes.\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
- UINT8 TargetId;\r
-\r
- AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
-\r
- //\r
- // For ATAPI device, UINT8 is enough to represent the SCSI ID on channel.\r
- //\r
- TargetId = Target[0];\r
-\r
- //\r
- // Target is not allowed beyond MAX_TARGET_ID\r
- //\r
- if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // check the data fields in Packet parameter.\r
- //\r
- Status = CheckExtSCSIRequestPacket (Packet);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // If Request Packet targets at the IDE channel itself,\r
- // do nothing.\r
- //\r
- if (TargetId == (UINT8)This->Mode->AdapterId) {\r
- Packet->InTransferLength = Packet->OutTransferLength = 0;\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // According to Target ID, reset the Atapi I/O Register mapping\r
- // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],\r
- // Target Id in [2,3] area, using AtapiIoPortRegisters[1]\r
- //\r
- if ((TargetId / 2) == 0) {\r
- TargetId = (UINT8) (TargetId % 2);\r
- AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];\r
- } else {\r
- TargetId = (UINT8) (TargetId % 2);\r
- AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];\r
- }\r
-\r
- //\r
- // the ATAPI SCSI interface does not support non-blocking I/O\r
- // ignore the Event parameter\r
- //\r
- // Performs blocking I/O.\r
- //\r
- Status = SubmitExtBlockingIoCommand (AtapiScsiPrivate, TargetId, Packet);\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiExtScsiPassThruGetNextTargetLun (\r
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN OUT UINT8 **Target,\r
- IN OUT UINT64 *Lun\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Used to retrieve the list of legal Target IDs for SCSI devices\r
- on a SCSI channel.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- Target - On input, a pointer to the Target ID of a SCSI\r
- device present on the SCSI channel. On output,\r
- a pointer to the Target ID of the next SCSI device\r
- present on a SCSI channel. An input value of\r
- 0xFFFFFFFF retrieves the Target ID of the first\r
- SCSI device present on a SCSI channel.\r
- Lun - On input, a pointer to the LUN of a SCSI device\r
- present on the SCSI channel. On output, a pointer\r
- to the LUN of the next SCSI device present on\r
- a SCSI channel.\r
-Returns:\r
-\r
- EFI_SUCCESS - The Target ID and Lun of the next SCSI device\r
- on the SCSI channel was returned in Target and Lun.\r
- EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.\r
- EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
- returned on a previous call to GetNextDevice().\r
---*/\r
-{\r
- UINT8 ByteIndex;\r
- UINT8 TargetId;\r
- UINT8 ScsiId[TARGET_MAX_BYTES];\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
-\r
- //\r
- // Retrieve Device Private Data Structure.\r
- //\r
- AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
-\r
- //\r
- // Check whether Target is valid.\r
- //\r
- if (*Target == NULL || Lun == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);\r
-\r
- TargetId = (*Target)[0];\r
-\r
- //\r
- // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.\r
- //\r
- if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {\r
- for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {\r
- if ((*Target)[ByteIndex] != 0) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- }\r
- }\r
-\r
- if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&\r
- ((TargetId != AtapiScsiPrivate->LatestTargetId) ||\r
- (*Lun != AtapiScsiPrivate->LatestLun))) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (TargetId == MAX_TARGET_ID) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0) {\r
- SetMem (*Target, TARGET_MAX_BYTES,0);\r
- } else {\r
- (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);\r
- }\r
-\r
- *Lun = 0;\r
-\r
- //\r
- // Update the LatestTargetId.\r
- //\r
- AtapiScsiPrivate->LatestTargetId = (*Target)[0];\r
- AtapiScsiPrivate->LatestLun = *Lun;\r
-\r
- return EFI_SUCCESS;\r
-\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiExtScsiPassThruBuildDevicePath (\r
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN UINT8 *Target,\r
- IN UINT64 Lun,\r
- IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Used to allocate and build a device path node for a SCSI device\r
- on a SCSI channel. Would not build device path for a SCSI Host Controller.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- Target - The Target ID of the SCSI device for which\r
- a device path node is to be allocated and built.\r
- Lun - The LUN of the SCSI device for which a device\r
- path node is to be allocated and built.\r
- DevicePath - A pointer to a single device path node that\r
- describes the SCSI device specified by\r
- Target and Lun. This function is responsible\r
- for allocating the buffer DevicePath with the boot\r
- service AllocatePool(). It is the caller's\r
- responsibility to free DevicePath when the caller\r
- is finished with DevicePath.\r
- Returns:\r
- EFI_SUCCESS - The device path node that describes the SCSI device\r
- specified by Target and Lun was allocated and\r
- returned in DevicePath.\r
- EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does\r
- not exist on the SCSI channel.\r
- EFI_INVALID_PARAMETER - DevicePath is NULL.\r
- EFI_OUT_OF_RESOURCES - There are not enough resources to allocate\r
- DevicePath.\r
---*/\r
-{\r
- EFI_DEV_PATH *Node;\r
- UINT8 TargetId;\r
-\r
- TargetId = Target[0];\r
-\r
- //\r
- // Validate parameters passed in.\r
- //\r
-\r
- if (DevicePath == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // can not build device path for the SCSI Host Controller.\r
- //\r
- if ((TargetId > (MAX_TARGET_ID - 1)) || (Lun != 0)) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));\r
- if (Node == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Node->DevPath.Type = MESSAGING_DEVICE_PATH;\r
- Node->DevPath.SubType = MSG_ATAPI_DP;\r
- SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));\r
-\r
- Node->Atapi.PrimarySecondary = (UINT8) (TargetId / 2);\r
- Node->Atapi.SlaveMaster = (UINT8) (TargetId % 2);\r
- Node->Atapi.Lun = (UINT16) Lun;\r
-\r
- *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiExtScsiPassThruGetTargetLun (\r
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
- OUT UINT8 **Target,\r
- OUT UINT64 *Lun\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Used to translate a device path node to a Target ID and LUN.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- DevicePath - A pointer to the device path node that\r
- describes a SCSI device on the SCSI channel.\r
- Target - A pointer to the Target ID of a SCSI device\r
- on the SCSI channel.\r
- Lun - A pointer to the LUN of a SCSI device on\r
- the SCSI channel.\r
-Returns:\r
-\r
- EFI_SUCCESS - DevicePath was successfully translated to a\r
- Target ID and LUN, and they were returned\r
- in Target and Lun.\r
- EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.\r
- EFI_UNSUPPORTED - This driver does not support the device path\r
- node type in DevicePath.\r
- EFI_NOT_FOUND - A valid translation from DevicePath to a\r
- Target ID and LUN does not exist.\r
---*/\r
-{\r
- EFI_DEV_PATH *Node;\r
-\r
- //\r
- // Validate parameters passed in.\r
- //\r
- if (DevicePath == NULL || Target == NULL || Lun == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Check whether the DevicePath belongs to SCSI_DEVICE_PATH\r
- //\r
- if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
- (DevicePath->SubType != MSG_ATAPI_DP) ||\r
- (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- ZeroMem (*Target, TARGET_MAX_BYTES);\r
-\r
- Node = (EFI_DEV_PATH *) DevicePath;\r
-\r
- (*Target)[0] = (UINT8) (Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster);\r
- *Lun = Node->Atapi.Lun;\r
-\r
- if ((*Target)[0] > (MAX_TARGET_ID - 1) || *Lun != 0) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiExtScsiPassThruResetChannel (\r
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Resets a SCSI channel.This operation resets all the\r
- SCSI devices connected to the SCSI channel.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS - The SCSI channel was reset.\r
- EFI_UNSUPPORTED - The SCSI channel does not support\r
- a channel reset operation.\r
- EFI_DEVICE_ERROR - A device error occurred while\r
- attempting to reset the SCSI channel.\r
- EFI_TIMEOUT - A timeout occurred while attempting\r
- to reset the SCSI channel.\r
---*/\r
-{\r
- UINT8 DeviceControlValue;\r
- UINT8 Index;\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
- BOOLEAN ResetFlag;\r
-\r
- AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
- ResetFlag = FALSE;\r
- //\r
- // Reset both Primary channel and Secondary channel.\r
- // so, the IoPort pointer must point to the right I/O Register group\r
- // And if there is a channel reset successfully, return EFI_SUCCESS.\r
- //\r
- for (Index = 0; Index < 2; Index++) {\r
- //\r
- // Reset\r
- //\r
- AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];\r
-\r
- DeviceControlValue = 0;\r
- //\r
- // set SRST bit to initiate soft reset\r
- //\r
- DeviceControlValue |= SRST;\r
- //\r
- // disable Interrupt\r
- //\r
- DeviceControlValue |= BIT1;\r
- WritePortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Alt.DeviceControl,\r
- DeviceControlValue\r
- );\r
-\r
- //\r
- // Wait 10us\r
- //\r
- gBS->Stall (10);\r
-\r
- //\r
- // Clear SRST bit\r
- // 0xfb:1111,1011\r
- //\r
- DeviceControlValue &= 0xfb;\r
-\r
- WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);\r
-\r
- //\r
- // slave device needs at most 31s to clear BSY\r
- //\r
- if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {\r
- ResetFlag = TRUE;\r
- }\r
- }\r
-\r
- if (ResetFlag) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- return EFI_TIMEOUT;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiExtScsiPassThruResetTarget (\r
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN UINT8 *Target,\r
- IN UINT64 Lun\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Resets a SCSI device that is connected to a SCSI channel.\r
-\r
-Arguments:\r
-\r
- This - Protocol instance pointer.\r
- Target - The Target ID of the SCSI device to reset.\r
- Lun - The LUN of the SCSI device to reset.\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS - The SCSI device specified by Target and\r
- Lun was reset.\r
- EFI_UNSUPPORTED - The SCSI channel does not support a target\r
- reset operation.\r
- EFI_INVALID_PARAMETER - Target or Lun are invalid.\r
- EFI_DEVICE_ERROR - A device error occurred while attempting\r
- to reset the SCSI device specified by Target\r
- and Lun.\r
- EFI_TIMEOUT - A timeout occurred while attempting to reset\r
- the SCSI device specified by Target and Lun.\r
---*/\r
-{\r
- UINT8 Command;\r
- UINT8 DeviceSelect;\r
- UINT8 TargetId;\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
-\r
- AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
- TargetId = Target[0];\r
-\r
- if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- //\r
- // Directly return EFI_SUCCESS if want to reset the host controller\r
- //\r
- if (TargetId == This->Mode->AdapterId) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // According to Target ID, reset the Atapi I/O Register mapping\r
- // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],\r
- // Target Id in [2,3] area, using AtapiIoPortRegisters[1]\r
- //\r
- if ((TargetId / 2) == 0) {\r
- AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];\r
- } else {\r
- AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];\r
- }\r
-\r
- //\r
- // for ATAPI device, no need to wait DRDY ready after device selecting.\r
- //\r
- // bit7 and bit5 are both set to 1 for backward compatibility\r
- //\r
- DeviceSelect = (UINT8) ((BIT7 | BIT5) | (TargetId << 4));\r
- WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);\r
-\r
- Command = ATAPI_SOFT_RESET_CMD;\r
- WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);\r
-\r
- //\r
- // BSY clear is the only status return to the host by the device\r
- // when reset is complete.\r
- // slave device needs at most 31s to clear BSY\r
- //\r
- if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- //\r
- // stall 5 seconds to make the device status stable\r
- //\r
- gBS->Stall (5000000);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-AtapiExtScsiPassThruGetNextTarget (\r
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
- IN OUT UINT8 **Target\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Used to retrieve the list of legal Target IDs for SCSI devices\r
- on a SCSI channel.\r
-\r
-Arguments:\r
- This - Protocol instance pointer.\r
- Target - On input, a pointer to the Target ID of a SCSI\r
- device present on the SCSI channel. On output,\r
- a pointer to the Target ID of the next SCSI device\r
- present on a SCSI channel. An input value of\r
- 0xFFFFFFFF retrieves the Target ID of the first\r
- SCSI device present on a SCSI channel.\r
- Lun - On input, a pointer to the LUN of a SCSI device\r
- present on the SCSI channel. On output, a pointer\r
- to the LUN of the next SCSI device present on\r
- a SCSI channel.\r
-\r
-Returns:\r
- EFI_SUCCESS - The Target ID and Lun of the next SCSI device\r
- on the SCSI channel was returned in Target and Lun.\r
- EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.\r
- EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
- returned on a previous call to GetNextDevice().\r
---*/\r
-{\r
- UINT8 TargetId;\r
- UINT8 ScsiId[TARGET_MAX_BYTES];\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
- UINT8 ByteIndex;\r
-\r
- //\r
- // Retrieve Device Private Data Structure.\r
- //\r
- AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
-\r
- //\r
- // Check whether Target is valid.\r
- //\r
- if (*Target == NULL ) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- TargetId = (*Target)[0];\r
- SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);\r
-\r
- //\r
- // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.\r
- //\r
- if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {\r
- for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {\r
- if ((*Target)[ByteIndex] != 0) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- }\r
- }\r
-\r
- if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&(TargetId != AtapiScsiPrivate->LatestTargetId)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (TargetId == MAX_TARGET_ID) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0)) {\r
- SetMem (*Target, TARGET_MAX_BYTES, 0);\r
- } else {\r
- (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);\r
- }\r
-\r
- //\r
- // Update the LatestTargetId.\r
- //\r
- AtapiScsiPrivate->LatestTargetId = (*Target)[0];\r
- AtapiScsiPrivate->LatestLun = 0;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-GetIdeRegistersBaseAddr (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
- use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
- the PCI IDE controller's Configuration Space.\r
-\r
-Arguments:\r
- PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance\r
- IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to\r
- receive IDE IO port registers' base addresses\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- PCI_TYPE00 PciData;\r
-\r
- Status = PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint8,\r
- 0,\r
- sizeof (PciData),\r
- &PciData\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
- IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;\r
- IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;\r
- } else {\r
- //\r
- // The BARs should be of IO type\r
- //\r
- if ((PciData.Device.Bar[0] & BIT0) == 0 ||\r
- (PciData.Device.Bar[1] & BIT0) == 0) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =\r
- (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
- IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =\r
- (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
- }\r
-\r
- if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
- IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;\r
- IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;\r
- } else {\r
- //\r
- // The BARs should be of IO type\r
- //\r
- if ((PciData.Device.Bar[2] & BIT0) == 0 ||\r
- (PciData.Device.Bar[3] & BIT0) == 0) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =\r
- (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
- IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =\r
- (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-VOID\r
-InitAtapiIoPortRegisters (\r
- IN ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- IN IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Initialize each Channel's Base Address of CommandBlock and ControlBlock.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
- IdeRegsBaseAddr - The pointer of IDE_REGISTERS_BASE_ADDR\r
-\r
-Returns:\r
-\r
- None\r
-\r
---*/\r
-{\r
-\r
- UINT8 IdeChannel;\r
- UINT16 CommandBlockBaseAddr;\r
- UINT16 ControlBlockBaseAddr;\r
- IDE_BASE_REGISTERS *RegisterPointer;\r
-\r
-\r
- for (IdeChannel = 0; IdeChannel < ATAPI_MAX_CHANNEL; IdeChannel++) {\r
-\r
- RegisterPointer = &AtapiScsiPrivate->AtapiIoPortRegisters[IdeChannel];\r
-\r
- //\r
- // Initialize IDE IO port addresses, including Command Block registers\r
- // and Control Block registers\r
- //\r
- CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;\r
- ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;\r
-\r
- RegisterPointer->Data = CommandBlockBaseAddr;\r
- (*(UINT16 *) &RegisterPointer->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
- RegisterPointer->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
- RegisterPointer->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
- RegisterPointer->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
- RegisterPointer->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
- RegisterPointer->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
- (*(UINT16 *) &RegisterPointer->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
-\r
- (*(UINT16 *) &RegisterPointer->Alt) = ControlBlockBaseAddr;\r
- RegisterPointer->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
- }\r
-\r
-}\r
-\r
-\r
-EFI_STATUS\r
-CheckSCSIRequestPacket (\r
- EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Checks the parameters in the SCSI Request Packet to make sure\r
- they are valid for a SCSI Pass Thru request.\r
-\r
-Arguments:\r
-\r
- Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- if (Packet == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (!ValidCdbLength (Packet->CdbLength)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (Packet->Cdb == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Checks whether the request command is supported.\r
- //\r
- if (!IsCommandValid (Packet)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-BOOLEAN\r
-IsCommandValid (\r
- EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Checks the requested SCSI command:\r
- Is it supported by this driver?\r
- Is the Data transfer direction reasonable?\r
-\r
-Arguments:\r
-\r
- Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT8 Index;\r
- UINT8 *OpCode;\r
- UINT8 ArrayLen;\r
-\r
- OpCode = (UINT8 *) (Packet->Cdb);\r
- ArrayLen = (UINT8) (ARRAY_SIZE (gSupportedATAPICommands));\r
-\r
- for (Index = 0; (Index < ArrayLen) && (CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)) != 0); Index++) {\r
-\r
- if (*OpCode == gSupportedATAPICommands[Index].OpCode) {\r
- //\r
- // Check whether the requested Command is supported by this driver\r
- //\r
- if (Packet->DataDirection == DataIn) {\r
- //\r
- // Check whether the requested data direction conforms to\r
- // what it should be.\r
- //\r
- if (gSupportedATAPICommands[Index].Direction == DataOut) {\r
- return FALSE;\r
- }\r
- }\r
-\r
- if (Packet->DataDirection == DataOut) {\r
- //\r
- // Check whether the requested data direction conforms to\r
- // what it should be.\r
- //\r
- if (gSupportedATAPICommands[Index].Direction == DataIn) {\r
- return FALSE;\r
- }\r
- }\r
-\r
- return TRUE;\r
- }\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-EFI_STATUS\r
-SubmitBlockingIoCommand (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT32 Target,\r
- EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Performs blocking I/O request.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate: Private data structure for the specified channel.\r
- Target: The Target ID of the ATAPI device to send the SCSI\r
- Request Packet. To ATAPI devices attached on an IDE\r
- Channel, Target ID 0 indicates Master device;Target\r
- ID 1 indicates Slave device.\r
- Packet: The SCSI Request Packet to send to the ATAPI device\r
- specified by Target.\r
-\r
- Returns: EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT8 PacketCommand[12];\r
- UINT64 TimeoutInMicroSeconds;\r
- EFI_STATUS PacketCommandStatus;\r
-\r
- //\r
- // Fill ATAPI Command Packet according to CDB\r
- //\r
- ZeroMem (&PacketCommand, 12);\r
- CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);\r
-\r
- //\r
- // Timeout is 100ns unit, convert it to 1000ns (1us) unit.\r
- //\r
- TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);\r
-\r
- //\r
- // Submit ATAPI Command Packet\r
- //\r
- PacketCommandStatus = AtapiPacketCommand (\r
- AtapiScsiPrivate,\r
- Target,\r
- PacketCommand,\r
- Packet->DataBuffer,\r
- &(Packet->TransferLength),\r
- (DATA_DIRECTION) Packet->DataDirection,\r
- TimeoutInMicroSeconds\r
- );\r
- if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {\r
- Packet->SenseDataLength = 0;\r
- return PacketCommandStatus;\r
- }\r
-\r
- //\r
- // Return SenseData if PacketCommandStatus matches\r
- // the following return codes.\r
- //\r
- if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||\r
- (PacketCommandStatus == EFI_DEVICE_ERROR) ||\r
- (PacketCommandStatus == EFI_TIMEOUT)) {\r
-\r
- //\r
- // avoid submit request sense command continuously.\r
- //\r
- if (PacketCommand[0] == OP_REQUEST_SENSE) {\r
- Packet->SenseDataLength = 0;\r
- return PacketCommandStatus;\r
- }\r
-\r
- RequestSenseCommand (\r
- AtapiScsiPrivate,\r
- Target,\r
- Packet->Timeout,\r
- Packet->SenseData,\r
- &Packet->SenseDataLength\r
- );\r
- }\r
-\r
- return PacketCommandStatus;\r
-}\r
-\r
-EFI_STATUS\r
-RequestSenseCommand (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT32 Target,\r
- UINT64 Timeout,\r
- VOID *SenseData,\r
- UINT8 *SenseDataLength\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Submit request sense command\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
- Target - The target ID\r
- Timeout - The time to complete the command\r
- SenseData - The buffer to fill in sense data\r
- SenseDataLength - The length of buffer\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;\r
- UINT8 Cdb[12];\r
- EFI_STATUS Status;\r
-\r
- ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
- ZeroMem (Cdb, 12);\r
-\r
- Cdb[0] = OP_REQUEST_SENSE;\r
- Cdb[4] = (UINT8) (*SenseDataLength);\r
-\r
- Packet.Timeout = Timeout;\r
- Packet.DataBuffer = SenseData;\r
- Packet.SenseData = NULL;\r
- Packet.Cdb = Cdb;\r
- Packet.TransferLength = *SenseDataLength;\r
- Packet.CdbLength = 12;\r
- Packet.DataDirection = DataIn;\r
-\r
- Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);\r
- *SenseDataLength = (UINT8) (Packet.TransferLength);\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-CheckExtSCSIRequestPacket (\r
- EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Checks the parameters in the SCSI Request Packet to make sure\r
- they are valid for a SCSI Pass Thru request.\r
-\r
-Arguments:\r
-\r
- Packet - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- if (Packet == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (!ValidCdbLength (Packet->CdbLength)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (Packet->Cdb == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Checks whether the request command is supported.\r
- //\r
- if (!IsExtCommandValid (Packet)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-BOOLEAN\r
-IsExtCommandValid (\r
- EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Checks the requested SCSI command:\r
- Is it supported by this driver?\r
- Is the Data transfer direction reasonable?\r
-\r
-Arguments:\r
-\r
- Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT8 Index;\r
- UINT8 *OpCode;\r
- UINT8 ArrayLen;\r
-\r
- OpCode = (UINT8 *) (Packet->Cdb);\r
- ArrayLen = (UINT8) (ARRAY_SIZE (gSupportedATAPICommands));\r
-\r
- for (Index = 0; (Index < ArrayLen) && (CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)) != 0); Index++) {\r
-\r
- if (*OpCode == gSupportedATAPICommands[Index].OpCode) {\r
- //\r
- // Check whether the requested Command is supported by this driver\r
- //\r
- if (Packet->DataDirection == DataIn) {\r
- //\r
- // Check whether the requested data direction conforms to\r
- // what it should be.\r
- //\r
- if (gSupportedATAPICommands[Index].Direction == DataOut) {\r
- return FALSE;\r
- }\r
- }\r
-\r
- if (Packet->DataDirection == DataOut) {\r
- //\r
- // Check whether the requested data direction conforms to\r
- // what it should be.\r
- //\r
- if (gSupportedATAPICommands[Index].Direction == DataIn) {\r
- return FALSE;\r
- }\r
- }\r
-\r
- return TRUE;\r
- }\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-EFI_STATUS\r
-SubmitExtBlockingIoCommand (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT8 Target,\r
- EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Performs blocking I/O request.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate: Private data structure for the specified channel.\r
- Target: The Target ID of the ATAPI device to send the SCSI\r
- Request Packet. To ATAPI devices attached on an IDE\r
- Channel, Target ID 0 indicates Master device;Target\r
- ID 1 indicates Slave device.\r
- Packet: The SCSI Request Packet to send to the ATAPI device\r
- specified by Target.\r
-\r
- Returns: EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT8 PacketCommand[12];\r
- UINT64 TimeoutInMicroSeconds;\r
- EFI_STATUS PacketCommandStatus;\r
-\r
- //\r
- // Fill ATAPI Command Packet according to CDB\r
- //\r
- ZeroMem (&PacketCommand, 12);\r
- CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);\r
-\r
- //\r
- // Timeout is 100ns unit, convert it to 1000ns (1us) unit.\r
- //\r
- TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);\r
-\r
- //\r
- // Submit ATAPI Command Packet\r
- //\r
- if (Packet->DataDirection == DataIn) {\r
- PacketCommandStatus = AtapiPacketCommand (\r
- AtapiScsiPrivate,\r
- Target,\r
- PacketCommand,\r
- Packet->InDataBuffer,\r
- &(Packet->InTransferLength),\r
- DataIn,\r
- TimeoutInMicroSeconds\r
- );\r
- } else {\r
-\r
- PacketCommandStatus = AtapiPacketCommand (\r
- AtapiScsiPrivate,\r
- Target,\r
- PacketCommand,\r
- Packet->OutDataBuffer,\r
- &(Packet->OutTransferLength),\r
- DataOut,\r
- TimeoutInMicroSeconds\r
- );\r
- }\r
-\r
- if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {\r
- Packet->SenseDataLength = 0;\r
- return PacketCommandStatus;\r
- }\r
-\r
- //\r
- // Return SenseData if PacketCommandStatus matches\r
- // the following return codes.\r
- //\r
- if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||\r
- (PacketCommandStatus == EFI_DEVICE_ERROR) ||\r
- (PacketCommandStatus == EFI_TIMEOUT)) {\r
-\r
- //\r
- // avoid submit request sense command continuously.\r
- //\r
- if (PacketCommand[0] == OP_REQUEST_SENSE) {\r
- Packet->SenseDataLength = 0;\r
- return PacketCommandStatus;\r
- }\r
-\r
- RequestSenseCommand (\r
- AtapiScsiPrivate,\r
- Target,\r
- Packet->Timeout,\r
- Packet->SenseData,\r
- &Packet->SenseDataLength\r
- );\r
- }\r
-\r
- return PacketCommandStatus;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-AtapiPacketCommand (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT32 Target,\r
- UINT8 *PacketCommand,\r
- VOID *Buffer,\r
- UINT32 *ByteCount,\r
- DATA_DIRECTION Direction,\r
- UINT64 TimeoutInMicroSeconds\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Submits ATAPI command packet to the specified ATAPI device.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate: Private data structure for the specified channel.\r
- Target: The Target ID of the ATAPI device to send the SCSI\r
- Request Packet. To ATAPI devices attached on an IDE\r
- Channel, Target ID 0 indicates Master device;Target\r
- ID 1 indicates Slave device.\r
- PacketCommand: Points to the ATAPI command packet.\r
- Buffer: Points to the transferred data.\r
- ByteCount: When input,indicates the buffer size; when output,\r
- indicates the actually transferred data size.\r
- Direction: Indicates the data transfer direction.\r
- TimeoutInMicroSeconds:\r
- The timeout, in micro second units, to use for the\r
- execution of this ATAPI command.\r
- A TimeoutInMicroSeconds value of 0 means that\r
- this function will wait indefinitely for the ATAPI\r
- command to execute.\r
- If TimeoutInMicroSeconds is greater than zero, then\r
- this function will return EFI_TIMEOUT if the time\r
- required to execute the ATAPI command is greater\r
- than TimeoutInMicroSeconds.\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
-\r
- UINT16 *CommandIndex;\r
- UINT8 Count;\r
- EFI_STATUS Status;\r
-\r
- //\r
- // Set all the command parameters by fill related registers.\r
- // Before write to all the following registers, BSY must be 0.\r
- //\r
- Status = StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
-\r
- //\r
- // Select device via Device/Head Register.\r
- // "Target = 0" indicates device 0; "Target = 1" indicates device 1\r
- //\r
- WritePortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Head,\r
- (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)\r
- );\r
-\r
- //\r
- // Set all the command parameters by fill related registers.\r
- // Before write to all the following registers, BSY DRQ must be 0.\r
- //\r
- Status = StatusDRQClear(AtapiScsiPrivate, TimeoutInMicroSeconds);\r
-\r
- if (EFI_ERROR (Status)) {\r
- if (Status == EFI_ABORTED) {\r
- Status = EFI_DEVICE_ERROR;\r
- }\r
- *ByteCount = 0;\r
- return Status;\r
- }\r
-\r
- //\r
- // No OVL; No DMA (by setting feature register)\r
- //\r
- WritePortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg1.Feature,\r
- 0x00\r
- );\r
-\r
- //\r
- // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device\r
- // determine how much data should be transfered.\r
- //\r
- WritePortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->CylinderLsb,\r
- (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
- );\r
- WritePortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->CylinderMsb,\r
- (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
- );\r
-\r
- //\r
- // DEFAULT_CTL:0x0a (0000,1010)\r
- // Disable interrupt\r
- //\r
- WritePortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Alt.DeviceControl,\r
- DEFAULT_CTL\r
- );\r
-\r
- //\r
- // Send Packet command to inform device\r
- // that the following data bytes are command packet.\r
- //\r
- WritePortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg.Command,\r
- PACKET_CMD\r
- );\r
-\r
- //\r
- // Before data transfer, BSY should be 0 and DRQ should be 1.\r
- // if they are not in specified time frame,\r
- // retrieve Sense Key from Error Register before return.\r
- //\r
- Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
- if (EFI_ERROR (Status)) {\r
- if (Status == EFI_ABORTED) {\r
- Status = EFI_DEVICE_ERROR;\r
- }\r
-\r
- *ByteCount = 0;\r
- return Status;\r
- }\r
-\r
- //\r
- // Send out command packet\r
- //\r
- CommandIndex = (UINT16 *) PacketCommand;\r
- for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
- WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex);\r
- }\r
-\r
- //\r
- // call AtapiPassThruPioReadWriteData() function to get\r
- // requested transfer data form device.\r
- //\r
- return AtapiPassThruPioReadWriteData (\r
- AtapiScsiPrivate,\r
- Buffer,\r
- ByteCount,\r
- Direction,\r
- TimeoutInMicroSeconds\r
- );\r
-}\r
-\r
-EFI_STATUS\r
-AtapiPassThruPioReadWriteData (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT16 *Buffer,\r
- UINT32 *ByteCount,\r
- DATA_DIRECTION Direction,\r
- UINT64 TimeoutInMicroSeconds\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Performs data transfer between ATAPI device and host after the\r
- ATAPI command packet is sent.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate: Private data structure for the specified channel.\r
- Buffer: Points to the transferred data.\r
- ByteCount: When input,indicates the buffer size; when output,\r
- indicates the actually transferred data size.\r
- Direction: Indicates the data transfer direction.\r
- TimeoutInMicroSeconds:\r
- The timeout, in micro second units, to use for the\r
- execution of this ATAPI command.\r
- A TimeoutInMicroSeconds value of 0 means that\r
- this function will wait indefinitely for the ATAPI\r
- command to execute.\r
- If TimeoutInMicroSeconds is greater than zero, then\r
- this function will return EFI_TIMEOUT if the time\r
- required to execute the ATAPI command is greater\r
- than TimeoutInMicroSeconds.\r
- Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT32 Index;\r
- UINT32 RequiredWordCount;\r
- UINT32 ActualWordCount;\r
- UINT32 WordCount;\r
- EFI_STATUS Status;\r
- UINT16 *ptrBuffer;\r
-\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Non Data transfer request is also supported.\r
- //\r
- if (*ByteCount == 0 || Buffer == NULL) {\r
- *ByteCount = 0;\r
- if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- }\r
-\r
- ptrBuffer = Buffer;\r
- RequiredWordCount = *ByteCount / 2;\r
-\r
- //\r
- // ActuralWordCount means the word count of data really transfered.\r
- //\r
- ActualWordCount = 0;\r
-\r
- while (ActualWordCount < RequiredWordCount) {\r
- //\r
- // before each data transfer stream, the host should poll DRQ bit ready,\r
- // which indicates device's ready for data transfer .\r
- //\r
- Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
- if (EFI_ERROR (Status)) {\r
- *ByteCount = ActualWordCount * 2;\r
-\r
- AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);\r
-\r
- if (ActualWordCount == 0) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // ActualWordCount > 0\r
- //\r
- if (ActualWordCount < RequiredWordCount) {\r
- return EFI_BAD_BUFFER_SIZE;\r
- }\r
- }\r
- //\r
- // get current data transfer size from Cylinder Registers.\r
- //\r
- WordCount = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8;\r
- WordCount = WordCount | ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb);\r
- WordCount = WordCount & 0xffff;\r
- WordCount /= 2;\r
-\r
- //\r
- // perform a series data In/Out.\r
- //\r
- for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {\r
-\r
- if (Direction == DataIn) {\r
-\r
- *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data);\r
- } else {\r
-\r
- WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer);\r
- }\r
-\r
- ptrBuffer++;\r
-\r
- }\r
- }\r
- //\r
- // After data transfer is completed, normally, DRQ bit should clear.\r
- //\r
- StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
-\r
- //\r
- // read status register to check whether error happens.\r
- //\r
- Status = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);\r
-\r
- *ByteCount = ActualWordCount * 2;\r
-\r
- return Status;\r
-}\r
-\r
-\r
-UINT8\r
-ReadPortB (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT16 Port\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Read one byte from a specified I/O port.\r
-\r
-Arguments:\r
-\r
- PciIo - The pointer of EFI_PCI_IO_PROTOCOL\r
- Port - IO port\r
-\r
-Returns:\r
-\r
- A byte read out\r
-\r
---*/\r
-{\r
- UINT8 Data;\r
-\r
- Data = 0;\r
- PciIo->Io.Read (\r
- PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- (UINT64) Port,\r
- 1,\r
- &Data\r
- );\r
- return Data;\r
-}\r
-\r
-\r
-UINT16\r
-ReadPortW (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT16 Port\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Read one word from a specified I/O port.\r
-\r
-Arguments:\r
-\r
- PciIo - The pointer of EFI_PCI_IO_PROTOCOL\r
- Port - IO port\r
-\r
-Returns:\r
-\r
- A word read out\r
---*/\r
-{\r
- UINT16 Data;\r
-\r
- Data = 0;\r
- PciIo->Io.Read (\r
- PciIo,\r
- EfiPciIoWidthUint16,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- (UINT64) Port,\r
- 1,\r
- &Data\r
- );\r
- return Data;\r
-}\r
-\r
-\r
-VOID\r
-WritePortB (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT16 Port,\r
- IN UINT8 Data\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Write one byte to a specified I/O port.\r
-\r
-Arguments:\r
-\r
- PciIo - The pointer of EFI_PCI_IO_PROTOCOL\r
- Port - IO port\r
- Data - The data to write\r
-\r
-Returns:\r
-\r
- NONE\r
-\r
---*/\r
-{\r
- PciIo->Io.Write (\r
- PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- (UINT64) Port,\r
- 1,\r
- &Data\r
- );\r
-}\r
-\r
-\r
-VOID\r
-WritePortW (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT16 Port,\r
- IN UINT16 Data\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Write one word to a specified I/O port.\r
-\r
-Arguments:\r
-\r
- PciIo - The pointer of EFI_PCI_IO_PROTOCOL\r
- Port - IO port\r
- Data - The data to write\r
-\r
-Returns:\r
-\r
- NONE\r
-\r
---*/\r
-{\r
- PciIo->Io.Write (\r
- PciIo,\r
- EfiPciIoWidthUint16,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- (UINT64) Port,\r
- 1,\r
- &Data\r
- );\r
-}\r
-\r
-EFI_STATUS\r
-StatusDRQClear (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT64 TimeoutInMicroSeconds\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check whether DRQ is clear in the Status Register. (BSY must also be cleared)\r
- If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
- DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is\r
- elapsed.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
- TimeoutInMicroSeconds - The time to wait for\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT64 Delay;\r
- UINT8 StatusRegister;\r
- UINT8 ErrRegister;\r
-\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- } else {\r
- Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
- }\r
-\r
- do {\r
-\r
- StatusRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg.Status\r
- );\r
-\r
- //\r
- // wait for BSY == 0 and DRQ == 0\r
- //\r
- if ((StatusRegister & (DRQ | BSY)) == 0) {\r
- break;\r
- }\r
- //\r
- // check whether the command is aborted by the device\r
- //\r
- if ((StatusRegister & (BSY | ERR)) == ERR) {\r
-\r
- ErrRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg1.Error\r
- );\r
- if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
-\r
- return EFI_ABORTED;\r
- }\r
- }\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
-\r
- //\r
- // Loop infinitely if not meeting expected condition\r
- //\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- }\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-AltStatusDRQClear (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT64 TimeoutInMicroSeconds\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check whether DRQ is clear in the Alternate Status Register.\r
- (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should\r
- wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is\r
- elapsed.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
- TimeoutInMicroSeconds - The time to wait for\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT64 Delay;\r
- UINT8 AltStatusRegister;\r
- UINT8 ErrRegister;\r
-\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- } else {\r
- Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
- }\r
-\r
- do {\r
-\r
- AltStatusRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Alt.AltStatus\r
- );\r
-\r
- //\r
- // wait for BSY == 0 and DRQ == 0\r
- //\r
- if ((AltStatusRegister & (DRQ | BSY)) == 0) {\r
- break;\r
- }\r
-\r
- if ((AltStatusRegister & (BSY | ERR)) == ERR) {\r
-\r
- ErrRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg1.Error\r
- );\r
- if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
-\r
- return EFI_ABORTED;\r
- }\r
- }\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
-\r
- //\r
- // Loop infinitely if not meeting expected condition\r
- //\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- }\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-StatusDRQReady (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT64 TimeoutInMicroSeconds\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check whether DRQ is ready in the Status Register. (BSY must also be cleared)\r
- If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
- DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is\r
- elapsed.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
- TimeoutInMicroSeconds - The time to wait for\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT64 Delay;\r
- UINT8 StatusRegister;\r
- UINT8 ErrRegister;\r
-\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- } else {\r
- Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
- }\r
-\r
- do {\r
- //\r
- // read Status Register will clear interrupt\r
- //\r
- StatusRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg.Status\r
- );\r
-\r
- //\r
- // BSY==0,DRQ==1\r
- //\r
- if ((StatusRegister & (BSY | DRQ)) == DRQ) {\r
- break;\r
- }\r
-\r
- if ((StatusRegister & (BSY | ERR)) == ERR) {\r
-\r
- ErrRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg1.Error\r
- );\r
- if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
-\r
- //\r
- // Loop infinitely if not meeting expected condition\r
- //\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- }\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-AltStatusDRQReady (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT64 TimeoutInMicroSeconds\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check whether DRQ is ready in the Alternate Status Register.\r
- (BSY must also be cleared)\r
- If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
- DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is\r
- elapsed.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
- TimeoutInMicroSeconds - The time to wait for\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT64 Delay;\r
- UINT8 AltStatusRegister;\r
- UINT8 ErrRegister;\r
-\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- } else {\r
- Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
- }\r
-\r
- do {\r
- //\r
- // read Status Register will clear interrupt\r
- //\r
- AltStatusRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Alt.AltStatus\r
- );\r
- //\r
- // BSY==0,DRQ==1\r
- //\r
- if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {\r
- break;\r
- }\r
-\r
- if ((AltStatusRegister & (BSY | ERR)) == ERR) {\r
-\r
- ErrRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg1.Error\r
- );\r
- if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
-\r
- //\r
- // Loop infinitely if not meeting expected condition\r
- //\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- }\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-StatusWaitForBSYClear (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT64 TimeoutInMicroSeconds\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check whether BSY is clear in the Status Register.\r
- If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
- BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is\r
- elapsed.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
- TimeoutInMicroSeconds - The time to wait for\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT64 Delay;\r
- UINT8 StatusRegister;\r
-\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- } else {\r
- Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
- }\r
-\r
- do {\r
-\r
- StatusRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg.Status\r
- );\r
- if ((StatusRegister & BSY) == 0x00) {\r
- break;\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
-\r
- //\r
- // Loop infinitely if not meeting expected condition\r
- //\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- }\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-AltStatusWaitForBSYClear (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT64 TimeoutInMicroSeconds\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check whether BSY is clear in the Alternate Status Register.\r
- If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
- BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is\r
- elapsed.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
- TimeoutInMicroSeconds - The time to wait for\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT64 Delay;\r
- UINT8 AltStatusRegister;\r
-\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- } else {\r
- Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
- }\r
-\r
- do {\r
-\r
- AltStatusRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Alt.AltStatus\r
- );\r
- if ((AltStatusRegister & BSY) == 0x00) {\r
- break;\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
- //\r
- // Loop infinitely if not meeting expected condition\r
- //\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- }\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-StatusDRDYReady (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT64 TimeoutInMicroSeconds\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check whether DRDY is ready in the Status Register.\r
- (BSY must also be cleared)\r
- If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
- DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is\r
- elapsed.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
- TimeoutInMicroSeconds - The time to wait for\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT64 Delay;\r
- UINT8 StatusRegister;\r
- UINT8 ErrRegister;\r
-\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- } else {\r
- Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
- }\r
-\r
- do {\r
- StatusRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg.Status\r
- );\r
- //\r
- // BSY == 0 , DRDY == 1\r
- //\r
- if ((StatusRegister & (DRDY | BSY)) == DRDY) {\r
- break;\r
- }\r
-\r
- if ((StatusRegister & (BSY | ERR)) == ERR) {\r
-\r
- ErrRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg1.Error\r
- );\r
- if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
- //\r
- // Loop infinitely if not meeting expected condition\r
- //\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- }\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-AltStatusDRDYReady (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
- UINT64 TimeoutInMicroSeconds\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check whether DRDY is ready in the Alternate Status Register.\r
- (BSY must also be cleared)\r
- If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
- DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is\r
- elapsed.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
- TimeoutInMicroSeconds - The time to wait for\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT64 Delay;\r
- UINT8 AltStatusRegister;\r
- UINT8 ErrRegister;\r
-\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- } else {\r
- Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
- }\r
-\r
- do {\r
- AltStatusRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Alt.AltStatus\r
- );\r
- //\r
- // BSY == 0 , DRDY == 1\r
- //\r
- if ((AltStatusRegister & (DRDY | BSY)) == DRDY) {\r
- break;\r
- }\r
-\r
- if ((AltStatusRegister & (BSY | ERR)) == ERR) {\r
-\r
- ErrRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg1.Error\r
- );\r
- if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
- //\r
- // Loop infinitely if not meeting expected condition\r
- //\r
- if (TimeoutInMicroSeconds == 0) {\r
- Delay = 2;\r
- }\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-AtapiPassThruCheckErrorStatus (\r
- ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check Error Register for Error Information.\r
-\r
-Arguments:\r
-\r
- AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- UINT8 StatusRegister;\r
- UINT8 ErrorRegister;\r
-\r
- StatusRegister = ReadPortB (\r
- AtapiScsiPrivate->PciIo,\r
- AtapiScsiPrivate->IoPort->Reg.Status\r
- );\r
-\r
- DEBUG_CODE_BEGIN ();\r
-\r
- if (StatusRegister & DWF) {\r
- DEBUG (\r
- (EFI_D_BLKIO,\r
- "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",\r
- StatusRegister)\r
- );\r
- }\r
-\r
- if (StatusRegister & CORR) {\r
- DEBUG (\r
- (EFI_D_BLKIO,\r
- "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",\r
- StatusRegister)\r
- );\r
- }\r
-\r
- if (StatusRegister & ERR) {\r
- ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);\r
-\r
-\r
- if (ErrorRegister & BBK_ERR) {\r
- DEBUG (\r
- (EFI_D_BLKIO,\r
- "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",\r
- ErrorRegister)\r
- );\r
- }\r
-\r
- if (ErrorRegister & UNC_ERR) {\r
- DEBUG (\r
- (EFI_D_BLKIO,\r
- "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",\r
- ErrorRegister)\r
- );\r
- }\r
-\r
- if (ErrorRegister & MC_ERR) {\r
- DEBUG (\r
- (EFI_D_BLKIO,\r
- "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",\r
- ErrorRegister)\r
- );\r
- }\r
-\r
- if (ErrorRegister & ABRT_ERR) {\r
- DEBUG (\r
- (EFI_D_BLKIO,\r
- "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",\r
- ErrorRegister)\r
- );\r
- }\r
-\r
- if (ErrorRegister & TK0NF_ERR) {\r
- DEBUG (\r
- (EFI_D_BLKIO,\r
- "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",\r
- ErrorRegister)\r
- );\r
- }\r
-\r
- if (ErrorRegister & AMNF_ERR) {\r
- DEBUG (\r
- (EFI_D_BLKIO,\r
- "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",\r
- ErrorRegister)\r
- );\r
- }\r
- }\r
-\r
- DEBUG_CODE_END ();\r
-\r
- if ((StatusRegister & (ERR | DWF | CORR)) == 0) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
-\r
- return EFI_DEVICE_ERROR;\r
-}\r
-\r
-\r
-/**\r
- Installs Scsi Pass Thru and/or Ext Scsi Pass Thru\r
- protocols based on feature flags.\r
-\r
- @param Controller The controller handle to\r
- install these protocols on.\r
- @param AtapiScsiPrivate A pointer to the protocol private\r
- data structure.\r
-\r
- @retval EFI_SUCCESS The installation succeeds.\r
- @retval other The installation fails.\r
-\r
-**/\r
-EFI_STATUS\r
-InstallScsiPassThruProtocols (\r
- IN EFI_HANDLE *ControllerHandle,\r
- IN ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;\r
- EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;\r
-\r
- ScsiPassThru = &AtapiScsiPrivate->ScsiPassThru;\r
- ExtScsiPassThru = &AtapiScsiPrivate->ExtScsiPassThru;\r
-\r
- if (FeaturePcdGet (PcdSupportScsiPassThru)) {\r
- ScsiPassThru = CopyMem (ScsiPassThru, &gScsiPassThruProtocolTemplate, sizeof (*ScsiPassThru));\r
- if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {\r
- ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- ControllerHandle,\r
- &gEfiScsiPassThruProtocolGuid,\r
- ScsiPassThru,\r
- &gEfiExtScsiPassThruProtocolGuid,\r
- ExtScsiPassThru,\r
- NULL\r
- );\r
- } else {\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- ControllerHandle,\r
- &gEfiScsiPassThruProtocolGuid,\r
- ScsiPassThru,\r
- NULL\r
- );\r
- }\r
- } else {\r
- if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {\r
- ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- ControllerHandle,\r
- &gEfiExtScsiPassThruProtocolGuid,\r
- ExtScsiPassThru,\r
- NULL\r
- );\r
- } else {\r
- //\r
- // This driver must support either ScsiPassThru or\r
- // ExtScsiPassThru protocols\r
- //\r
- ASSERT (FALSE);\r
- Status = EFI_UNSUPPORTED;\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- The user Entry Point for module AtapiPassThru. The user code starts with this function.\r
-\r
- @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
- @param[in] SystemTable A pointer to the EFI System Table.\r
-\r
- @retval EFI_SUCCESS The entry point is executed successfully.\r
- @retval other Some error occurs when executing this entry point.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-InitializeAtapiPassThru(\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- //\r
- // Install driver model protocol(s).\r
- //\r
- Status = EfiLibInstallDriverBindingComponentName2 (\r
- ImageHandle,\r
- SystemTable,\r
- &gAtapiScsiPassThruDriverBinding,\r
- ImageHandle,\r
- &gAtapiScsiPassThruComponentName,\r
- &gAtapiScsiPassThruComponentName2\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Install EFI Driver Supported EFI Version Protocol required for\r
- // EFI drivers that are on PCI and other plug in cards.\r
- //\r
- gAtapiScsiPassThruDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &ImageHandle,\r
- &gEfiDriverSupportedEfiVersionProtocolGuid,\r
- &gAtapiScsiPassThruDriverSupportedEfiVersion,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return Status;\r
-}\r