Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma
[linux-2.6-block.git] / drivers / infiniband / hw / qedr / verbs.c
index 57c8de2080773b161272774a69eaebf02cc411ed..6b3bb32803bd8661d9efebd14dcefff0b601f6f3 100644 (file)
@@ -238,8 +238,8 @@ int qedr_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *attr)
        }
 
        rdma_port = dev->ops->rdma_query_port(dev->rdma_ctx);
-       memset(attr, 0, sizeof(*attr));
 
+       /* *attr being zeroed by the caller, avoid zeroing it here */
        if (rdma_port->port_state == QED_RDMA_PORT_UP) {
                attr->state = IB_PORT_ACTIVE;
                attr->phys_state = 5;
@@ -471,8 +471,6 @@ struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev,
                            struct ib_ucontext *context, struct ib_udata *udata)
 {
        struct qedr_dev *dev = get_qedr_dev(ibdev);
-       struct qedr_ucontext *uctx = NULL;
-       struct qedr_alloc_pd_uresp uresp;
        struct qedr_pd *pd;
        u16 pd_id;
        int rc;
@@ -489,21 +487,33 @@ struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev,
        if (!pd)
                return ERR_PTR(-ENOMEM);
 
-       dev->ops->rdma_alloc_pd(dev->rdma_ctx, &pd_id);
+       rc = dev->ops->rdma_alloc_pd(dev->rdma_ctx, &pd_id);
+       if (rc)
+               goto err;
 
-       uresp.pd_id = pd_id;
        pd->pd_id = pd_id;
 
        if (udata && context) {
+               struct qedr_alloc_pd_uresp uresp;
+
+               uresp.pd_id = pd_id;
+
                rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
-               if (rc)
+               if (rc) {
                        DP_ERR(dev, "copy error pd_id=0x%x.\n", pd_id);
-               uctx = get_qedr_ucontext(context);
-               uctx->pd = pd;
-               pd->uctx = uctx;
+                       dev->ops->rdma_dealloc_pd(dev->rdma_ctx, pd_id);
+                       goto err;
+               }
+
+               pd->uctx = get_qedr_ucontext(context);
+               pd->uctx->pd = pd;
        }
 
        return &pd->ibpd;
+
+err:
+       kfree(pd);
+       return ERR_PTR(rc);
 }
 
 int qedr_dealloc_pd(struct ib_pd *ibpd)
