]> err.no Git - linux-2.6/blobdiff - drivers/infiniband/hw/ipath/ipath_qp.c
IB/ipath: Fix CQ flushing when QP is modified to error state
[linux-2.6] / drivers / infiniband / hw / ipath / ipath_qp.c
index 64f07b19349fadc8ca88a2c27eac01b89fa13498..f671fd07325302977e83d08040bb31d08877ec30 100644 (file)
@@ -274,7 +274,7 @@ void ipath_free_all_qps(struct ipath_qp_table *qpt)
                                free_qpn(qpt, qp->ibqp.qp_num);
                        if (!atomic_dec_and_test(&qp->refcount) ||
                            !ipath_destroy_qp(&qp->ibqp))
-                               ipath_dbg(KERN_INFO "QP memory leak!\n");
+                               ipath_dbg("QP memory leak!\n");
                        qp = nqp;
                }
        }
@@ -320,7 +320,8 @@ static void ipath_reset_qp(struct ipath_qp *qp)
        qp->remote_qpn = 0;
        qp->qkey = 0;
        qp->qp_access_flags = 0;
-       clear_bit(IPATH_S_BUSY, &qp->s_flags);
+       qp->s_busy = 0;
+       qp->s_flags &= ~IPATH_S_SIGNAL_REQ_WR;
        qp->s_hdrwords = 0;
        qp->s_psn = 0;
        qp->r_psn = 0;
@@ -333,7 +334,6 @@ static void ipath_reset_qp(struct ipath_qp *qp)
                qp->r_state = IB_OPCODE_UC_SEND_LAST;
        }
        qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
-       qp->r_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
        qp->r_nak_state = 0;
        qp->r_wrid_valid = 0;
        qp->s_rnr_timeout = 0;
@@ -344,6 +344,10 @@ static void ipath_reset_qp(struct ipath_qp *qp)
        qp->s_ssn = 1;
        qp->s_lsn = 0;
        qp->s_wait_credit = 0;
+       memset(qp->s_ack_queue, 0, sizeof(qp->s_ack_queue));
+       qp->r_head_ack_queue = 0;
+       qp->s_tail_ack_queue = 0;
+       qp->s_num_rd_atomic = 0;
        if (qp->r_rq.wq) {
                qp->r_rq.wq->head = 0;
                qp->r_rq.wq->tail = 0;
@@ -357,7 +361,7 @@ static void ipath_reset_qp(struct ipath_qp *qp)
  * @err: the receive completion error to signal if a RWQE is active
  *
  * Flushes both send and receive work queues.
- * QP s_lock should be held and interrupts disabled.
+ * The QP s_lock should be held and interrupts disabled.
  */
 
 void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
@@ -365,7 +369,7 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
        struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
        struct ib_wc wc;
 
-       ipath_dbg(KERN_INFO "QP%d/%d in error state\n",
+       ipath_dbg("QP%d/%d in error state\n",
                  qp->ibqp.qp_num, qp->remote_qpn);
 
        spin_lock(&dev->pending_lock);
@@ -389,6 +393,8 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
        wc.port_num = 0;
        if (qp->r_wrid_valid) {
                qp->r_wrid_valid = 0;
+               wc.wr_id = qp->r_wr_id;
+               wc.opcode = IB_WC_RECV;
                wc.status = err;
                ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1);
        }
@@ -503,13 +509,17 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                    attr->path_mig_state != IB_MIG_REARM)
                        goto inval;
 
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+               if (attr->max_dest_rd_atomic > IPATH_MAX_RDMA_ATOMIC)
+                       goto inval;
+
        switch (new_state) {
        case IB_QPS_RESET:
                ipath_reset_qp(qp);
                break;
 
        case IB_QPS_ERR:
-               ipath_error_qp(qp, IB_WC_GENERAL_ERR);
+               ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
                break;
 
        default:
@@ -559,6 +569,12 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        if (attr_mask & IB_QP_QKEY)
                qp->qkey = attr->qkey;
 
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+               qp->r_max_rd_atomic = attr->max_dest_rd_atomic;
+
+       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC)
+               qp->s_max_rd_atomic = attr->max_rd_atomic;
+
        qp->state = new_state;
        spin_unlock_irqrestore(&qp->s_lock, flags);
 
@@ -598,8 +614,8 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        attr->alt_pkey_index = 0;
        attr->en_sqd_async_notify = 0;
        attr->sq_draining = 0;
-       attr->max_rd_atomic = 1;
-       attr->max_dest_rd_atomic = 1;
+       attr->max_rd_atomic = qp->s_max_rd_atomic;
+       attr->max_dest_rd_atomic = qp->r_max_rd_atomic;
        attr->min_rnr_timer = qp->r_min_rnr_timer;
        attr->port_num = 1;
        attr->timeout = qp->timeout;
@@ -614,7 +630,7 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        init_attr->recv_cq = qp->ibqp.recv_cq;
        init_attr->srq = qp->ibqp.srq;
        init_attr->cap = attr->cap;
-       if (qp->s_flags & (1 << IPATH_S_SIGNAL_REQ_WR))
+       if (qp->s_flags & IPATH_S_SIGNAL_REQ_WR)
                init_attr->sq_sig_type = IB_SIGNAL_REQ_WR;
        else
                init_attr->sq_sig_type = IB_SIGNAL_ALL_WR;
@@ -786,7 +802,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
                qp->s_size = init_attr->cap.max_send_wr + 1;
                qp->s_max_sge = init_attr->cap.max_send_sge;
                if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR)
-                       qp->s_flags = 1 << IPATH_S_SIGNAL_REQ_WR;
+                       qp->s_flags = IPATH_S_SIGNAL_REQ_WR;
                else
                        qp->s_flags = 0;
                dev = to_idev(ibpd->device);
@@ -958,7 +974,7 @@ bail:
  * @wc: the WC responsible for putting the QP in this state
  *
  * Flushes the send work queue.
- * The QP s_lock should be held.
+ * The QP s_lock should be held and interrupts disabled.
  */
 
 void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc)
@@ -966,7 +982,7 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc)
        struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
        struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
 
-       ipath_dbg(KERN_INFO "Send queue error on QP%d/%d: err: %d\n",
+       ipath_dbg("Send queue error on QP%d/%d: err: %d\n",
                  qp->ibqp.qp_num, qp->remote_qpn, wc->status);
 
        spin_lock(&dev->pending_lock);
@@ -984,12 +1000,12 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc)
        wc->status = IB_WC_WR_FLUSH_ERR;
 
        while (qp->s_last != qp->s_head) {
+               wqe = get_swqe_ptr(qp, qp->s_last);
                wc->wr_id = wqe->wr.wr_id;
                wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
                ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 1);
                if (++qp->s_last >= qp->s_size)
                        qp->s_last = 0;
-               wqe = get_swqe_ptr(qp, qp->s_last);
        }
        qp->s_cur = qp->s_tail = qp->s_head;
        qp->state = IB_QPS_SQE;