Patch can be applied separately from patch to mthca, but requires other patch to work properly.
- Sean
Index: mad.c =================================================================== --- mad.c (revision 1209) +++ mad.c (working copy) @@ -90,6 +90,8 @@ struct ib_mad_send_wc *mad_send_wc); static void timeout_sends(void *data); static int solicited_mad(struct ib_mad *mad); +static int ib_mad_change_qp_state_to_rts(struct ib_qp *qp, + enum ib_qp_state cur_state);
/* * Returns a ib_mad_port_private structure or NULL for a device/port. @@ -591,6 +593,7 @@ /* Timeout will be updated after send completes */ mad_send_wr->timeout = msecs_to_jiffies(send_wr->wr. ud.timeout_ms); + mad_send_wr->retry = 0; /* One reference for each work request to QP + response */ mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0); mad_send_wr->status = IB_WC_SUCCESS; @@ -1339,6 +1342,70 @@ } }
+static void mark_sends_for_retry(struct ib_mad_qp_info *qp_info) +{ + struct ib_mad_send_wr_private *mad_send_wr; + struct ib_mad_list_head *mad_list; + int flags; + + spin_lock_irqsave(&qp_info->send_queue.lock, flags); + list_for_each_entry(mad_list, &qp_info->send_queue.list, list) { + mad_send_wr = container_of(mad_list, + struct ib_mad_send_wr_private, + mad_list); + mad_send_wr->retry = 1; + } + spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); +} + +static void mad_error_handler(struct ib_mad_port_private *port_priv, + struct ib_wc *wc) +{ + struct ib_mad_list_head *mad_list; + struct ib_mad_qp_info *qp_info; + struct ib_mad_send_wr_private *mad_send_wr; + int ret; + + /* Determine if failure was a send or receive */ + mad_list = (struct ib_mad_list_head *)(unsigned long)wc->wr_id; + qp_info = mad_list->mad_queue->qp_info; + if (mad_list->mad_queue == &qp_info->recv_queue) { + /* + * Receive errors indicate that the QP has entered the error + * state - error handling/shutdown code will cleanup. + */ + return; + } + + /* + * Send errors will transition the QP to SQE - move + * QP to RTS and repost flushed work requests. + */ + mad_send_wr = container_of(mad_list, struct ib_mad_send_wr_private, + mad_list); + if (wc->status == IB_WC_WR_FLUSH_ERR) { + if (mad_send_wr->retry) { + /* Repost send. */ + struct ib_send_wr *bad_send_wr; + + mad_send_wr->retry = 0; + ret = ib_post_send(qp_info->qp, &mad_send_wr->send_wr, + &bad_send_wr); + if (ret) + ib_mad_send_done_handler(port_priv, wc); + } else + ib_mad_send_done_handler(port_priv, wc); + } else { + /* Transition QP to RTS and fail offending send. */ + ret = ib_mad_change_qp_state_to_rts(qp_info->qp, IB_QPS_SQE); + if (ret) + printk(KERN_ERR PFX "mad_error_handler - unable to " + "transition QP to RTS : %d\n", ret); + ib_mad_send_done_handler(port_priv, wc); + mark_sends_for_retry(qp_info); + } +} + /* * IB MAD completion callback */ @@ -1346,34 +1413,25 @@ { struct ib_mad_port_private *port_priv; struct ib_wc wc; - struct ib_mad_list_head *mad_list; - struct ib_mad_qp_info *qp_info;
port_priv = (struct ib_mad_port_private*)data; ib_req_notify_cq(port_priv->cq, IB_CQ_NEXT_COMP); while (ib_poll_cq(port_priv->cq, 1, &wc) == 1) { - if (wc.status != IB_WC_SUCCESS) { - /* Determine if failure was a send or receive */ - mad_list = (struct ib_mad_list_head *) - (unsigned long)wc.wr_id; - qp_info = mad_list->mad_queue->qp_info; - if (mad_list->mad_queue == &qp_info->send_queue) - wc.opcode = IB_WC_SEND; - else - wc.opcode = IB_WC_RECV; - } - switch (wc.opcode) { - case IB_WC_SEND: - ib_mad_send_done_handler(port_priv, &wc); - break; - case IB_WC_RECV: - ib_mad_recv_done_handler(port_priv, &wc); - break; - default: - BUG_ON(1); - break; - } + if (wc.status == IB_WC_SUCCESS) { + switch (wc.opcode) { + case IB_WC_SEND: + ib_mad_send_done_handler(port_priv, &wc); + break; + case IB_WC_RECV: + ib_mad_recv_done_handler(port_priv, &wc); + break; + default: + BUG_ON(1); + break; + } + } else + mad_error_handler(port_priv, &wc); } }
@@ -1717,7 +1775,8 @@ /* * Modify QP into Ready-To-Send state */ -static inline int ib_mad_change_qp_state_to_rts(struct ib_qp *qp) +static int ib_mad_change_qp_state_to_rts(struct ib_qp *qp, + enum ib_qp_state cur_state) { int ret; struct ib_qp_attr *attr; @@ -1729,11 +1788,12 @@ "ib_qp_attr\n"); return -ENOMEM; } - attr->qp_state = IB_QPS_RTS; - attr->sq_psn = IB_MAD_SEND_Q_PSN; - attr_mask = IB_QP_STATE | IB_QP_SQ_PSN; - + attr_mask = IB_QP_STATE; + if (cur_state == IB_QPS_RTR) { + attr->sq_psn = IB_MAD_SEND_Q_PSN; + attr_mask |= IB_QP_SQ_PSN; + } ret = ib_modify_qp(qp, attr, attr_mask); kfree(attr);
@@ -1793,7 +1853,8 @@ goto error; }
- ret = ib_mad_change_qp_state_to_rts(port_priv->qp_info[i].qp); + ret = ib_mad_change_qp_state_to_rts(port_priv->qp_info[i].qp, + IB_QPS_RTR); if (ret) { printk(KERN_ERR PFX "Couldn't change QP%d state to " "RTS\n", i); @@ -1852,6 +1913,15 @@ } }
+static void qp_event_handler(struct ib_event *event, void *qp_context) +{ + struct ib_mad_qp_info *qp_info = qp_context; + + /* It's worse than that! He's dead, Jim! */ + printk(KERN_ERR PFX "Fatal error (%d) on MAD QP (%d)\n", + event->event, qp_info->qp->qp_num); +} + static void init_mad_queue(struct ib_mad_qp_info *qp_info, struct ib_mad_queue *mad_queue) { @@ -1884,6 +1954,8 @@ qp_init_attr.cap.max_recv_sge = IB_MAD_RECV_REQ_MAX_SG; qp_init_attr.qp_type = qp_type; qp_init_attr.port_num = port_priv->port_num; + qp_init_attr.qp_context = qp_info; + qp_init_attr.event_handler = qp_event_handler; qp_info->qp = ib_create_qp(port_priv->pd, &qp_init_attr); if (IS_ERR(qp_info->qp)) { printk(KERN_ERR PFX "Couldn't create ib_mad QP%d\n", Index: mad_priv.h =================================================================== --- mad_priv.h (revision 1209) +++ mad_priv.h (working copy) @@ -127,6 +127,7 @@ u64 wr_id; /* client WR ID */ u64 tid; unsigned long timeout; + int retry; int refcount; enum ib_wc_status status; };
_______________________________________________ openib-general mailing list [EMAIL PROTECTED] http://openib.org/mailman/listinfo/openib-general
To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general