@@ -761,8 +771,10 @@ static inline int qedr_init_user_queue(struct ib_ucontext *ib_ctx,
                goto err0;
 
        q->pbl_tbl = qedr_alloc_pbl_tbl(dev, &q->pbl_info, GFP_KERNEL);
-       if (IS_ERR_OR_NULL(q->pbl_tbl))
+       if (IS_ERR(q->pbl_tbl)) {
+               rc = PTR_ERR(q->pbl_tbl);
                goto err0;
+       }
 
        qedr_populate_pbls(dev, q->umem, q->pbl_tbl, &q->pbl_info);
 
@@ -1076,30 +1088,6 @@ static inline int get_gid_info_from_table(struct ib_qp *ibqp,
        return 0;
 }
 
-static void qedr_cleanup_user_sq(struct qedr_dev *dev, struct qedr_qp *qp)
-{
-       qedr_free_pbl(dev, &qp->usq.pbl_info, qp->usq.pbl_tbl);
-       ib_umem_release(qp->usq.umem);
-}
-
-static void qedr_cleanup_user_rq(struct qedr_dev *dev, struct qedr_qp *qp)
-{
-       qedr_free_pbl(dev, &qp->urq.pbl_info, qp->urq.pbl_tbl);
-       ib_umem_release(qp->urq.umem);
-}
-
-static void qedr_cleanup_kernel_sq(struct qedr_dev *dev, struct qedr_qp *qp)
-{
-       dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl);
-       kfree(qp->wqe_wr_id);
-}
-
-static void qedr_cleanup_kernel_rq(struct qedr_dev *dev, struct qedr_qp *qp)
-{
-       dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl);
-       kfree(qp->rqe_wr_id);
-}
-
 static int qedr_check_qp_attrs(struct ib_pd *ibpd, struct qedr_dev *dev,
                               struct ib_qp_init_attr *attrs)
 {
@@ -1188,15 +1176,13 @@ static int qedr_copy_qp_uresp(struct qedr_dev *dev,
        return rc;
 }
 
-static void qedr_set_qp_init_params(struct qedr_dev *dev,
-                                   struct qedr_qp *qp,
-                                   struct qedr_pd *pd,
-                                   struct ib_qp_init_attr *attrs)
+static void qedr_set_common_qp_params(struct qedr_dev *dev,
+                                     struct qedr_qp *qp,
+                                     struct qedr_pd *pd,
+                                     struct ib_qp_init_attr *attrs)
 {
-       qp->pd = pd;
-
        spin_lock_init(&qp->q_lock);
-
+       qp->pd = pd;
        qp->qp_type = attrs->qp_type;
        qp->max_inline_data = attrs->cap.max_inline_data;
        qp->sq.max_sges = attrs->cap.max_send_sge;
@@ -1205,7 +1191,11 @@ static void qedr_set_qp_init_params(struct qedr_dev *dev,
        qp->sq_cq = get_qedr_cq(attrs->send_cq);
        qp->rq_cq = get_qedr_cq(attrs->recv_cq);
        qp->dev = dev;
+       qp->rq.max_sges = attrs->cap.max_recv_sge;
 
+       DP_DEBUG(dev, QEDR_MSG_QP,
+                "RQ params:\trq_max_sges = %d, rq_cq_id = %d\n",
+                qp->rq.max_sges, qp->rq_cq->icid);
        DP_DEBUG(dev, QEDR_MSG_QP,
                 "QP params:\tpd = %d, qp_type = %d, max_inline_data = %d, state = %d, signaled = %d, use_srq=%d\n",
                 pd->pd_id, qp->qp_type, qp->max_inline_data,
@@ -1213,95 +1203,149 @@ static void qedr_set_qp_init_params(struct qedr_dev *dev,
        DP_DEBUG(dev, QEDR_MSG_QP,
                 "SQ params:\tsq_max_sges = %d, sq_cq_id = %d\n",
                 qp->sq.max_sges, qp->sq_cq->icid);
-       qp->rq.max_sges = attrs->cap.max_recv_sge;
-       DP_DEBUG(dev, QEDR_MSG_QP,
-                "RQ params:\trq_max_sges = %d, rq_cq_id = %d\n",
-                qp->rq.max_sges, qp->rq_cq->icid);
 }
 
-static inline void
-qedr_init_qp_user_params(struct qed_rdma_create_qp_in_params *params,
-                        struct qedr_create_qp_ureq *ureq)
-{
-       /* QP handle to be written in CQE */
-       params->qp_handle_lo = ureq->qp_handle_lo;
-       params->qp_handle_hi = ureq->qp_handle_hi;
-}
-
-static inline void
-qedr_init_qp_kernel_doorbell_sq(struct qedr_dev *dev, struct qedr_qp *qp)
+static void qedr_set_roce_db_info(struct qedr_dev *dev, struct qedr_qp *qp)
 {
        qp->sq.db = dev->db_addr +
                    DB_ADDR_SHIFT(DQ_PWM_OFFSET_XCM_RDMA_SQ_PROD);
        qp->sq.db_data.data.icid = qp->icid + 1;
+       qp->rq.db = dev->db_addr +
+                   DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_ROCE_RQ_PROD);
+       qp->rq.db_data.data.icid = qp->icid;
 }
 
 static inline void
-qedr_init_qp_kernel_doorbell_rq(struct qedr_dev *dev, struct qedr_qp *qp)
+qedr_init_common_qp_in_params(struct qedr_dev *dev,
+                             struct qedr_pd *pd,
+                             struct qedr_qp *qp,
+                             struct ib_qp_init_attr *attrs,
+                             bool fmr_and_reserved_lkey,
+                             struct qed_rdma_create_qp_in_params *params)
 {
-       qp->rq.db = dev->db_addr +
-                   DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_ROCE_RQ_PROD);
-       qp->rq.db_data.data.icid = qp->icid;
+       /* QP handle to be written in an async event */
+       params->qp_handle_async_lo = lower_32_bits((uintptr_t) qp);
+       params->qp_handle_async_hi = upper_32_bits((uintptr_t) qp);
+
+       params->signal_all = (attrs->sq_sig_type == IB_SIGNAL_ALL_WR);
+       params->fmr_and_reserved_lkey = fmr_and_reserved_lkey;
+       params->pd = pd->pd_id;
+       params->dpi = pd->uctx ? pd->uctx->dpi : dev->dpi;
+       params->sq_cq_id = get_qedr_cq(attrs->send_cq)->icid;
+       params->stats_queue = 0;
+       params->rq_cq_id = get_qedr_cq(attrs->recv_cq)->icid;
+       params->srq_id = 0;
+       params->use_srq = false;
 }
 
-static inline int
-qedr_init_qp_kernel_params_rq(struct qedr_dev *dev,
-                             struct qedr_qp *qp, struct ib_qp_init_attr *attrs)
+static inline void qedr_qp_user_print(struct qedr_dev *dev, struct qedr_qp *qp)
 {
-       /* Allocate driver internal RQ array */
-       qp->rqe_wr_id = kcalloc(qp->rq.max_wr, sizeof(*qp->rqe_wr_id),
-                               GFP_KERNEL);
-       if (!qp->rqe_wr_id)
-               return -ENOMEM;
+       DP_DEBUG(dev, QEDR_MSG_QP, "create qp: successfully created user QP. "
+                "qp=%p. "
+                "sq_addr=0x%llx, "
+                "sq_len=%zd, "
+                "rq_addr=0x%llx, "
+                "rq_len=%zd"
+                "\n",
+                qp,
+                qp->usq.buf_addr,
+                qp->usq.buf_len, qp->urq.buf_addr, qp->urq.buf_len);
+}
 
-       DP_DEBUG(dev, QEDR_MSG_QP, "RQ max_wr set to %d.\n", qp->rq.max_wr);
+static void qedr_cleanup_user(struct qedr_dev *dev, struct qedr_qp *qp)
+{
+       if (qp->usq.umem)
+               ib_umem_release(qp->usq.umem);
+       qp->usq.umem = NULL;
 
-       return 0;
+       if (qp->urq.umem)
+               ib_umem_release(qp->urq.umem);
+       qp->urq.umem = NULL;
 }
 
-static inline int
-qedr_init_qp_kernel_params_sq(struct qedr_dev *dev,
-                             struct qedr_qp *qp,
-                             struct ib_qp_init_attr *attrs,
-                             struct qed_rdma_create_qp_in_params *params)
+static int qedr_create_user_qp(struct qedr_dev *dev,
+                              struct qedr_qp *qp,
+                              struct ib_pd *ibpd,
+                              struct ib_udata *udata,
+                              struct ib_qp_init_attr *attrs)
 {
-       u32 temp_max_wr;
+       struct qed_rdma_create_qp_in_params in_params;
+       struct qed_rdma_create_qp_out_params out_params;
+       struct qedr_pd *pd = get_qedr_pd(ibpd);
+       struct ib_ucontext *ib_ctx = NULL;
+       struct qedr_ucontext *ctx = NULL;
+       struct qedr_create_qp_ureq ureq;
+       int rc = -EINVAL;
 
-       /* Allocate driver internal SQ array */
-       temp_max_wr = attrs->cap.max_send_wr * dev->wq_multiplier;
-       temp_max_wr = min_t(u32, temp_max_wr, dev->attr.max_sqe);
+       ib_ctx = ibpd->uobject->context;
+       ctx = get_qedr_ucontext(ib_ctx);
 
-       /* temp_max_wr < attr->max_sqe < u16 so the casting is safe */
-       qp->sq.max_wr = (u16)temp_max_wr;
-       qp->wqe_wr_id = kcalloc(qp->sq.max_wr, sizeof(*qp->wqe_wr_id),
-                               GFP_KERNEL);
-       if (!qp->wqe_wr_id)
-               return -ENOMEM;
+       memset(&ureq, 0, sizeof(ureq));
+       rc = ib_copy_from_udata(&ureq, udata, sizeof(ureq));
+       if (rc) {
+               DP_ERR(dev, "Problem copying data from user space\n");
+               return rc;
+       }
 
-       DP_DEBUG(dev, QEDR_MSG_QP, "SQ max_wr set to %d.\n", qp->sq.max_wr);
+       /* SQ - read access only (0), dma sync not required (0) */
+       rc = qedr_init_user_queue(ib_ctx, dev, &qp->usq, ureq.sq_addr,
+                                 ureq.sq_len, 0, 0);
+       if (rc)
+               return rc;
 
-       /* QP handle to be written in CQE */
-       params->qp_handle_lo = lower_32_bits((uintptr_t)qp);
-       params->qp_handle_hi = upper_32_bits((uintptr_t)qp);
+       /* RQ - read access only (0), dma sync not required (0) */
+       rc = qedr_init_user_queue(ib_ctx, dev, &qp->urq, ureq.rq_addr,
+                                 ureq.rq_len, 0, 0);
+
+       if (rc)
+               return rc;
+
+       memset(&in_params, 0, sizeof(in_params));
+       qedr_init_common_qp_in_params(dev, pd, qp, attrs, false, &in_params);
+       in_params.qp_handle_lo = ureq.qp_handle_lo;
+       in_params.qp_handle_hi = ureq.qp_handle_hi;
+       in_params.sq_num_pages = qp->usq.pbl_info.num_pbes;
+       in_params.sq_pbl_ptr = qp->usq.pbl_tbl->pa;
+       in_params.rq_num_pages = qp->urq.pbl_info.num_pbes;
+       in_params.rq_pbl_ptr = qp->urq.pbl_tbl->pa;
+
+       qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx,
+                                             &in_params, &out_params);
+
+       if (!qp->qed_qp) {
+               rc = -ENOMEM;
+               goto err1;
+       }
+
+       qp->qp_id = out_params.qp_id;
+       qp->icid = out_params.icid;
+
+       rc = qedr_copy_qp_uresp(dev, qp, udata);
+       if (rc)
+               goto err;
+
+       qedr_qp_user_print(dev, qp);
 
        return 0;
+err:
+       rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp);
+       if (rc)
+               DP_ERR(dev, "create qp: fatal fault. rc=%d", rc);
+
+err1:
+       qedr_cleanup_user(dev, qp);
+       return rc;
 }
 
