]> Pileus Git - ~andy/linux/blobdiff - drivers/scsi/be2iscsi/be_cmds.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
[~andy/linux] / drivers / scsi / be2iscsi / be_cmds.c
index e66aa7c11a8a21e041f8956c6ed0f758401c8420..3338391b64de9b1aba50844c014f7e5fc44706b3 100644 (file)
@@ -17,9 +17,9 @@
 
 #include <scsi/iscsi_proto.h>
 
+#include "be_main.h"
 #include "be.h"
 #include "be_mgmt.h"
-#include "be_main.h"
 
 int beiscsi_pci_soft_reset(struct beiscsi_hba *phba)
 {
@@ -158,8 +158,10 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
        struct be_cmd_resp_hdr *ioctl_resp_hdr;
        struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
 
-       if (beiscsi_error(phba))
+       if (beiscsi_error(phba)) {
+               free_mcc_tag(&phba->ctrl, tag);
                return -EIO;
+       }
 
        /* wait for the mccq completion */
        rc = wait_event_interruptible_timeout(
@@ -173,7 +175,11 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
                            BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
                            BEISCSI_LOG_CONFIG,
                            "BC_%d : MBX Cmd Completion timed out\n");
-               rc = -EAGAIN;
+               rc = -EBUSY;
+
+               /* decrement the mccq used count */
+               atomic_dec(&phba->ctrl.mcc_obj.q.used);
+
                goto release_mcc_tag;
        } else
                rc = 0;
@@ -208,10 +214,18 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
 
                if (status == MCC_STATUS_INSUFFICIENT_BUFFER) {
                        ioctl_resp_hdr = (struct be_cmd_resp_hdr *) ioctl_hdr;
-                       if (ioctl_resp_hdr->response_length)
-                               goto release_mcc_tag;
+                       beiscsi_log(phba, KERN_WARNING,
+                                   BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
+                                   BEISCSI_LOG_CONFIG,
+                                   "BC_%d : Insufficent Buffer Error "
+                                   "Resp_Len : %d Actual_Resp_Len : %d\n",
+                                   ioctl_resp_hdr->response_length,
+                                   ioctl_resp_hdr->actual_resp_len);
+
+                       rc = -EAGAIN;
+                       goto release_mcc_tag;
                }
-               rc = -EAGAIN;
+               rc = -EIO;
        }
 
 release_mcc_tag:
