/** @file
|
|
Copyright (c) 2016 Linaro Ltd.
|
Copyright (c) 2016 Hisilicon Limited.
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
#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 <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
|
);
|
}
|