-static inline int qedr_init_qp_kernel_sq(struct qedr_dev *dev,
-                                        struct qedr_qp *qp,
-                                        struct ib_qp_init_attr *attrs)
+static int
+qedr_roce_create_kernel_qp(struct qedr_dev *dev,
+                          struct qedr_qp *qp,
+                          struct qed_rdma_create_qp_in_params *in_params,
+                          u32 n_sq_elems, u32 n_rq_elems)
 {
-       u32 n_sq_elems, n_sq_entries;
+       struct qed_rdma_create_qp_out_params out_params;
        int rc;
 
-       /* A single work request may take up to QEDR_MAX_SQ_WQE_SIZE elements in
-        * the ring. The ring should allow at least a single WR, even if the
-        * user requested none, due to allocation issues.
-        */
-       n_sq_entries = attrs->cap.max_send_wr;
-       n_sq_entries = min_t(u32, n_sq_entries, dev->attr.max_sqe);
-       n_sq_entries = max_t(u32, n_sq_entries, 1);
-       n_sq_elems = n_sq_entries * QEDR_MAX_SQE_ELEMENTS_PER_SQE;
        rc = dev->ops->common->chain_alloc(dev->cdev,
                                           QED_CHAIN_USE_TO_PRODUCE,
                                           QED_CHAIN_MODE_PBL,
@@ -1309,31 +1353,13 @@ static inline int qedr_init_qp_kernel_sq(struct qedr_dev *dev,
                                           n_sq_elems,
                                           QEDR_SQE_ELEMENT_SIZE,
                                           &qp->sq.pbl);
-       if (rc) {
-               DP_ERR(dev, "failed to allocate QP %p SQ\n", qp);
-               return rc;
-       }
 
-       DP_DEBUG(dev, QEDR_MSG_SQ,
-                "SQ Pbl base addr = %llx max_send_wr=%d max_wr=%d capacity=%d, rc=%d\n",
-                qed_chain_get_pbl_phys(&qp->sq.pbl), attrs->cap.max_send_wr,
-                n_sq_entries, qed_chain_get_capacity(&qp->sq.pbl), rc);
-       return 0;
-}
+       if (rc)
+               return rc;
 
-static inline int qedr_init_qp_kernel_rq(struct qedr_dev *dev,
-                                        struct qedr_qp *qp,
-                                        struct ib_qp_init_attr *attrs)
-{
-       u32 n_rq_elems, n_rq_entries;
-       int rc;
+       in_params->sq_num_pages = qed_chain_get_page_cnt(&qp->sq.pbl);
+       in_params->sq_pbl_ptr = qed_chain_get_pbl_phys(&qp->sq.pbl);
 
-       /* A single work request may take up to QEDR_MAX_RQ_WQE_SIZE elements in
-        * the ring. There ring should allow at least a single WR, even if the
-        * user requested none, due to allocation issues.
-        */
-       n_rq_entries = max_t(u32, attrs->cap.max_recv_wr, 1);
-       n_rq_elems = n_rq_entries * QEDR_MAX_RQE_ELEMENTS_PER_RQE;
        rc = dev->ops->common->chain_alloc(dev->cdev,
                                           QED_CHAIN_USE_TO_CONSUME_PRODUCE,
                                           QED_CHAIN_MODE_PBL,
@@ -1341,136 +1367,102 @@ static inline int qedr_init_qp_kernel_rq(struct qedr_dev *dev,
                                           n_rq_elems,
                                           QEDR_RQE_ELEMENT_SIZE,
                                           &qp->rq.pbl);
+       if (rc)
+               return rc;
 
-       if (rc) {
-               DP_ERR(dev, "failed to allocate memory for QP %p RQ\n", qp);
-               return -ENOMEM;
-       }
-
-       DP_DEBUG(dev, QEDR_MSG_RQ,
-                "RQ Pbl base addr = %llx max_recv_wr=%d max_wr=%d capacity=%d, rc=%d\n",
-                qed_chain_get_pbl_phys(&qp->rq.pbl), attrs->cap.max_recv_wr,
-                n_rq_entries, qed_chain_get_capacity(&qp->rq.pbl), rc);
+       in_params->rq_num_pages = qed_chain_get_page_cnt(&qp->rq.pbl);
+       in_params->rq_pbl_ptr = qed_chain_get_pbl_phys(&qp->rq.pbl);
 
-       /* n_rq_entries < u16 so the casting is safe */
-       qp->rq.max_wr = (u16)n_rq_entries;
+       qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx,
+                                             in_params, &out_params);
 
-       return 0;
-}
+       if (!qp->qed_qp)
+               return -EINVAL;
 
-static inline void
-qedr_init_qp_in_params_sq(struct qedr_dev *dev,
-                         struct qedr_pd *pd,
-                         struct qedr_qp *qp,
-                         struct ib_qp_init_attr *attrs,
-                         struct ib_udata *udata,
-                         struct qed_rdma_create_qp_in_params *params)
-{
-       /* QP handle to be written in an async event */
-       params->qp_handle_async_lo = lower_32_bits((uintptr_t)qp);
-       params->qp_handle_async_hi = upper_32_bits((uintptr_t)qp);
+       qp->qp_id = out_params.qp_id;
+       qp->icid = out_params.icid;
 
-       params->signal_all = (attrs->sq_sig_type == IB_SIGNAL_ALL_WR);
-       params->fmr_and_reserved_lkey = !udata;
-       params->pd = pd->pd_id;
-       params->dpi = pd->uctx ? pd->uctx->dpi : dev->dpi;
-       params->sq_cq_id = get_qedr_cq(attrs->send_cq)->icid;
-       params->max_sq_sges = 0;
-       params->stats_queue = 0;
+       qedr_set_roce_db_info(dev, qp);
 
-       if (udata) {
-               params->sq_num_pages = qp->usq.pbl_info.num_pbes;
-               params->sq_pbl_ptr = qp->usq.pbl_tbl->pa;
-       } else {
-               params->sq_num_pages = qed_chain_get_page_cnt(&qp->sq.pbl);
-               params->sq_pbl_ptr = qed_chain_get_pbl_phys(&qp->sq.pbl);
-       }
+       return 0;
 }
 
-static inline void
-qedr_init_qp_in_params_rq(struct qedr_qp *qp,
-                         struct ib_qp_init_attr *attrs,
-                         struct ib_udata *udata,
-                         struct qed_rdma_create_qp_in_params *params)
+static void qedr_cleanup_kernel(struct qedr_dev *dev, struct qedr_qp *qp)
 {
-       params->rq_cq_id = get_qedr_cq(attrs->recv_cq)->icid;
-       params->srq_id = 0;
-       params->use_srq = false;
+       dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl);
+       kfree(qp->wqe_wr_id);
 
-       if (udata) {
-               params->rq_num_pages = qp->urq.pbl_info.num_pbes;
-               params->rq_pbl_ptr = qp->urq.pbl_tbl->pa;
-       } else {
-               params->rq_num_pages = qed_chain_get_page_cnt(&qp->rq.pbl);
-               params->rq_pbl_ptr = qed_chain_get_pbl_phys(&qp->rq.pbl);
-       }
+       dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl);
+       kfree(qp->rqe_wr_id);
 }
 