@@ -363,7 +377,7 @@ void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
        } else if ((evt->port_link_status & ASYNC_EVENT_LINK_UP) ||
                    ((evt->port_link_status & ASYNC_EVENT_LOGICAL) &&
                     (evt->port_fault == BEISCSI_PHY_LINK_FAULT_NONE))) {
-               phba->state = BE_ADAPTER_UP;
+               phba->state = BE_ADAPTER_LINK_UP;
 
                beiscsi_log(phba, KERN_ERR,
                            BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT,
@@ -486,33 +500,47 @@ int be_mcc_notify_wait(struct beiscsi_hba *phba)
  **/
 static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
 {
+#define BEISCSI_MBX_RDY_BIT_TIMEOUT    4000    /* 4sec */
        void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
        struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
-       uint32_t wait = 0;
+       unsigned long timeout;
+       bool read_flag = false;
+       int ret = 0, i;
        u32 ready;
+       DECLARE_WAIT_QUEUE_HEAD_ONSTACK(rdybit_check_q);
 
-       do {
+       if (beiscsi_error(phba))
+               return -EIO;
 
-               if (beiscsi_error(phba))
-                       return -EIO;
+       timeout = jiffies + (HZ * 110);
 
-               ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
-               if (ready)
-                       break;
+       do {
+               for (i = 0; i < BEISCSI_MBX_RDY_BIT_TIMEOUT; i++) {
+                       ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
+                       if (ready) {
+                               read_flag = true;
+                               break;
+                       }
+                       mdelay(1);
+               }
 
-               if (wait > BEISCSI_HOST_MBX_TIMEOUT) {
-                       beiscsi_log(phba, KERN_ERR,
-                                   BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                                   "BC_%d : FW Timed Out\n");
+               if (!read_flag) {
+                       wait_event_timeout(rdybit_check_q,
+                                         (read_flag != true),
+                                          HZ * 5);
+               }
+       } while ((time_before(jiffies, timeout)) && !read_flag);
+
+       if (!read_flag) {
+               beiscsi_log(phba, KERN_ERR,
+                           BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+                           "BC_%d : FW Timed Out\n");
                        phba->fw_timeout = true;
                        beiscsi_ue_detect(phba);
-                       return -EBUSY;
-               }
+                       ret = -EBUSY;
+       }
 
-               mdelay(1);
-               wait++;
-       } while (true);
-       return 0;
+       return ret;
 }
 
 /*
@@ -699,7 +727,7 @@ 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);
+       WARN_ON(atomic_read(&mccq->used) >= mccq->len);
        wrb = queue_head_node(mccq);
        memset(wrb, 0, sizeof(*wrb));
        wrb->tag0 = (mccq->head & 0x000000FF) << 16;
@@ -1009,10 +1037,29 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
        return status;
 }
 
+/**
+ * be_cmd_create_default_pdu_queue()- Create DEFQ for the adapter
+ * @ctrl: ptr to ctrl_info
+ * @cq: Completion Queue
+ * @dq: Default Queue
+ * @lenght: ring size
+ * @entry_size: size of each entry in DEFQ
+ * @is_header: Header or Data DEFQ
+ * @ulp_num: Bind to which ULP
+ *
+ * Create HDR/Data DEFQ for the passed ULP. Unsol PDU are posted
+ * on this queue by the FW
+ *
+ * return
+ *     Success: 0
+ *     Failure: Non-Zero Value
+ *
+ **/
 int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
                                    struct be_queue_info *cq,
                                    struct be_queue_info *dq, int length,
-                                   int entry_size)
+                                   int entry_size, uint8_t is_header,
+                                   uint8_t ulp_num)
 {
        struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
        struct be_defq_create_req *req = embedded_payload(wrb);
@@ -1030,6 +1077,11 @@ int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
                           OPCODE_COMMON_ISCSI_DEFQ_CREATE, sizeof(*req));
 
        req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+       if (phba->fw_config.dual_ulp_aware) {
+               req->ulp_num = ulp_num;
+               req->dua_feature |= (1 << BEISCSI_DUAL_ULP_AWARE_BIT);
+               req->dua_feature |= (1 << BEISCSI_BIND_Q_TO_ULP_BIT);
+       }
 
        if (is_chip_be2_be3r(phba)) {
                AMAP_SET_BITS(struct amap_be_default_pdu_context,
@@ -1067,22 +1119,53 @@ int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
 
        status = be_mbox_notify(ctrl);
        if (!status) {
+               struct be_ring *defq_ring;
                struct be_defq_create_resp *resp = embedded_payload(wrb);
 
                dq->id = le16_to_cpu(resp->id);
                dq->created = true;
+               if (is_header)
+                       defq_ring = &phba->phwi_ctrlr->default_pdu_hdr[ulp_num];
+               else
+                       defq_ring = &phba->phwi_ctrlr->
+                                   default_pdu_data[ulp_num];
+
+               defq_ring->id = dq->id;
+
+               if (!phba->fw_config.dual_ulp_aware) {
+                       defq_ring->ulp_num = BEISCSI_ULP0;
+                       defq_ring->doorbell_offset = DB_RXULP0_OFFSET;
+               } else {
+                       defq_ring->ulp_num = resp->ulp_num;
+                       defq_ring->doorbell_offset = resp->doorbell_offset;
+               }
        }
        spin_unlock(&ctrl->mbox_lock);
 
        return status;
 }
 
-int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
-                      struct be_queue_info *wrbq)
+/**
+ * be_cmd_wrbq_create()- Create WRBQ
+ * @ctrl: ptr to ctrl_info
+ * @q_mem: memory details for the queue
+ * @wrbq: queue info
+ * @pwrb_context: ptr to wrb_context
+ * @ulp_num: ULP on which the WRBQ is to be created
+ *
+ * Create WRBQ on the passed ULP_NUM.
+ *
+ **/
+int be_cmd_wrbq_create(struct be_ctrl_info *ctrl,
+                       struct be_dma_mem *q_mem,
+                       struct be_queue_info *wrbq,
+                       struct hwi_wrb_context *pwrb_context,
+                       uint8_t ulp_num)
 {
        struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
        struct be_wrbq_create_req *req = embedded_payload(wrb);
        struct be_wrbq_create_resp *resp = embedded_payload(wrb);
+       struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
        int status;
 
        spin_lock(&ctrl->mbox_lock);
@@ -1093,17 +1176,78 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
                OPCODE_COMMON_ISCSI_WRBQ_CREATE, sizeof(*req));
        req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+
+       if (phba->fw_config.dual_ulp_aware) {
+               req->ulp_num = ulp_num;
+               req->dua_feature |= (1 << BEISCSI_DUAL_ULP_AWARE_BIT);
+               req->dua_feature |= (1 << BEISCSI_BIND_Q_TO_ULP_BIT);
+       }
+
        be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
 
        status = be_mbox_notify(ctrl);
        if (!status) {
                wrbq->id = le16_to_cpu(resp->cid);
                wrbq->created = true;
+
+               pwrb_context->cid = wrbq->id;
+               if (!phba->fw_config.dual_ulp_aware) {
+                       pwrb_context->doorbell_offset = DB_TXULP0_OFFSET;
+                       pwrb_context->ulp_num = BEISCSI_ULP0;
+               } else {
+                       pwrb_context->ulp_num = resp->ulp_num;
+                       pwrb_context->doorbell_offset = resp->doorbell_offset;
+               }
        }
        spin_unlock(&ctrl->mbox_lock);
        return status;
 }
 
+int be_cmd_iscsi_post_template_hdr(struct be_ctrl_info *ctrl,
+                                   struct be_dma_mem *q_mem)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_post_template_pages_req *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_COMMON,
+                          OPCODE_COMMON_ADD_TEMPLATE_HEADER_BUFFERS,
+                          sizeof(*req));
+
+       req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+       req->type = BEISCSI_TEMPLATE_HDR_TYPE_ISCSI;
+       be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+       status = be_mbox_notify(ctrl);
+       spin_unlock(&ctrl->mbox_lock);
+       return status;
+}
+
+int be_cmd_iscsi_remove_template_hdr(struct be_ctrl_info *ctrl)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_remove_template_pages_req *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_COMMON,
+                          OPCODE_COMMON_REMOVE_TEMPLATE_HEADER_BUFFERS,
+                          sizeof(*req));
+
+       req->type = BEISCSI_TEMPLATE_HDR_TYPE_ISCSI;
+
+       status = be_mbox_notify(ctrl);
+       spin_unlock(&ctrl->mbox_lock);
+       return status;
+}
+
 int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
                                struct be_dma_mem *q_mem,
                                u32 page_offset, u32 num_pages)