diff options
Diffstat (limited to 'drivers/scsi/be2iscsi/be_cmds.c')
-rw-r--r-- | drivers/scsi/be2iscsi/be_cmds.c | 263 |
1 files changed, 234 insertions, 29 deletions
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 08007b6e42df..10f8fe7a38d2 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -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; } |