-static inline void qedr_qp_user_print(struct qedr_dev *dev, struct qedr_qp *qp)
+static int qedr_create_kernel_qp(struct qedr_dev *dev,
+                                struct qedr_qp *qp,
+                                struct ib_pd *ibpd,
+                                struct ib_qp_init_attr *attrs)
 {
-       DP_DEBUG(dev, QEDR_MSG_QP,
-                "create qp: successfully created user QP. qp=%p, sq_addr=0x%llx, sq_len=%zd, rq_addr=0x%llx, rq_len=%zd\n",
-                qp, qp->usq.buf_addr, qp->usq.buf_len, qp->urq.buf_addr,
-                qp->urq.buf_len);
-}
+       struct qed_rdma_create_qp_in_params in_params;
+       struct qedr_pd *pd = get_qedr_pd(ibpd);
+       int rc = -EINVAL;
+       u32 n_rq_elems;
+       u32 n_sq_elems;
+       u32 n_sq_entries;
 
-static inline int qedr_init_user_qp(struct ib_ucontext *ib_ctx,
-                                   struct qedr_dev *dev,
-                                   struct qedr_qp *qp,
-                                   struct qedr_create_qp_ureq *ureq)
-{
-       int rc;
+       memset(&in_params, 0, sizeof(in_params));
 
-       /* SQ - read access only (0), dma sync not required (0) */
-       rc = qedr_init_user_queue(ib_ctx, dev, &qp->usq, ureq->sq_addr,
-                                 ureq->sq_len, 0, 0);
-       if (rc)
-               return rc;
+       /* A single work request may take up to QEDR_MAX_SQ_WQE_SIZE elements in
+        * the ring. The ring should allow at least a single WR, even if the
+        * user requested none, due to allocation issues.
+        * We should add an extra WR since the prod and cons indices of
+        * wqe_wr_id are managed in such a way that the WQ is considered full
+        * when (prod+1)%max_wr==cons. We currently don't do that because we
+        * double the number of entries due an iSER issue that pushes far more
+        * WRs than indicated. If we decline its ib_post_send() then we get
+        * error prints in the dmesg we'd like to avoid.
+        */
+       qp->sq.max_wr = min_t(u32, attrs->cap.max_send_wr * dev->wq_multiplier,
+                             dev->attr.max_sqe);
 
-       /* RQ - read access only (0), dma sync not required (0) */
-       rc = qedr_init_user_queue(ib_ctx, dev, &qp->urq, ureq->rq_addr,
-                                 ureq->rq_len, 0, 0);
+       qp->wqe_wr_id = kzalloc(qp->sq.max_wr * sizeof(*qp->wqe_wr_id),
+                               GFP_KERNEL);
+       if (!qp->wqe_wr_id) {
+               DP_ERR(dev, "create qp: failed SQ shadow memory allocation\n");
+               return -ENOMEM;
+       }
 
-       if (rc)
-               qedr_cleanup_user_sq(dev, qp);
-       return rc;
-}
+       /* QP handle to be written in CQE */
+       in_params.qp_handle_lo = lower_32_bits((uintptr_t) qp);
+       in_params.qp_handle_hi = upper_32_bits((uintptr_t) qp);
 
