summaryrefslogtreecommitdiff
path: root/Silicon/Hisilicon/Drivers/SasV1Dxe/SasV1Dxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/Hisilicon/Drivers/SasV1Dxe/SasV1Dxe.c')
-rw-r--r--Silicon/Hisilicon/Drivers/SasV1Dxe/SasV1Dxe.c1049
1 files changed, 1049 insertions, 0 deletions
diff --git a/Silicon/Hisilicon/Drivers/SasV1Dxe/SasV1Dxe.c b/Silicon/Hisilicon/Drivers/SasV1Dxe/SasV1Dxe.c
new file mode 100644
index 0000000000..18085c43c5
--- /dev/null
+++ b/Silicon/Hisilicon/Drivers/SasV1Dxe/SasV1Dxe.c
@@ -0,0 +1,1049 @@
+/** @file
+
+ Copyright (c) 2016 Linaro Ltd.
+ Copyright (c) 2016 Hisilicon Limited.
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DmaLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UncachedMemoryAllocationLib.h>
+
+#include <Protocol/PlatformSasProtocol.h>
+#include <Protocol/ScsiPassThruExt.h>
+#include <IndustryStandard/Scsi.h>
+
+#define READ_REG32(Base, Offset) MmioRead32 ((Base) + (Offset))
+#define WRITE_REG32(Base, Offset, Val) MmioWrite32 ((Base) + (Offset), (Val))
+
+#define PHY_READ_REG32(Base, Offset, phy) MmioRead32 ((Base) + (Offset) + 0x400 * (phy))
+#define PHY_WRITE_REG32(Base, Offset, phy, Val) MmioWrite32 ((Base) + (Offset) + 0x400 * (phy), (Val))
+
+#define DLVRY_QUEUE_ENABLE 0x0
+#define IOST_BASE_ADDR_LO 0x8
+#define IOST_BASE_ADDR_HI 0xc
+#define ITCT_BASE_ADDR_LO 0x10
+#define ITCT_BASE_ADDR_HI 0x14
+#define BROKEN_MSG_ADDR_LO 0x18
+#define BROKEN_MSG_ADDR_HI 0x1c
+#define PHY_CONTEXT 0x20
+#define PHY_PORT_NUM_MA 0x28
+#define HGC_TRANS_TASK_CNT_LIMIT 0x38
+#define AXI_AHB_CLK_CFG 0x3c
+#define HGC_SAS_TXFAIL_RETRY_CTRL 0x84
+#define HGC_GET_ITV_TIME 0x90
+#define DEVICE_MSG_WORK_MODE 0x94
+#define I_T_NEXUS_LOSS_TIME 0xa0
+#define BUS_INACTIVE_LIMIT_TIME 0xa8
+#define REJECT_TO_OPEN_LIMIT_TIME 0xac
+#define CFG_AGING_TIME 0xbc
+#define HGC_DFX_CFG2 0xc0
+#define FIS_LIST_BADDR_L 0xc4
+#define CFG_1US_TIMER_TRSH 0xcc
+#define CFG_SAS_CONFIG 0xd4
+#define INT_COAL_EN 0x1bc
+#define OQ_INT_COAL_TIME 0x1c0
+#define OQ_INT_COAL_CNT 0x1c4
+#define ENT_INT_COAL_TIME 0x1c8
+#define ENT_INT_COAL_CNT 0x1cc
+#define OQ_INT_SRC 0x1d0
+#define OQ_INT_SRC_MSK 0x1d4
+#define ENT_INT_SRC1 0x1d8
+#define ENT_INT_SRC2 0x1dc
+#define ENT_INT_SRC_MSK1 0x1e0
+#define ENT_INT_SRC_MSK2 0x1e4
+#define SAS_ECC_INTR_MSK 0x1ec
+#define HGC_ERR_STAT_EN 0x238
+#define DLVRY_Q_0_BASE_ADDR_LO 0x260
+#define DLVRY_Q_0_BASE_ADDR_HI 0x264
+#define DLVRY_Q_0_DEPTH 0x268
+#define DLVRY_Q_0_WR_PTR 0x26c
+#define DLVRY_Q_0_RD_PTR 0x270
+#define COMPL_Q_0_BASE_ADDR_LO 0x4e0
+#define COMPL_Q_0_BASE_ADDR_HI 0x4e4
+#define COMPL_Q_0_DEPTH 0x4e8
+#define COMPL_Q_0_WR_PTR 0x4ec
+#define COMPL_Q_0_RD_PTR 0x4f0
+#define AXI_CFG 0x5100
+
+#define PORT_BASE 0x800
+#define PHY_CFG (PORT_BASE + 0x0)
+#define PHY_CFG_ENA_OFF 0
+#define PHY_CFG_ENA_MSK (0x1 << PHY_CFG_ENA_OFF)
+#define PHY_CFG_DC_OPT_OFF 2
+#define PHY_CFG_DC_OPT_MSK (0x1 << PHY_CFG_DC_OPT_OFF)
+#define PROG_PHY_LINK_RATE (PORT_BASE + 0xc)
+#define PHY_CTRL (PORT_BASE + 0x14)
+#define PHY_CTRL_RESET BIT0
+#define PHY_RATE_NEGO (PORT_BASE + 0x30)
+#define PHY_PCN (PORT_BASE + 0x44)
+#define SL_TOUT_CFG (PORT_BASE + 0x8c)
+#define SL_CONTROL (PORT_BASE + 0x94)
+#define SL_CONTROL_NOTIFY_EN BIT0
+#define TX_ID_DWORD0 (PORT_BASE + 0x9c)
+#define TX_ID_DWORD1 (PORT_BASE + 0xa0)
+#define TX_ID_DWORD2 (PORT_BASE + 0xa4)
+#define TX_ID_DWORD3 (PORT_BASE + 0xa8)
+#define TX_ID_DWORD4 (PORT_BASE + 0xaC)
+#define TX_ID_DWORD5 (PORT_BASE + 0xb0)
+#define TX_ID_DWORD6 (PORT_BASE + 0xb4)
+#define RX_IDAF_DWORD3 (PORT_BASE + 0xd0)
+#define RX_IDAF_DWORD4 (PORT_BASE + 0xd4)
+#define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc)
+#define DONE_RECEIVED_TIME (PORT_BASE + 0x12c)
+#define CON_CFG_DRIVER (PORT_BASE + 0x130)
+#define PHY_CONFIG2 (PORT_BASE + 0x1a8)
+#define PHY_CONFIG2_FORCE_TXDEEMPH_OFF 3
+#define PHY_CONFIG2_FORCE_TXDEEMPH_MSK (0x1 << PHY_CONFIG2_FORCE_TXDEEMPH_OFF)
+#define CHL_INT_COAL_EN (PORT_BASE + 0x1d0)
+#define CHL_INT0 (PORT_BASE + 0x1b0)
+#define CHL_INT0_PHYCTRL_NOTRDY BIT0
+#define CHL_INT1 (PORT_BASE + 0x1b4)
+#define CHL_INT2 (PORT_BASE + 0x1b8)
+#define CHL_INT2_SL_PHY_ENA BIT6
+#define CHL_INT0_MSK (PORT_BASE + 0x1bc)
+#define CHL_INT0_MSK_PHYCTRL_NOTRDY BIT0
+#define CHL_INT1_MSK (PORT_BASE + 0x1c0)
+#define CHL_INT2_MSK (PORT_BASE + 0x1c4)
+#define DMA_TX_STATUS (PORT_BASE + 0x2d0)
+#define DMA_TX_STATUS_BUSY BIT0
+#define DMA_RX_STATUS (PORT_BASE + 0x2e8)
+#define DMA_RX_STATUS_BUSY BIT0
+
+#define QUEUE_CNT 32
+#define QUEUE_SLOTS 256
+#define SLOT_ENTRIES 8192
+#define PHY_CNT 8
+#define MAX_ITCT_ENTRIES 1
+
+// Completion header
+#define CMPLT_HDR_IPTT_OFF 0
+#define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF)
+
+#define BIT(x) (1 << x)
+
+// HW dma structures
+// Delivery queue header
+// dw0
+#define CMD_HDR_RESP_REPORT_OFF 5
+#define CMD_HDR_RESP_REPORT_MSK 0x20
+#define CMD_HDR_TLR_CTRL_OFF 6
+#define CMD_HDR_TLR_CTRL_MSK 0xc0
+#define CMD_HDR_PORT_OFF 17
+#define CMD_HDR_PORT_MSK 0xe0000
+#define CMD_HDR_PRIORITY_OFF 27
+#define CMD_HDR_PRIORITY_MSK 0x8000000
+#define CMD_HDR_MODE_OFF 28
+#define CMD_HDR_MODE_MSK 0x10000000
+#define CMD_HDR_CMD_OFF 29
+#define CMD_HDR_CMD_MSK 0xe0000000
+// dw1
+#define CMD_HDR_VERIFY_DTL_OFF 10
+#define CMD_HDR_VERIFY_DTL_MSK 0x400
+#define CMD_HDR_SSP_FRAME_TYPE_OFF 13
+#define CMD_HDR_SSP_FRAME_TYPE_MSK 0xe000
+#define CMD_HDR_DEVICE_ID_OFF 16
+#define CMD_HDR_DEVICE_ID_MSK 0xffff0000
+// dw2
+#define CMD_HDR_CFL_OFF 0
+#define CMD_HDR_CFL_MSK 0x1ff
+#define CMD_HDR_MRFL_OFF 15
+#define CMD_HDR_MRFL_MSK 0xff8000
+#define CMD_HDR_FIRST_BURST_OFF 25
+#define CMD_HDR_FIRST_BURST_MSK 0x2000000
+// dw3
+#define CMD_HDR_IPTT_OFF 0
+#define CMD_HDR_IPTT_MSK 0xffff
+// dw6
+#define CMD_HDR_DATA_SGL_LEN_OFF 16
+#define CMD_HDR_DATA_SGL_LEN_MSK 0xffff0000
+
+// Completion header
+#define CMPLT_HDR_IPTT_OFF 0
+#define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF)
+#define CMPLT_HDR_CMD_CMPLT_MSK BIT17
+#define CMPLT_HDR_ERR_RCRD_XFRD_MSK BIT18
+#define CMPLT_HDR_RSPNS_XFRD_MSK BIT19
+#define CMPLT_HDR_IO_CFG_ERR_MSK BIT27
+
+#define SENSE_DATA_PRES 26
+
+#define SGE_LIMIT 0x10000
+#define upper_32_bits(n) ((UINT32)(((n) >> 16) >> 16))
+#define lower_32_bits(n) ((UINT32)(n))
+#define MAX_TARGET_ID 4
+
+// Generic HW DMA host memory structures
+struct hisi_sas_cmd_hdr {
+ UINT32 dw0;
+ UINT32 dw1;
+ UINT32 dw2;
+ UINT32 transfer_tags;
+ UINT32 data_transfer_len;
+ UINT32 first_burst_num;
+ UINT32 sg_len;
+ UINT32 dw7;
+ UINT64 cmd_table_addr;
+ UINT64 sts_buffer_addr;
+ UINT64 prd_table_addr;
+ UINT64 dif_prd_table_addr;
+};
+
+struct hisi_sas_complete_hdr {
+ UINT32 data;
+};
+
+struct hisi_sas_iost {
+ UINT64 qw0;
+ UINT64 qw1;
+ UINT64 qw2;
+ UINT64 qw3;
+};
+
+struct hisi_sas_itct {
+ UINT64 qw0;
+ UINT64 sas_addr;
+ UINT64 qw2;
+ UINT64 qw3;
+ UINT64 qw4;
+ UINT64 qw_sata_ncq0_3;
+ UINT64 qw_sata_ncq7_4;
+ UINT64 qw_sata_ncq11_8;
+ UINT64 qw_sata_ncq15_12;
+ UINT64 qw_sata_ncq19_16;
+ UINT64 qw_sata_ncq23_20;
+ UINT64 qw_sata_ncq27_24;
+ UINT64 qw_sata_ncq31_28;
+ UINT64 qw_non_ncq_iptt;
+ UINT64 qw_rsvd0;
+ UINT64 qw_rsvd1;
+};
+
+struct hisi_sas_breakpoint {
+ UINT8 data[128];
+};
+
+struct hisi_sas_sge {
+ UINT64 addr;
+ UINT32 page_ctrl_0;
+ UINT32 page_ctrl_1;
+ UINT32 data_len;
+ UINT32 data_off;
+};
+
+struct hisi_sas_sge_page {
+ struct hisi_sas_sge sg[512];
+};
+
+struct hisi_sas_cmd {
+ UINT8 cmd[128];
+};
+
+struct hisi_sas_sts {
+UINT32 status[260];
+};
+
+struct hisi_sas_slot {
+ BOOLEAN used;
+};
+
+struct hisi_hba {
+ struct hisi_sas_cmd_hdr *cmd_hdr[QUEUE_CNT];
+ struct hisi_sas_complete_hdr *complete_hdr[QUEUE_CNT];
+ struct hisi_sas_sge_page *sge[QUEUE_CNT];
+ struct hisi_sas_sts *status_buf[QUEUE_CNT];
+ struct hisi_sas_cmd *command_table[QUEUE_CNT];
+ struct hisi_sas_iost *iost;
+ struct hisi_sas_itct *itct;
+ struct hisi_sas_breakpoint *breakpoint;
+ struct hisi_sas_slot *slots;
+ UINT32 base;
+ int queue;
+ int port_id;
+ UINT32 LatestTargetId;
+ UINT64 LatestLun;
+};
+
+#pragma pack (1)
+typedef struct {
+ VENDOR_DEVICE_PATH Vendor;
+ UINT64 PhysBase;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} SAS_V1_TRANSPORT_DEVICE_PATH;
+#pragma pack ()
+
+typedef struct {
+ UINT32 Signature;
+ EFI_EXT_SCSI_PASS_THRU_MODE ExtScsiPassThruMode;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL ExtScsiPassThru;
+ SAS_V1_TRANSPORT_DEVICE_PATH *DevicePath;
+ struct hisi_hba *hba;
+ EFI_EVENT TimerEvent;
+} SAS_V1_INFO;
+
+#define SAS_DEVICE_SIGNATURE SIGNATURE_32 ('S','A','S','0')
+#define SAS_FROM_PASS_THRU(a) CR (a, SAS_V1_INFO, ExtScsiPassThru, SAS_DEVICE_SIGNATURE)
+
+STATIC EFI_STATUS prepare_cmd (
+ struct hisi_hba *hba,
+ EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ )
+{
+ struct hisi_sas_slot *slot;
+ struct hisi_sas_cmd_hdr *hdr;
+ struct hisi_sas_sge_page *sge;
+ struct hisi_sas_sts *sts;
+ struct hisi_sas_cmd *cmd;
+ EFI_SCSI_SENSE_DATA *SensePtr = Packet->SenseData;
+ VOID *Buffer = NULL;
+ UINTN BufferSize = 0;
+ int queue = hba->queue;
+ UINT32 r, w = 0, slot_idx = 0;
+ UINT32 base = hba->base;
+ UINT8 *p;
+ EFI_PHYSICAL_ADDRESS BufferAddress;
+ EFI_STATUS Status = EFI_SUCCESS;
+ VOID *BufferMap = NULL;
+ DMA_MAP_OPERATION DmaOperation = MapOperationBusMasterCommonBuffer;
+
+ while (1) {
+ w = READ_REG32(base, DLVRY_Q_0_WR_PTR + (queue * 0x14));
+ r = READ_REG32(base, DLVRY_Q_0_RD_PTR + (queue * 0x14));
+ slot_idx = queue * QUEUE_SLOTS + w;
+ slot = &hba->slots[slot_idx];
+ if (slot->used || (r == (w+1) % QUEUE_SLOTS)) {
+ queue = (queue + 1) % QUEUE_CNT;
+ if (queue == hba->queue) {
+ DEBUG ((EFI_D_ERROR, "could not find free slot\n"));
+ return EFI_NOT_READY;
+ }
+ continue;
+ }
+ break;
+ }
+
+ hdr = &hba->cmd_hdr[queue][w];
+ cmd = &hba->command_table[queue][w];
+ sts = &hba->status_buf[queue][w];
+ sge = &hba->sge[queue][w];
+
+ ZeroMem (cmd, sizeof (struct hisi_sas_cmd));
+ ZeroMem (sts, sizeof (struct hisi_sas_sts));
+ if (SensePtr)
+ ZeroMem (SensePtr, sizeof (EFI_SCSI_SENSE_DATA));
+
+ slot->used = TRUE;
+ hba->queue = (queue + 1) % QUEUE_CNT;
+
+ // Only consider ssp
+ hdr->dw0 = (1 << CMD_HDR_RESP_REPORT_OFF) |
+ (0x2 << CMD_HDR_TLR_CTRL_OFF) |
+ (hba->port_id << CMD_HDR_PORT_OFF) |
+ (1 << CMD_HDR_MODE_OFF) |
+ (1 << CMD_HDR_CMD_OFF);
+ hdr->dw1 = 1 << CMD_HDR_VERIFY_DTL_OFF;
+ hdr->dw1 |= 0 << CMD_HDR_DEVICE_ID_OFF;
+ hdr->dw2 = 0x83000d;
+ hdr->transfer_tags = slot_idx << CMD_HDR_IPTT_OFF;
+
+ if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+ Buffer = Packet->InDataBuffer;
+ BufferSize = Packet->InTransferLength;
+ if (Buffer) {
+ hdr->dw1 |= 1 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ DmaOperation = MapOperationBusMasterWrite;
+ }
+ } else if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE) {
+ Buffer = Packet->OutDataBuffer;
+ BufferSize = Packet->OutTransferLength;
+ if (Buffer) {
+ DmaOperation = MapOperationBusMasterRead;
+ hdr->dw1 |= 2 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ }
+ } else {
+ hdr->dw1 |= 0 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ }
+
+ hdr->data_transfer_len = BufferSize;
+ hdr->cmd_table_addr = (UINT64)cmd;
+ hdr->sts_buffer_addr = (UINT64)sts;
+
+ CopyMem (&cmd->cmd[36], Packet->Cdb, Packet->CdbLength);
+
+ if (Buffer != NULL) {
+ struct hisi_sas_sge *sg;
+ UINT32 remain, len, pos = 0, i = 0;
+
+ Status = DmaMap (DmaOperation, Buffer, &BufferSize, &BufferAddress, &BufferMap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ remain = len = BufferSize;
+
+ while (remain) {
+ if (len > SGE_LIMIT)
+ len = SGE_LIMIT;
+ sg = &sge->sg[i];
+ sg->addr = (UINT64)(BufferAddress + pos);
+ sg->page_ctrl_0 = sg->page_ctrl_1 = 0;
+ sg->data_len = len;
+ sg->data_off = 0;
+ remain -= len;
+ pos += len;
+ len = remain;
+ i++;
+ }
+
+ hdr->prd_table_addr = (UINT64)sge;
+ hdr->sg_len = i << CMD_HDR_DATA_SGL_LEN_OFF;
+ }
+
+ // Ensure descriptor effective before start dma
+ MemoryFence();
+
+ // Start dma
+ WRITE_REG32(base, DLVRY_Q_0_WR_PTR + queue * 0x14, ++w % QUEUE_SLOTS);
+
+ // Wait for dma complete
+ while (slot->used) {
+ if (READ_REG32(base, OQ_INT_SRC) & BIT(queue)) {
+ struct hisi_sas_complete_hdr *complete_hdr;
+ UINT32 data, rd;
+ rd = READ_REG32(base, COMPL_Q_0_RD_PTR + (0x14 * queue));
+
+ complete_hdr = &hba->complete_hdr[queue][rd];
+ data = complete_hdr->data;
+
+ // Check whether dma transfer error
+ if ((data & CMPLT_HDR_ERR_RCRD_XFRD_MSK) &&
+ !(data & CMPLT_HDR_RSPNS_XFRD_MSK)) {
+ DEBUG ((EFI_D_VERBOSE, "sas retry data=0x%x\n", data));
+ DEBUG ((EFI_D_VERBOSE, "sts[0]=0x%x\n", sts->status[0]));
+ DEBUG ((EFI_D_VERBOSE, "sts[1]=0x%x\n", sts->status[1]));
+ DEBUG ((EFI_D_VERBOSE, "sts[2]=0x%x\n", sts->status[2]));
+ Status = EFI_NOT_READY;
+ // wait 1 second and retry, some disk need long time to be ready
+ // and ScsiDisk treat retry over 3 times as error
+ MicroSecondDelay(1000000);
+ }
+ // Update read point
+ WRITE_REG32(base, COMPL_Q_0_RD_PTR + (0x14 * queue), w);
+ // Clear int
+ WRITE_REG32(base, OQ_INT_SRC, BIT(queue));
+ slot->used = FALSE;
+ break;
+ }
+ // Wait for status change in polling
+ NanoSecondDelay (100);
+ }
+
+ if (BufferMap)
+ DmaUnmap (BufferMap);
+
+ p = (UINT8 *)&sts->status[0];
+ if (p[SENSE_DATA_PRES]) {
+ // Disk not ready normal return for ScsiDiskTestUnitReady do next try
+ SensePtr->Sense_Key = EFI_SCSI_SK_NOT_READY;
+ SensePtr->Addnl_Sense_Code = EFI_SCSI_ASC_NOT_READY;
+ SensePtr->Addnl_Sense_Code_Qualifier = EFI_SCSI_ASCQ_IN_PROGRESS;
+ // wait 1 second for disk spin up, refer drivers/scsi/sd.c
+ MicroSecondDelay(1000000);
+ }
+ return Status;
+}
+
+STATIC VOID hisi_sas_v1_init(struct hisi_hba *hba, PLATFORM_SAS_PROTOCOL *plat)
+{
+ int i, j;
+ UINT32 val, base = hba->base;
+
+ // Reset
+ for (i = 0; i < PHY_CNT; i++) {
+ UINT32 phy_ctrl = PHY_READ_REG32(base, PHY_CTRL, i);
+
+ phy_ctrl |= PHY_CTRL_RESET;
+ PHY_WRITE_REG32(base, PHY_CTRL, i, phy_ctrl);
+ }
+ // spec says safe to wait 50us after reset
+ MicroSecondDelay(50);
+
+ // Ensure DMA tx & rx idle
+ for (i = 0; i < PHY_CNT; i++) {
+ UINT32 dma_tx_status, dma_rx_status;
+
+ for (j = 0; j < 100; j++) {
+ dma_tx_status = PHY_READ_REG32(base, DMA_TX_STATUS, i);
+ dma_rx_status = PHY_READ_REG32(base, DMA_RX_STATUS, i);
+
+ if (!(dma_tx_status & DMA_TX_STATUS_BUSY) &&
+ !(dma_rx_status & DMA_RX_STATUS_BUSY))
+ break;
+
+ // Wait for status change in polling
+ NanoSecondDelay (100);
+ }
+ }
+
+ // Ensure axi bus idle
+ for (j = 0; j < 100; j++) {
+ UINT32 axi_status = READ_REG32(base, AXI_CFG);
+ if (axi_status == 0)
+ break;
+
+ // Wait for status change in polling
+ NanoSecondDelay (100);
+ }
+
+ plat->Init(plat);
+
+ WRITE_REG32(base, DLVRY_QUEUE_ENABLE, 0xffffffff);
+ WRITE_REG32(base, HGC_TRANS_TASK_CNT_LIMIT, 0x11);
+ WRITE_REG32(base, DEVICE_MSG_WORK_MODE, 0x1);
+ WRITE_REG32(base, HGC_SAS_TXFAIL_RETRY_CTRL, 0x1ff);
+ WRITE_REG32(base, HGC_ERR_STAT_EN, 0x401);
+ WRITE_REG32(base, CFG_1US_TIMER_TRSH, 0x64);
+ WRITE_REG32(base, HGC_GET_ITV_TIME, 0x1);
+ WRITE_REG32(base, I_T_NEXUS_LOSS_TIME, 0x64);
+ WRITE_REG32(base, BUS_INACTIVE_LIMIT_TIME, 0x2710);
+ WRITE_REG32(base, REJECT_TO_OPEN_LIMIT_TIME, 0x1);
+ WRITE_REG32(base, CFG_AGING_TIME, 0x7a12);
+ WRITE_REG32(base, HGC_DFX_CFG2, 0x9c40);
+ WRITE_REG32(base, FIS_LIST_BADDR_L, 0x2);
+ WRITE_REG32(base, INT_COAL_EN, 0xc);
+ WRITE_REG32(base, OQ_INT_COAL_TIME, 0x186a0);
+ WRITE_REG32(base, OQ_INT_COAL_CNT, 1);
+ WRITE_REG32(base, ENT_INT_COAL_TIME, 0x1);
+ WRITE_REG32(base, ENT_INT_COAL_CNT, 0x1);
+ WRITE_REG32(base, OQ_INT_SRC, 0xffffffff);
+ WRITE_REG32(base, ENT_INT_SRC1, 0xffffffff);
+ WRITE_REG32(base, ENT_INT_SRC_MSK1, 0);
+ WRITE_REG32(base, ENT_INT_SRC2, 0xffffffff);
+ WRITE_REG32(base, ENT_INT_SRC_MSK2, 0);
+ WRITE_REG32(base, SAS_ECC_INTR_MSK, 0);
+ WRITE_REG32(base, AXI_AHB_CLK_CFG, 0x2);
+ WRITE_REG32(base, CFG_SAS_CONFIG, 0x22000000);
+
+ for (i = 0; i < PHY_CNT; i++) {
+ PHY_WRITE_REG32(base, PROG_PHY_LINK_RATE, i, 0x88a);
+ PHY_WRITE_REG32(base, PHY_CONFIG2, i, 0x7c080);
+ PHY_WRITE_REG32(base, PHY_RATE_NEGO, i, 0x415ee00);
+ PHY_WRITE_REG32(base, PHY_PCN, i, 0x80a80000);
+ PHY_WRITE_REG32(base, SL_TOUT_CFG, i, 0x7d7d7d7d);
+ PHY_WRITE_REG32(base, DONE_RECEIVED_TIME, i, 0x0);
+ PHY_WRITE_REG32(base, RXOP_CHECK_CFG_H, i, 0x1000);
+ PHY_WRITE_REG32(base, DONE_RECEIVED_TIME, i, 0);
+ PHY_WRITE_REG32(base, CON_CFG_DRIVER, i, 0x13f0a);
+ PHY_WRITE_REG32(base, CHL_INT_COAL_EN, i, 3);
+ PHY_WRITE_REG32(base, DONE_RECEIVED_TIME, i, 8);
+ }
+
+ for (i = 0; i < QUEUE_CNT; i++) {
+ WRITE_REG32(base, DLVRY_Q_0_BASE_ADDR_HI + (i * 0x14), upper_32_bits((UINT64)(hba->cmd_hdr[i])));
+ WRITE_REG32(base, DLVRY_Q_0_BASE_ADDR_LO + (i * 0x14), lower_32_bits((UINT64)(hba->cmd_hdr[i])));
+ WRITE_REG32(base, DLVRY_Q_0_DEPTH + (i * 0x14), QUEUE_SLOTS);
+
+ WRITE_REG32(base, COMPL_Q_0_BASE_ADDR_HI + (i * 0x14), upper_32_bits((UINT64)(hba->complete_hdr[i])));
+ WRITE_REG32(base, COMPL_Q_0_BASE_ADDR_LO + (i * 0x14), lower_32_bits((UINT64)(hba->complete_hdr[i])));
+ WRITE_REG32(base, COMPL_Q_0_DEPTH + (i * 0x14), QUEUE_SLOTS);
+ }
+
+ WRITE_REG32(base, ITCT_BASE_ADDR_LO, lower_32_bits((UINT64)(hba->itct)));
+ WRITE_REG32(base, ITCT_BASE_ADDR_HI, upper_32_bits((UINT64)(hba->itct)));
+
+ WRITE_REG32(base, IOST_BASE_ADDR_LO, lower_32_bits((UINT64)(hba->iost)));
+ WRITE_REG32(base, IOST_BASE_ADDR_HI, upper_32_bits((UINT64)(hba->iost)));
+
+ WRITE_REG32(base, BROKEN_MSG_ADDR_LO, lower_32_bits((UINT64)(hba->breakpoint)));
+ WRITE_REG32(base, BROKEN_MSG_ADDR_HI, upper_32_bits((UINT64)(hba->breakpoint)));
+
+ for (i = 0; i < PHY_CNT; i++) {
+ // Clear interrupt status
+ val = PHY_READ_REG32(base, CHL_INT0, i);
+ PHY_WRITE_REG32(base, CHL_INT0, i, val);
+ val = PHY_READ_REG32(base, CHL_INT1, i);
+ PHY_WRITE_REG32(base, CHL_INT1, i, val);
+ val = PHY_READ_REG32(base, CHL_INT2, i);
+ PHY_WRITE_REG32(base, CHL_INT2, i, val);
+
+ // Bypass chip bug mask abnormal intr
+ PHY_WRITE_REG32(base, CHL_INT0_MSK, i, 0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY);
+ }
+
+ // Init phy
+ for (i = 0; i < PHY_CNT; i++) {
+ PHY_WRITE_REG32(base, TX_ID_DWORD0, i, 0x10010e00);
+ PHY_WRITE_REG32(base, TX_ID_DWORD1, i, 0x16);
+ PHY_WRITE_REG32(base, TX_ID_DWORD2, i, 0x20880150);
+ PHY_WRITE_REG32(base, TX_ID_DWORD3, i, 0x16);
+ PHY_WRITE_REG32(base, TX_ID_DWORD4, i, 0x20880150);
+ PHY_WRITE_REG32(base, TX_ID_DWORD5, i, 0x0);
+
+ val = PHY_READ_REG32(base, PHY_CFG, i);
+ val &= ~PHY_CFG_DC_OPT_MSK;
+ val |= 1 << PHY_CFG_DC_OPT_OFF;
+ PHY_WRITE_REG32(base, PHY_CFG, i, val);
+
+ val = PHY_READ_REG32(base, PHY_CONFIG2, i);
+ val &= ~PHY_CONFIG2_FORCE_TXDEEMPH_MSK;
+ PHY_WRITE_REG32(base, PHY_CONFIG2, i, val);
+
+ val = PHY_READ_REG32(base, PHY_CFG, i);
+ val |= PHY_CFG_ENA_MSK;
+ PHY_WRITE_REG32(base, PHY_CFG, i, val);
+ }
+}
+
+STATIC VOID sas_init(SAS_V1_INFO *SasV1Info, PLATFORM_SAS_PROTOCOL *plat)
+{
+ struct hisi_hba *hba = SasV1Info->hba;
+ int i, s;
+
+ for (i = 0; i < QUEUE_CNT; i++) {
+ s = sizeof(struct hisi_sas_cmd_hdr) * QUEUE_SLOTS;
+ DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (s), (VOID *)&hba->cmd_hdr[i]);
+ ASSERT (hba->cmd_hdr[i] != NULL);
+ ZeroMem (hba->cmd_hdr[i], s);
+
+ s = sizeof(struct hisi_sas_complete_hdr) * QUEUE_SLOTS;
+ DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (s), (VOID *)&hba->complete_hdr[i]);
+ ASSERT (hba->complete_hdr[i] != NULL);
+ ZeroMem (hba->complete_hdr[i], s);
+
+ s = sizeof(struct hisi_sas_sts) * QUEUE_SLOTS;
+ DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (s), (VOID *)&hba->status_buf[i]);
+ ASSERT (hba->status_buf[i] != NULL);
+ ZeroMem (hba->status_buf[i], s);
+
+ s = sizeof(struct hisi_sas_cmd) * QUEUE_SLOTS;
+ DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (s), (VOID *)&hba->command_table[i]);
+ ASSERT (hba->command_table[i] != NULL);
+ ZeroMem (hba->command_table[i], s);
+
+ s = sizeof(struct hisi_sas_sge_page) * QUEUE_SLOTS;
+ DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (s), (VOID *)&hba->sge[i]);
+ ASSERT (hba->sge[i] != NULL);
+ ZeroMem (hba->sge[i], s);
+ }
+
+ s = SLOT_ENTRIES * sizeof(struct hisi_sas_iost);
+ DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (s), (VOID *)&hba->iost);
+ ASSERT (hba->iost != NULL);
+ ZeroMem (hba->iost, s);
+
+ s = SLOT_ENTRIES * sizeof(struct hisi_sas_breakpoint);
+ DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (s), (VOID *)&hba->breakpoint);
+ ASSERT (hba->breakpoint != NULL);
+ ZeroMem (hba->breakpoint, s);
+
+ s = MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+ DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (s), (VOID *)&hba->itct);
+ ASSERT (hba->itct != NULL);
+ ZeroMem (hba->itct, s);
+
+ hba->slots = AllocateZeroPool (SLOT_ENTRIES * sizeof(struct hisi_sas_slot));
+ ASSERT (hba->slots != NULL);
+
+ hisi_sas_v1_init(hba, plat);
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+SasV1ExtScsiPassThruFunction (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ SAS_V1_INFO *SasV1Info = SAS_FROM_PASS_THRU(This);
+ struct hisi_hba *hba = SasV1Info->hba;
+
+ return prepare_cmd(hba, Packet);
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+SasV1ExtScsiPassThruGetNextTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target,
+ IN OUT UINT64 *Lun
+ )
+{
+ SAS_V1_INFO *SasV1Info = SAS_FROM_PASS_THRU(This);
+ struct hisi_hba *hba = SasV1Info->hba;
+ UINT8 ScsiId[TARGET_MAX_BYTES];
+ UINT8 TargetId;
+
+ if (*Target == NULL || Lun == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);
+
+ TargetId = (*Target)[0];
+
+ if (TargetId == MAX_TARGET_ID) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0) {
+ SetMem (*Target, TARGET_MAX_BYTES,0);
+ } else {
+ (*Target)[0] = (UINT8) (hba->LatestTargetId + 1);
+ }
+
+ *Lun = 0;
+
+ //
+ // Update the LatestTargetId.
+ //
+ hba->LatestTargetId = (*Target)[0];
+ hba->LatestLun = *Lun;
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+SasV1ExtScsiPassThruBuildDevicePath (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ SAS_V1_INFO *SasV1Info = SAS_FROM_PASS_THRU(This);
+
+ *DevicePath = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL *)(SasV1Info->DevicePath));
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+SasV1ExtScsiPassThruGetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 **Target,
+ OUT UINT64 *Lun
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+SasV1ExtScsiPassThruResetChannel (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
+ )
+{
+
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+SasV1ExtScsiPassThruResetTarget (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun
+ )
+{
+
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+SasV1ExtScsiPassThruGetNextTarget (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target
+ )
+{
+
+ return EFI_UNSUPPORTED;
+}
+
+STATIC EFI_EXT_SCSI_PASS_THRU_PROTOCOL SasV1ExtScsiPassThruProtocolTemplate = {
+ NULL,
+ SasV1ExtScsiPassThruFunction,
+ SasV1ExtScsiPassThruGetNextTargetLun,
+ SasV1ExtScsiPassThruBuildDevicePath,
+ SasV1ExtScsiPassThruGetTargetLun,
+ SasV1ExtScsiPassThruResetChannel,
+ SasV1ExtScsiPassThruResetTarget,
+ SasV1ExtScsiPassThruGetNextTarget
+};
+
+EFI_STATUS
+EFIAPI
+SasDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ PLATFORM_SAS_PROTOCOL *plat;
+ EFI_STATUS Status;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gPlatformSasProtocolGuid,
+ (VOID **) &plat,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the Sas Host used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gPlatformSasProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SasDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ PLATFORM_SAS_PROTOCOL *plat;
+ SAS_V1_INFO *SasV1Info = NULL;
+ SAS_V1_TRANSPORT_DEVICE_PATH *DevicePath;
+ UINT32 val, base;
+ int i, phy_id = 0;
+ struct hisi_sas_itct *itct;
+ struct hisi_hba *hba;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gPlatformSasProtocolGuid,
+ (VOID **) &plat,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+ return Status;
+ }
+
+ SasV1Info = AllocateZeroPool (sizeof (SAS_V1_INFO));
+ ASSERT (SasV1Info);
+ SasV1Info->Signature = SAS_DEVICE_SIGNATURE;
+
+ SasV1Info->hba = AllocateZeroPool (sizeof(struct hisi_hba));
+ ASSERT (SasV1Info->hba);
+ hba = SasV1Info->hba;
+ base = hba->base = plat->BaseAddr;
+
+ sas_init(SasV1Info, plat);
+
+ // Wait for sas controller phyup happen
+ MicroSecondDelay(100000);
+
+ for (i = 0; i < PHY_CNT; i++) {
+ val = PHY_READ_REG32(base, CHL_INT2, i);
+
+ if (val & CHL_INT2_SL_PHY_ENA) {
+ phy_id = i;
+ }
+ }
+
+ itct = &hba->itct[0]; //device_id = 0
+
+ hba->port_id = (READ_REG32(base, PHY_PORT_NUM_MA) >> (4 * phy_id)) & 0xf;
+ // Setup itct
+ itct->qw0 = 0x355;
+ itct->sas_addr = PHY_READ_REG32(base, RX_IDAF_DWORD3, phy_id);
+ itct->sas_addr = itct->sas_addr << 32 | PHY_READ_REG32(base, RX_IDAF_DWORD4, phy_id);
+ itct->qw2 = 0;
+
+ // Clear phyup
+ PHY_WRITE_REG32(base, CHL_INT2, phy_id, CHL_INT2_SL_PHY_ENA);
+ val = PHY_READ_REG32(base, CHL_INT0, phy_id);
+ val &= ~CHL_INT0_PHYCTRL_NOTRDY;
+ PHY_WRITE_REG32(base, CHL_INT0, phy_id, val);
+ PHY_WRITE_REG32(base, CHL_INT0_MSK, phy_id, 0x3ce3ee);
+
+ // Need notify
+ val = PHY_READ_REG32(base, SL_CONTROL, phy_id);
+ val |= SL_CONTROL_NOTIFY_EN;
+ PHY_WRITE_REG32(base, SL_CONTROL, phy_id, val);
+ // wait 100ms required for notify takes effect, refer drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+ MicroSecondDelay(100000);
+ val = PHY_READ_REG32(base, SL_CONTROL, phy_id);
+ val &= ~SL_CONTROL_NOTIFY_EN;
+ PHY_WRITE_REG32(base, SL_CONTROL, phy_id, val);
+
+ CopyMem (&SasV1Info->ExtScsiPassThru, &SasV1ExtScsiPassThruProtocolTemplate, sizeof (EFI_EXT_SCSI_PASS_THRU_PROTOCOL));
+ SasV1Info->ExtScsiPassThruMode.AdapterId = 2;
+ SasV1Info->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
+ SasV1Info->ExtScsiPassThruMode.IoAlign = 64; //cache line align
+ SasV1Info->ExtScsiPassThru.Mode = &SasV1Info->ExtScsiPassThruMode;
+
+ DevicePath = (SAS_V1_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ sizeof (SAS_V1_TRANSPORT_DEVICE_PATH));
+ ASSERT (DevicePath != NULL);
+ SasV1Info->DevicePath = DevicePath;
+
+ CopyMem (&DevicePath->Vendor.Guid, &gPlatformSasProtocolGuid, sizeof (EFI_GUID));
+ DevicePath->PhysBase = base;
+ SetDevicePathNodeLength (&DevicePath->Vendor,
+ sizeof (*DevicePath) - sizeof (DevicePath->End));
+ SetDevicePathEndNode (&DevicePath->End);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiDevicePathProtocolGuid, DevicePath,
+ &gEfiExtScsiPassThruProtocolGuid, &SasV1Info->ExtScsiPassThru,
+ NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SasDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ SAS_V1_INFO *SasV1Info;
+ EFI_STATUS Status;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsi;
+ int i, s;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ (VOID **) &ExtScsi,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SasV1Info = SAS_FROM_PASS_THRU(ExtScsi);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ SasV1Info->DevicePath,
+ &gEfiExtScsiPassThruProtocolGuid,
+ &SasV1Info->ExtScsiPassThru,
+ NULL);
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gPlatformSasProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseEvent (SasV1Info->TimerEvent);
+
+ for (i = 0; i < QUEUE_CNT; i++) {
+ s = sizeof(struct hisi_sas_cmd_hdr) * QUEUE_SLOTS;
+ DmaFreeBuffer(EFI_SIZE_TO_PAGES (s), (VOID *)SasV1Info->hba->cmd_hdr[i]);
+ s = sizeof(struct hisi_sas_complete_hdr) * QUEUE_SLOTS;
+ DmaFreeBuffer(EFI_SIZE_TO_PAGES (s), (VOID *)SasV1Info->hba->complete_hdr[i]);
+ s = sizeof(struct hisi_sas_sts) * QUEUE_SLOTS;
+ DmaFreeBuffer(EFI_SIZE_TO_PAGES (s), (VOID *)SasV1Info->hba->status_buf[i]);
+ s = sizeof(struct hisi_sas_cmd) * QUEUE_SLOTS;
+ DmaFreeBuffer(EFI_SIZE_TO_PAGES (s), (VOID *)SasV1Info->hba->command_table[i]);
+ s = sizeof(struct hisi_sas_sge_page) * QUEUE_SLOTS;
+ DmaFreeBuffer(EFI_SIZE_TO_PAGES (s), (VOID *)SasV1Info->hba->sge[i]);
+ }
+
+ s = SLOT_ENTRIES * sizeof(struct hisi_sas_iost);
+ DmaFreeBuffer(EFI_SIZE_TO_PAGES (s), (VOID *)SasV1Info->hba->iost);
+ s = SLOT_ENTRIES * sizeof(struct hisi_sas_breakpoint);
+ DmaFreeBuffer(EFI_SIZE_TO_PAGES (s), (VOID *)SasV1Info->hba->breakpoint);
+ s = MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+ DmaFreeBuffer(EFI_SIZE_TO_PAGES (s), (VOID *)SasV1Info->hba->itct);
+
+ FreePool (SasV1Info->hba->slots);
+ FreePool (SasV1Info->hba);
+ FreePool (SasV1Info);
+ return EFI_SUCCESS;
+ }
+ return Status;
+}
+
+EFI_DRIVER_BINDING_PROTOCOL gSasDriverBinding = {
+ SasDriverBindingSupported,
+ SasDriverBindingStart,
+ SasDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_STATUS
+SasV1Initialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSasDriverBinding,
+ ImageHandle,
+ NULL,
+ NULL
+ );
+}