|
@@ -19,6 +19,16 @@
|
|
|
#include "be_mgmt.h"
|
|
|
#include "be_main.h"
|
|
|
|
|
|
+static void be_mcc_notify(struct beiscsi_hba *phba)
|
|
|
+{
|
|
|
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
|
|
|
+ u32 val = 0;
|
|
|
+
|
|
|
+ val |= mccq->id & DB_MCCQ_RING_ID_MASK;
|
|
|
+ val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
|
|
|
+ iowrite32(val, phba->db_va + DB_MCCQ_OFFSET);
|
|
|
+}
|
|
|
+
|
|
|
static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
|
|
|
{
|
|
|
if (compl->flags != 0) {
|
|
@@ -54,13 +64,56 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
static inline bool is_link_state_evt(u32 trailer)
|
|
|
{
|
|
|
return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
|
|
|
- ASYNC_TRAILER_EVENT_CODE_MASK) == ASYNC_EVENT_CODE_LINK_STATE);
|
|
|
+ ASYNC_TRAILER_EVENT_CODE_MASK) ==
|
|
|
+ ASYNC_EVENT_CODE_LINK_STATE);
|
|
|
+}
|
|
|
+
|
|
|
+static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba)
|
|
|
+{
|
|
|
+ struct be_queue_info *mcc_cq = &phba->ctrl.mcc_obj.cq;
|
|
|
+ struct be_mcc_compl *compl = queue_tail_node(mcc_cq);
|
|
|
+
|
|
|
+ if (be_mcc_compl_is_new(compl)) {
|
|
|
+ queue_tail_inc(mcc_cq);
|
|
|
+ return compl;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static void be2iscsi_fail_session(struct iscsi_cls_session *cls_session)
|
|
|
+{
|
|
|
+ iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
|
|
|
+}
|
|
|
+
|
|
|
+static void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
|
|
|
+ struct be_async_event_link_state *evt)
|
|
|
+{
|
|
|
+ switch (evt->port_link_status) {
|
|
|
+ case ASYNC_EVENT_LINK_DOWN:
|
|
|
+ SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n",
|
|
|
+ evt->physical_port);
|
|
|
+ phba->state |= BE_ADAPTER_LINK_DOWN;
|
|
|
+ break;
|
|
|
+ case ASYNC_EVENT_LINK_UP:
|
|
|
+ phba->state = BE_ADAPTER_UP;
|
|
|
+ SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n",
|
|
|
+ evt->physical_port);
|
|
|
+ iscsi_host_for_each_session(phba->shost,
|
|
|
+ be2iscsi_fail_session);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on"
|
|
|
+ "Physical Port %d \n",
|
|
|
+ evt->port_link_status,
|
|
|
+ evt->physical_port);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm,
|
|
|
+static void beiscsi_cq_notify(struct beiscsi_hba *phba, u16 qid, bool arm,
|
|
|
u16 num_popped)
|
|
|
{
|
|
|
u32 val = 0;
|
|
@@ -68,7 +121,66 @@ void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm,
|
|
|
if (arm)
|
|
|
val |= 1 << DB_CQ_REARM_SHIFT;
|
|
|
val |= num_popped << DB_CQ_NUM_POPPED_SHIFT;
|
|
|
- iowrite32(val, ctrl->db + DB_CQ_OFFSET);
|
|
|
+ iowrite32(val, phba->db_va + DB_CQ_OFFSET);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int be_process_mcc(struct beiscsi_hba *phba)
|
|
|
+{
|
|
|
+ struct be_mcc_compl *compl;
|
|
|
+ int num = 0, status = 0;
|
|
|
+ struct be_ctrl_info *ctrl = &phba->ctrl;
|
|
|
+
|
|
|
+ spin_lock_bh(&phba->ctrl.mcc_cq_lock);
|
|
|
+ while ((compl = be_mcc_compl_get(phba))) {
|
|
|
+ if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
|
|
|
+ /* Interpret flags as an async trailer */
|
|
|
+ BUG_ON(!is_link_state_evt(compl->flags));
|
|
|
+
|
|
|
+ /* Interpret compl as a async link evt */
|
|
|
+ beiscsi_async_link_state_process(phba,
|
|
|
+ (struct be_async_event_link_state *) compl);
|
|
|
+ } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
|
|
|
+ status = be_mcc_compl_process(ctrl, compl);
|
|
|
+ atomic_dec(&phba->ctrl.mcc_obj.q.used);
|
|
|
+ }
|
|
|
+ be_mcc_compl_use(compl);
|
|
|
+ num++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (num)
|
|
|
+ beiscsi_cq_notify(phba, phba->ctrl.mcc_obj.cq.id, true, num);
|
|
|
+
|
|
|
+ spin_unlock_bh(&phba->ctrl.mcc_cq_lock);
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/* Wait till no more pending mcc requests are present */
|
|
|
+static int be_mcc_wait_compl(struct beiscsi_hba *phba)
|
|
|
+{
|
|
|
+#define mcc_timeout 120000 /* 5s timeout */
|
|
|
+ int i, status;
|
|
|
+ for (i = 0; i < mcc_timeout; i++) {
|
|
|
+ status = be_process_mcc(phba);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ if (atomic_read(&phba->ctrl.mcc_obj.q.used) == 0)
|
|
|
+ break;
|
|
|
+ udelay(100);
|
|
|
+ }
|
|
|
+ if (i == mcc_timeout) {
|
|
|
+ dev_err(&phba->pcidev->dev, "mccq poll timed out\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* Notify MCC requests and wait for completion */
|
|
|
+int be_mcc_notify_wait(struct beiscsi_hba *phba)
|
|
|
+{
|
|
|
+ be_mcc_notify(phba);
|
|
|
+ return be_mcc_wait_compl(phba);
|
|
|
}
|
|
|
|
|
|
static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
|
|
@@ -142,6 +254,52 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Insert the mailbox address into the doorbell in two steps
|
|
|
+ * Polls on the mbox doorbell till a command completion (or a timeout) occurs
|
|
|
+ */
|
|
|
+static int be_mbox_notify_wait(struct beiscsi_hba *phba)
|
|
|
+{
|
|
|
+ int status;
|
|
|
+ u32 val = 0;
|
|
|
+ void __iomem *db = phba->ctrl.db + MPU_MAILBOX_DB_OFFSET;
|
|
|
+ struct be_dma_mem *mbox_mem = &phba->ctrl.mbox_mem;
|
|
|
+ struct be_mcc_mailbox *mbox = mbox_mem->va;
|
|
|
+ struct be_mcc_compl *compl = &mbox->compl;
|
|
|
+ struct be_ctrl_info *ctrl = &phba->ctrl;
|
|
|
+
|
|
|
+ val |= MPU_MAILBOX_DB_HI_MASK;
|
|
|
+ /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
|
|
|
+ val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
|
|
|
+ iowrite32(val, db);
|
|
|
+
|
|
|
+ /* wait for ready to be set */
|
|
|
+ status = be_mbox_db_ready_wait(ctrl);
|
|
|
+ if (status != 0)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ val = 0;
|
|
|
+ /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */
|
|
|
+ val |= (u32)(mbox_mem->dma >> 4) << 2;
|
|
|
+ iowrite32(val, db);
|
|
|
+
|
|
|
+ status = be_mbox_db_ready_wait(ctrl);
|
|
|
+ if (status != 0)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* A cq entry has been made now */
|
|
|
+ if (be_mcc_compl_is_new(compl)) {
|
|
|
+ status = be_mcc_compl_process(ctrl, &mbox->compl);
|
|
|
+ be_mcc_compl_use(compl);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+ } else {
|
|
|
+ dev_err(&phba->pcidev->dev, "invalid mailbox completion\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
|
|
|
bool embedded, u8 sge_cnt)
|
|
|
{
|
|
@@ -203,6 +361,20 @@ struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem)
|
|
|
return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb;
|
|
|
}
|
|
|
|
|
|
+struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba)
|
|
|
+{
|
|
|
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
|
|
|
+ struct be_mcc_wrb *wrb;
|
|
|
+
|
|
|
+ BUG_ON(atomic_read(&mccq->used) >= mccq->len);
|
|
|
+ wrb = queue_head_node(mccq);
|
|
|
+ queue_head_inc(mccq);
|
|
|
+ atomic_inc(&mccq->used);
|
|
|
+ memset(wrb, 0, sizeof(*wrb));
|
|
|
+ return wrb;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
|
|
|
struct be_queue_info *eq, int eq_delay)
|
|
|
{
|
|
@@ -212,6 +384,7 @@ int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
|
|
|
struct be_dma_mem *q_mem = &eq->dma_mem;
|
|
|
int status;
|
|
|
|
|
|
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_eq_create\n");
|
|
|
spin_lock(&ctrl->mbox_lock);
|
|
|
memset(wrb, 0, sizeof(*wrb));
|
|
|
|
|
@@ -249,6 +422,7 @@ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
|
|
|
int status;
|
|
|
u8 *endian_check;
|
|
|
|
|
|
+ SE_DEBUG(DBG_LVL_8, "In be_cmd_fw_initialize\n");
|
|
|
spin_lock(&ctrl->mbox_lock);
|
|
|
memset(wrb, 0, sizeof(*wrb));
|
|
|
|
|
@@ -282,6 +456,7 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
|
|
|
void *ctxt = &req->context;
|
|
|
int status;
|
|
|
|
|
|
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_cq_create \n");
|
|
|
spin_lock(&ctrl->mbox_lock);
|
|
|
memset(wrb, 0, sizeof(*wrb));
|
|
|
|
|
@@ -289,7 +464,6 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
|
|
|
|
|
|
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
|
|
|
OPCODE_COMMON_CQ_CREATE, sizeof(*req));
|
|
|
-
|
|
|
if (!q_mem->va)
|
|
|
SE_DEBUG(DBG_LVL_1, "uninitialized q_mem->va\n");
|
|
|
|
|
@@ -329,6 +503,53 @@ static u32 be_encoded_q_len(int q_len)
|
|
|
len_encoded = 0;
|
|
|
return len_encoded;
|
|
|
}
|
|
|
+
|
|
|
+int be_cmd_mccq_create(struct beiscsi_hba *phba,
|
|
|
+ struct be_queue_info *mccq,
|
|
|
+ struct be_queue_info *cq)
|
|
|
+{
|
|
|
+ struct be_mcc_wrb *wrb;
|
|
|
+ struct be_cmd_req_mcc_create *req;
|
|
|
+ struct be_dma_mem *q_mem = &mccq->dma_mem;
|
|
|
+ struct be_ctrl_info *ctrl;
|
|
|
+ void *ctxt;
|
|
|
+ int status;
|
|
|
+
|
|
|
+ spin_lock(&phba->ctrl.mbox_lock);
|
|
|
+ ctrl = &phba->ctrl;
|
|
|
+ wrb = wrb_from_mbox(&ctrl->mbox_mem);
|
|
|
+ req = embedded_payload(wrb);
|
|
|
+ ctxt = &req->context;
|
|
|
+
|
|
|
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
|
|
|
+
|
|
|
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
|
|
|
+ OPCODE_COMMON_MCC_CREATE, sizeof(*req));
|
|
|
+
|
|
|
+ req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
|
|
|
+
|
|
|
+ AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt,
|
|
|
+ PCI_FUNC(phba->pcidev->devfn));
|
|
|
+ AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1);
|
|
|
+ AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt,
|
|
|
+ be_encoded_q_len(mccq->len));
|
|
|
+ AMAP_SET_BITS(struct amap_mcc_context, cq_id, ctxt, cq->id);
|
|
|
+
|
|
|
+ be_dws_cpu_to_le(ctxt, sizeof(req->context));
|
|
|
+
|
|
|
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
|
|
|
+
|
|
|
+ status = be_mbox_notify_wait(phba);
|
|
|
+ if (!status) {
|
|
|
+ struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb);
|
|
|
+ mccq->id = le16_to_cpu(resp->id);
|
|
|
+ mccq->created = true;
|
|
|
+ }
|
|
|
+ spin_unlock(&phba->ctrl.mbox_lock);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
|
|
|
int queue_type)
|
|
|
{
|
|
@@ -337,6 +558,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
|
|
|
u8 subsys = 0, opcode = 0;
|
|
|
int status;
|
|
|
|
|
|
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_q_destroy \n");
|
|
|
spin_lock(&ctrl->mbox_lock);
|
|
|
memset(wrb, 0, sizeof(*wrb));
|
|
|
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
|
|
@@ -350,6 +572,10 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
|
|
|
subsys = CMD_SUBSYSTEM_COMMON;
|
|
|
opcode = OPCODE_COMMON_CQ_DESTROY;
|
|
|
break;
|
|
|
+ case QTYPE_MCCQ:
|
|
|
+ subsys = CMD_SUBSYSTEM_COMMON;
|
|
|
+ opcode = OPCODE_COMMON_MCC_DESTROY;
|
|
|
+ break;
|
|
|
case QTYPE_WRBQ:
|
|
|
subsys = CMD_SUBSYSTEM_ISCSI;
|
|
|
opcode = OPCODE_COMMON_ISCSI_WRBQ_DESTROY;
|
|
@@ -377,30 +603,6 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-int be_cmd_get_mac_addr(struct be_ctrl_info *ctrl, u8 *mac_addr)
|
|
|
-{
|
|
|
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
|
|
|
- struct be_cmd_req_get_mac_addr *req = embedded_payload(wrb);
|
|
|
- int status;
|
|
|
-
|
|
|
- spin_lock(&ctrl->mbox_lock);
|
|
|
- memset(wrb, 0, sizeof(*wrb));
|
|
|
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
|
|
|
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
|
|
|
- OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
|
|
|
- sizeof(*req));
|
|
|
-
|
|
|
- status = be_mbox_notify(ctrl);
|
|
|
- if (!status) {
|
|
|
- struct be_cmd_resp_get_mac_addr *resp = embedded_payload(wrb);
|
|
|
-
|
|
|
- memcpy(mac_addr, resp->mac_address, ETH_ALEN);
|
|
|
- }
|
|
|
-
|
|
|
- spin_unlock(&ctrl->mbox_lock);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
|
|
|
struct be_queue_info *cq,
|
|
|
struct be_queue_info *dq, int length,
|
|
@@ -412,6 +614,7 @@ int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
|
|
|
void *ctxt = &req->context;
|
|
|
int status;
|
|
|
|
|
|
+ SE_DEBUG(DBG_LVL_8, "In be_cmd_create_default_pdu_queue\n");
|
|
|
spin_lock(&ctrl->mbox_lock);
|
|
|
memset(wrb, 0, sizeof(*wrb));
|
|
|
|
|
@@ -468,8 +671,10 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
|
|
|
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
|
|
|
|
|
|
status = be_mbox_notify(ctrl);
|
|
|
- if (!status)
|
|
|
+ if (!status) {
|
|
|
wrbq->id = le16_to_cpu(resp->cid);
|
|
|
+ wrbq->created = true;
|
|
|
+ }
|
|
|
spin_unlock(&ctrl->mbox_lock);
|
|
|
return status;
|
|
|
}
|