-static inline int
-qedr_init_kernel_qp(struct qedr_dev *dev,
-                   struct qedr_qp *qp,
-                   struct ib_qp_init_attr *attrs,
-                   struct qed_rdma_create_qp_in_params *params)
-{
-       int rc;
+       /* A single work request may take up to QEDR_MAX_RQ_WQE_SIZE elements in
+        * the ring. There ring should allow at least a single WR, even if the
+        * user requested none, due to allocation issues.
+        */
+       qp->rq.max_wr = (u16) max_t(u32, attrs->cap.max_recv_wr, 1);
 
-       rc = qedr_init_qp_kernel_sq(dev, qp, attrs);
-       if (rc) {
-               DP_ERR(dev, "failed to init kernel QP %p SQ\n", qp);
-               return rc;
+       /* Allocate driver internal RQ array */
+       qp->rqe_wr_id = kzalloc(qp->rq.max_wr * sizeof(*qp->rqe_wr_id),
+                               GFP_KERNEL);
+       if (!qp->rqe_wr_id) {
+               DP_ERR(dev,
+                      "create qp: failed RQ shadow memory allocation\n");
+               kfree(qp->wqe_wr_id);
+               return -ENOMEM;
        }
 
-       rc = qedr_init_qp_kernel_params_sq(dev, qp, attrs, params);
-       if (rc) {
-               dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl);
-               DP_ERR(dev, "failed to init kernel QP %p SQ params\n", qp);
-               return rc;
-       }
+       qedr_init_common_qp_in_params(dev, pd, qp, attrs, true, &in_params);
 
-       rc = qedr_init_qp_kernel_rq(dev, qp, attrs);
-       if (rc) {
-               qedr_cleanup_kernel_sq(dev, qp);
-               DP_ERR(dev, "failed to init kernel QP %p RQ\n", qp);
-               return rc;
-       }
+       n_sq_entries = attrs->cap.max_send_wr;
+       n_sq_entries = min_t(u32, n_sq_entries, dev->attr.max_sqe);
+       n_sq_entries = max_t(u32, n_sq_entries, 1);
+       n_sq_elems = n_sq_entries * QEDR_MAX_SQE_ELEMENTS_PER_SQE;
 
-       rc = qedr_init_qp_kernel_params_rq(dev, qp, attrs);
-       if (rc) {
-               DP_ERR(dev, "failed to init kernel QP %p RQ params\n", qp);
-               qedr_cleanup_kernel_sq(dev, qp);
-               dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl);
-               return rc;
-       }
+       n_rq_elems = qp->rq.max_wr * QEDR_MAX_RQE_ELEMENTS_PER_RQE;
+
+       rc = qedr_roce_create_kernel_qp(dev, qp, &in_params,
+                                       n_sq_elems, n_rq_elems);
+       if (rc)
+               qedr_cleanup_kernel(dev, qp);
 
        return rc;
 }
@@ -1480,12 +1472,7 @@ struct ib_qp *qedr_create_qp(struct ib_pd *ibpd,
                             struct ib_udata *udata)
 {
        struct qedr_dev *dev = get_qedr_dev(ibpd->device);
-       struct qed_rdma_create_qp_out_params out_params;
-       struct qed_rdma_create_qp_in_params in_params;
        struct qedr_pd *pd = get_qedr_pd(ibpd);
-       struct ib_ucontext *ib_ctx = NULL;
-       struct qedr_ucontext *ctx = NULL;
-       struct qedr_create_qp_ureq ureq;
        struct qedr_qp *qp;
        struct ib_qp *ibqp;
        int rc = 0;
@@ -1500,107 +1487,48 @@ struct ib_qp *qedr_create_qp(struct ib_pd *ibpd,
        if (attrs->srq)
                return ERR_PTR(-EINVAL);
 
-       qp = kzalloc(sizeof(*qp), GFP_KERNEL);
-       if (!qp)
-               return ERR_PTR(-ENOMEM);
-
        DP_DEBUG(dev, QEDR_MSG_QP,
-                "create qp: sq_cq=%p, sq_icid=%d, rq_cq=%p, rq_icid=%d\n",
+                "create qp: called from %s, event_handler=%p, eepd=%p sq_cq=%p, sq_icid=%d, rq_cq=%p, rq_icid=%d\n",
+                udata ? "user library" : "kernel", attrs->event_handler, pd,
                 get_qedr_cq(attrs->send_cq),
                 get_qedr_cq(attrs->send_cq)->icid,
                 get_qedr_cq(attrs->recv_cq),
                 get_qedr_cq(attrs->recv_cq)->icid);
 
-       qedr_set_qp_init_params(dev, qp, pd, attrs);
+       qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+       if (!qp) {
+               DP_ERR(dev, "create qp: failed allocating memory\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       qedr_set_common_qp_params(dev, qp, pd, attrs);
 
        if (attrs->qp_type == IB_QPT_GSI) {
-               if (udata) {
-                       DP_ERR(dev,
-                              "create qp: unexpected udata when creating GSI QP\n");
-                       goto err0;
-               }
                ibqp = qedr_create_gsi_qp(dev, attrs, qp);
                if (IS_ERR(ibqp))
                        kfree(qp);
                return ibqp;
        }
 
-       memset(&in_params, 0, sizeof(in_params));
-
-       if (udata) {
-               if (!(udata && ibpd->uobject && ibpd->uobject->context))
-                       goto err0;
-
-               ib_ctx = ibpd->uobject->context;
-               ctx = get_qedr_ucontext(ib_ctx);
-
-               memset(&ureq, 0, sizeof(ureq));
-               if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) {
-                       DP_ERR(dev,
-                              "create qp: problem copying data from user space\n");
-                       goto err0;
-               }
-
-               rc = qedr_init_user_qp(ib_ctx, dev, qp, &ureq);
-               if (rc)
-                       goto err0;
-
-               qedr_init_qp_user_params(&in_params, &ureq);
-       } else {
-               rc = qedr_init_kernel_qp(dev, qp, attrs, &in_params);
-               if (rc)
-                       goto err0;
-       }
-
-       qedr_init_qp_in_params_sq(dev, pd, qp, attrs, udata, &in_params);
-       qedr_init_qp_in_params_rq(qp, attrs, udata, &in_params);
-
-       qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx,
-                                             &in_params, &out_params);
+       if (udata)
+               rc = qedr_create_user_qp(dev, qp, ibpd, udata, attrs);
+       else
+               rc = qedr_create_kernel_qp(dev, qp, ibpd, attrs);
 
-       if (!qp->qed_qp)
-               goto err1;
+       if (rc)
+               goto err;
 
-       qp->qp_id = out_params.qp_id;
-       qp->icid = out_params.icid;
        qp->ibqp.qp_num = qp->qp_id;
 
-       if (udata) {
-               rc = qedr_copy_qp_uresp(dev, qp, udata);
-               if (rc)
-                       goto err2;
-
-               qedr_qp_user_print(dev, qp);
-       } else {
-               qedr_init_qp_kernel_doorbell_sq(dev, qp);
-               qedr_init_qp_kernel_doorbell_rq(dev, qp);
-       }
-
-       DP_DEBUG(dev, QEDR_MSG_QP, "created %s space QP %p\n",
-                udata ? "user" : "kernel", qp);
-
        return &qp->ibqp;
 
-err2:
-       rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp);
-       if (rc)
-               DP_ERR(dev, "create qp: fatal fault. rc=%d", rc);
-err1:
-       if (udata) {
-               qedr_cleanup_user_sq(dev, qp);
-               qedr_cleanup_user_rq(dev, qp);
-       } else {
-               qedr_cleanup_kernel_sq(dev, qp);
-               qedr_cleanup_kernel_rq(dev, qp);
-       }
-
-err0:
+err:
        kfree(qp);
 
        return ERR_PTR(-EFAULT);
 }
 
-enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state)
+static enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state)
 {
        switch (qp_state) {
        case QED_ROCE_QP_STATE_RESET:
@@ -1621,7 +1549,8 @@ enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state)
        return IB_QPS_ERR;
 }
 
-enum qed_roce_qp_state qedr_get_state_from_ibqp(enum ib_qp_state qp_state)
+static enum qed_roce_qp_state qedr_get_state_from_ibqp(
+                                       enum ib_qp_state qp_state)
 {
        switch (qp_state) {
        case IB_QPS_RESET:
@@ -1657,7 +1586,7 @@ static int qedr_update_qp_state(struct qedr_dev *dev,
        int status = 0;
 
        if (new_state == qp->state)
-               return 1;
+               return 0;
 
        switch (qp->state) {
        case QED_ROCE_QP_STATE_RESET:
@@ -1733,6 +1662,14 @@ static int qedr_update_qp_state(struct qedr_dev *dev,
                /* ERR->XXX */
                switch (new_state) {
                case QED_ROCE_QP_STATE_RESET:
+                       if ((qp->rq.prod != qp->rq.cons) ||
+                           (qp->sq.prod != qp->sq.cons)) {
+                               DP_NOTICE(dev,
+                                         "Error->Reset with rq/sq not empty rq.prod=%x rq.cons=%x sq.prod=%x sq.cons=%x\n",
+                                         qp->rq.prod, qp->rq.cons, qp->sq.prod,
+                                         qp->sq.cons);
+                               status = -EINVAL;
+                       }
                        break;
                default:
                        status = -EINVAL;
@@ -1865,7 +1802,6 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                         qp_params.sgid.dwords[2], qp_params.sgid.dwords[3]);
                DP_DEBUG(dev, QEDR_MSG_QP, "remote_mac=[%pM]\n",
                         qp_params.remote_mac_addr);
-;
 
                qp_params.mtu = qp->mtu;
                qp_params.lb_indication = false;
@@ -2016,7 +1952,7 @@ int qedr_query_qp(struct ib_qp *ibqp,
 
        qp_attr->qp_state = qedr_get_ibqp_state(params.state);
        qp_attr->cur_qp_state = qedr_get_ibqp_state(params.state);
-       qp_attr->path_mtu = iboe_get_mtu(params.mtu);
+       qp_attr->path_mtu = ib_mtu_int_to_enum(params.mtu);
        qp_attr->path_mig_state = IB_MIG_MIGRATED;
        qp_attr->rq_psn = params.rq_psn;
        qp_attr->sq_psn = params.sq_psn;
@@ -2028,7 +1964,7 @@ int qedr_query_qp(struct ib_qp *ibqp,
        qp_attr->cap.max_recv_wr = qp->rq.max_wr;
        qp_attr->cap.max_send_sge = qp->sq.max_sges;
        qp_attr->cap.max_recv_sge = qp->rq.max_sges;
-       qp_attr->cap.max_inline_data = qp->max_inline_data;
+       qp_attr->cap.max_inline_data = ROCE_REQ_MAX_INLINE_DATA_SIZE;
        qp_init_attr->cap = qp_attr->cap;
 
        memcpy(&qp_attr->ah_attr.grh.dgid.raw[0], &params.dgid.bytes[0],
@@ -2067,6 +2003,24 @@ err:
        return rc;
 }
 
+int qedr_free_qp_resources(struct qedr_dev *dev, struct qedr_qp *qp)
+{
+       int rc = 0;
+
+       if (qp->qp_type != IB_QPT_GSI) {
+               rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp);
+               if (rc)
+                       return rc;
+       }
+
+       if (qp->ibqp.uobject && qp->ibqp.uobject->context)
+               qedr_cleanup_user(dev, qp);
+       else
+               qedr_cleanup_kernel(dev, qp);
+
+       return 0;
+}
+
 int qedr_destroy_qp(struct ib_qp *ibqp)
 {
        struct qedr_qp *qp = get_qedr_qp(ibqp);
@@ -2089,21 +2043,10 @@ int qedr_destroy_qp(struct ib_qp *ibqp)
                qedr_modify_qp(ibqp, &attr, attr_mask, NULL);
        }
 
-       if (qp->qp_type != IB_QPT_GSI) {
-               rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp);
-               if (rc)
-                       return rc;
-       } else {
+       if (qp->qp_type == IB_QPT_GSI)
                qedr_destroy_gsi_qp(dev);
-       }
 
-       if (ibqp->uobject && ibqp->uobject->context) {
-               qedr_cleanup_user_sq(dev, qp);
-               qedr_cleanup_user_rq(dev, qp);
-       } else {
-               qedr_cleanup_kernel_sq(dev, qp);
-               qedr_cleanup_kernel_rq(dev, qp);
-       }
+       qedr_free_qp_resources(dev, qp);
 
        kfree(qp);
 
@@ -2164,8 +2107,8 @@ static int init_mr_info(struct qedr_dev *dev, struct mr_info *info,
                goto done;
 
        info->pbl_table = qedr_alloc_pbl_tbl(dev, &info->pbl_info, GFP_KERNEL);
-       if (!info->pbl_table) {
-               rc = -ENOMEM;
+       if (IS_ERR(info->pbl_table)) {
+               rc = PTR_ERR(info->pbl_table);
                goto done;
        }
 
@@ -2176,7 +2119,7 @@ static int init_mr_info(struct qedr_dev *dev, struct mr_info *info,
         * list and allocating another one
         */
        tmp = qedr_alloc_pbl_tbl(dev, &info->pbl_info, GFP_KERNEL);
-       if (!tmp) {
+       if (IS_ERR(tmp)) {
                DP_DEBUG(dev, QEDR_MSG_MR, "Extra PBL is not allocated\n");
                goto done;
        }
@@ -2302,7 +2245,8 @@ int qedr_dereg_mr(struct ib_mr *ib_mr)
        return rc;
 }
 
-struct qedr_mr *__qedr_alloc_mr(struct ib_pd *ibpd, int max_page_list_len)
+static struct qedr_mr *__qedr_alloc_mr(struct ib_pd *ibpd,
+                                      int max_page_list_len)
 {
        struct qedr_pd *pd = get_qedr_pd(ibpd);
        struct qedr_dev *dev = get_qedr_dev(ibpd->device);
@@ -2704,7 +2648,7 @@ static int qedr_prepare_reg(struct qedr_qp *qp,
        return 0;
 }
 
-enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode)
+static enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode)
 {
        switch (opcode) {
        case IB_WR_RDMA_WRITE:
@@ -2729,7 +2673,7 @@ enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode)
        }
 }
 
-inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr)
+static inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr)
 {
        int wq_is_full, err_wr, pbl_is_full;
        struct qedr_dev *dev = qp->dev;
@@ -2766,7 +2710,7 @@ inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr)
        return true;
 }
 
-int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                     struct ib_send_wr **bad_wr)
 {
        struct qedr_dev *dev = get_qedr_dev(ibqp->device);
@@ -3234,9 +3178,10 @@ static int qedr_poll_cq_req(struct qedr_dev *dev,
                                  IB_WC_SUCCESS, 0);
                break;
        case RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR:
-               DP_ERR(dev,
-                      "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n",
-                      cq->icid, qp->icid);
+               if (qp->state != QED_ROCE_QP_STATE_ERR)
+                       DP_ERR(dev,
+                              "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n",
+                              cq->icid, qp->icid);
                cnt = process_req(dev, qp, cq, num_entries, wc, req->sq_cons,
                                  IB_WC_WR_FLUSH_ERR, 1);
                break;
@@ -3549,14 +3494,15 @@ int qedr_port_immutable(struct ib_device *ibdev, u8 port_num,
        struct ib_port_attr attr;
        int err;
 
-       err = qedr_query_port(ibdev, port_num, &attr);
+       immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE |
+                                   RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP;
+
+       err = ib_query_port(ibdev, port_num, &attr);
        if (err)
                return err;
 
        immutable->pkey_tbl_len = attr.pkey_tbl_len;
        immutable->gid_tbl_len = attr.gid_tbl_len;
-       immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE |
-                                   RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP;
        immutable->max_mad_size = IB_MGMT_MAD_SIZE;
 
        return 0;