diff options
author | Ralph Campbell <ralph.campbell@qlogic.com> | 2008-05-13 14:40:25 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-05-13 14:40:25 -0400 |
commit | 53dc1ca194c062aa9771e194047f27ec1ca592df (patch) | |
tree | 4cf0fe73ea76f02f871d5e6def040a869b224f00 /drivers/infiniband/hw/ipath/ipath_ruc.c | |
parent | dd37818dbdf8e51d0288c0197c351c005ffcdbdb (diff) |
IB/ipath: Fix RC and UC error handling
When errors are detected in RC, the QP should transition to the
IB_QPS_ERR state, not the IB_QPS_SQE state. Also, when the error is on
the responder side, the receive work completion error was incorrect
(remote vs. local).
Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_ruc.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_ruc.c | 165 |
1 files changed, 79 insertions, 86 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index 9e3fe61cbd08..c716a03dd399 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved. | 2 | * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved. |
3 | * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. | 3 | * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. |
4 | * | 4 | * |
5 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
@@ -140,20 +140,11 @@ int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe, | |||
140 | goto bail; | 140 | goto bail; |
141 | 141 | ||
142 | bad_lkey: | 142 | bad_lkey: |
143 | memset(&wc, 0, sizeof(wc)); | ||
143 | wc.wr_id = wqe->wr_id; | 144 | wc.wr_id = wqe->wr_id; |
144 | wc.status = IB_WC_LOC_PROT_ERR; | 145 | wc.status = IB_WC_LOC_PROT_ERR; |
145 | wc.opcode = IB_WC_RECV; | 146 | wc.opcode = IB_WC_RECV; |
146 | wc.vendor_err = 0; | ||
147 | wc.byte_len = 0; | ||
148 | wc.imm_data = 0; | ||
149 | wc.qp = &qp->ibqp; | 147 | wc.qp = &qp->ibqp; |
150 | wc.src_qp = 0; | ||
151 | wc.wc_flags = 0; | ||
152 | wc.pkey_index = 0; | ||
153 | wc.slid = 0; | ||
154 | wc.sl = 0; | ||
155 | wc.dlid_path_bits = 0; | ||
156 | wc.port_num = 0; | ||
157 | /* Signal solicited completion event. */ | 148 | /* Signal solicited completion event. */ |
158 | ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); | 149 | ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); |
159 | ret = 0; | 150 | ret = 0; |
@@ -270,6 +261,7 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp) | |||
270 | struct ib_wc wc; | 261 | struct ib_wc wc; |
271 | u64 sdata; | 262 | u64 sdata; |
272 | atomic64_t *maddr; | 263 | atomic64_t *maddr; |
264 | enum ib_wc_status send_status; | ||
273 | 265 | ||
274 | qp = ipath_lookup_qpn(&dev->qp_table, sqp->remote_qpn); | 266 | qp = ipath_lookup_qpn(&dev->qp_table, sqp->remote_qpn); |
275 | if (!qp) { | 267 | if (!qp) { |
@@ -300,8 +292,8 @@ again: | |||
300 | wqe = get_swqe_ptr(sqp, sqp->s_last); | 292 | wqe = get_swqe_ptr(sqp, sqp->s_last); |
301 | spin_unlock_irqrestore(&sqp->s_lock, flags); | 293 | spin_unlock_irqrestore(&sqp->s_lock, flags); |
302 | 294 | ||
303 | wc.wc_flags = 0; | 295 | memset(&wc, 0, sizeof wc); |
304 | wc.imm_data = 0; | 296 | send_status = IB_WC_SUCCESS; |
305 | 297 | ||
306 | sqp->s_sge.sge = wqe->sg_list[0]; | 298 | sqp->s_sge.sge = wqe->sg_list[0]; |
307 | sqp->s_sge.sg_list = wqe->sg_list + 1; | 299 | sqp->s_sge.sg_list = wqe->sg_list + 1; |
@@ -313,75 +305,33 @@ again: | |||
313 | wc.imm_data = wqe->wr.ex.imm_data; | 305 | wc.imm_data = wqe->wr.ex.imm_data; |
314 | /* FALLTHROUGH */ | 306 | /* FALLTHROUGH */ |
315 | case IB_WR_SEND: | 307 | case IB_WR_SEND: |
316 | if (!ipath_get_rwqe(qp, 0)) { | 308 | if (!ipath_get_rwqe(qp, 0)) |
317 | rnr_nak: | 309 | goto rnr_nak; |
318 | /* Handle RNR NAK */ | ||
319 | if (qp->ibqp.qp_type == IB_QPT_UC) | ||
320 | goto send_comp; | ||
321 | if (sqp->s_rnr_retry == 0) { | ||
322 | wc.status = IB_WC_RNR_RETRY_EXC_ERR; | ||
323 | goto err; | ||
324 | } | ||
325 | if (sqp->s_rnr_retry_cnt < 7) | ||
326 | sqp->s_rnr_retry--; | ||
327 | dev->n_rnr_naks++; | ||
328 | sqp->s_rnr_timeout = | ||
329 | ib_ipath_rnr_table[qp->r_min_rnr_timer]; | ||
330 | ipath_insert_rnr_queue(sqp); | ||
331 | goto done; | ||
332 | } | ||
333 | break; | 310 | break; |
334 | 311 | ||
335 | case IB_WR_RDMA_WRITE_WITH_IMM: | 312 | case IB_WR_RDMA_WRITE_WITH_IMM: |
336 | if (unlikely(!(qp->qp_access_flags & | 313 | if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) |
337 | IB_ACCESS_REMOTE_WRITE))) { | 314 | goto inv_err; |
338 | wc.status = IB_WC_REM_INV_REQ_ERR; | ||
339 | goto err; | ||
340 | } | ||
341 | wc.wc_flags = IB_WC_WITH_IMM; | 315 | wc.wc_flags = IB_WC_WITH_IMM; |
342 | wc.imm_data = wqe->wr.ex.imm_data; | 316 | wc.imm_data = wqe->wr.ex.imm_data; |
343 | if (!ipath_get_rwqe(qp, 1)) | 317 | if (!ipath_get_rwqe(qp, 1)) |
344 | goto rnr_nak; | 318 | goto rnr_nak; |
345 | /* FALLTHROUGH */ | 319 | /* FALLTHROUGH */ |
346 | case IB_WR_RDMA_WRITE: | 320 | case IB_WR_RDMA_WRITE: |
347 | if (unlikely(!(qp->qp_access_flags & | 321 | if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) |
348 | IB_ACCESS_REMOTE_WRITE))) { | 322 | goto inv_err; |
349 | wc.status = IB_WC_REM_INV_REQ_ERR; | ||
350 | goto err; | ||
351 | } | ||
352 | if (wqe->length == 0) | 323 | if (wqe->length == 0) |
353 | break; | 324 | break; |
354 | if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, wqe->length, | 325 | if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, wqe->length, |
355 | wqe->wr.wr.rdma.remote_addr, | 326 | wqe->wr.wr.rdma.remote_addr, |
356 | wqe->wr.wr.rdma.rkey, | 327 | wqe->wr.wr.rdma.rkey, |
357 | IB_ACCESS_REMOTE_WRITE))) { | 328 | IB_ACCESS_REMOTE_WRITE))) |
358 | acc_err: | 329 | goto acc_err; |
359 | wc.status = IB_WC_REM_ACCESS_ERR; | ||
360 | err: | ||
361 | wc.wr_id = wqe->wr.wr_id; | ||
362 | wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; | ||
363 | wc.vendor_err = 0; | ||
364 | wc.byte_len = 0; | ||
365 | wc.qp = &sqp->ibqp; | ||
366 | wc.src_qp = sqp->remote_qpn; | ||
367 | wc.pkey_index = 0; | ||
368 | wc.slid = sqp->remote_ah_attr.dlid; | ||
369 | wc.sl = sqp->remote_ah_attr.sl; | ||
370 | wc.dlid_path_bits = 0; | ||
371 | wc.port_num = 0; | ||
372 | spin_lock_irqsave(&sqp->s_lock, flags); | ||
373 | ipath_sqerror_qp(sqp, &wc); | ||
374 | spin_unlock_irqrestore(&sqp->s_lock, flags); | ||
375 | goto done; | ||
376 | } | ||
377 | break; | 330 | break; |
378 | 331 | ||
379 | case IB_WR_RDMA_READ: | 332 | case IB_WR_RDMA_READ: |
380 | if (unlikely(!(qp->qp_access_flags & | 333 | if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ))) |
381 | IB_ACCESS_REMOTE_READ))) { | 334 | goto inv_err; |
382 | wc.status = IB_WC_REM_INV_REQ_ERR; | ||
383 | goto err; | ||
384 | } | ||
385 | if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length, | 335 | if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length, |
386 | wqe->wr.wr.rdma.remote_addr, | 336 | wqe->wr.wr.rdma.remote_addr, |
387 | wqe->wr.wr.rdma.rkey, | 337 | wqe->wr.wr.rdma.rkey, |
@@ -394,11 +344,8 @@ again: | |||
394 | 344 | ||
395 | case IB_WR_ATOMIC_CMP_AND_SWP: | 345 | case IB_WR_ATOMIC_CMP_AND_SWP: |
396 | case IB_WR_ATOMIC_FETCH_AND_ADD: | 346 | case IB_WR_ATOMIC_FETCH_AND_ADD: |
397 | if (unlikely(!(qp->qp_access_flags & | 347 | if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) |
398 | IB_ACCESS_REMOTE_ATOMIC))) { | 348 | goto inv_err; |
399 | wc.status = IB_WC_REM_INV_REQ_ERR; | ||
400 | goto err; | ||
401 | } | ||
402 | if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64), | 349 | if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64), |
403 | wqe->wr.wr.atomic.remote_addr, | 350 | wqe->wr.wr.atomic.remote_addr, |
404 | wqe->wr.wr.atomic.rkey, | 351 | wqe->wr.wr.atomic.rkey, |
@@ -415,7 +362,8 @@ again: | |||
415 | goto send_comp; | 362 | goto send_comp; |
416 | 363 | ||
417 | default: | 364 | default: |
418 | goto done; | 365 | send_status = IB_WC_LOC_QP_OP_ERR; |
366 | goto serr; | ||
419 | } | 367 | } |
420 | 368 | ||
421 | sge = &sqp->s_sge.sge; | 369 | sge = &sqp->s_sge.sge; |
@@ -458,14 +406,11 @@ again: | |||
458 | wc.opcode = IB_WC_RECV; | 406 | wc.opcode = IB_WC_RECV; |
459 | wc.wr_id = qp->r_wr_id; | 407 | wc.wr_id = qp->r_wr_id; |
460 | wc.status = IB_WC_SUCCESS; | 408 | wc.status = IB_WC_SUCCESS; |
461 | wc.vendor_err = 0; | ||
462 | wc.byte_len = wqe->length; | 409 | wc.byte_len = wqe->length; |
463 | wc.qp = &qp->ibqp; | 410 | wc.qp = &qp->ibqp; |
464 | wc.src_qp = qp->remote_qpn; | 411 | wc.src_qp = qp->remote_qpn; |
465 | wc.pkey_index = 0; | ||
466 | wc.slid = qp->remote_ah_attr.dlid; | 412 | wc.slid = qp->remote_ah_attr.dlid; |
467 | wc.sl = qp->remote_ah_attr.sl; | 413 | wc.sl = qp->remote_ah_attr.sl; |
468 | wc.dlid_path_bits = 0; | ||
469 | wc.port_num = 1; | 414 | wc.port_num = 1; |
470 | /* Signal completion event if the solicited bit is set. */ | 415 | /* Signal completion event if the solicited bit is set. */ |
471 | ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, | 416 | ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, |
@@ -473,9 +418,63 @@ again: | |||
473 | 418 | ||
474 | send_comp: | 419 | send_comp: |
475 | sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; | 420 | sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; |
476 | ipath_send_complete(sqp, wqe, IB_WC_SUCCESS); | 421 | ipath_send_complete(sqp, wqe, send_status); |
477 | goto again; | 422 | goto again; |
478 | 423 | ||
424 | rnr_nak: | ||
425 | /* Handle RNR NAK */ | ||
426 | if (qp->ibqp.qp_type == IB_QPT_UC) | ||
427 | goto send_comp; | ||
428 | /* | ||
429 | * Note: we don't need the s_lock held since the BUSY flag | ||
430 | * makes this single threaded. | ||
431 | */ | ||
432 | if (sqp->s_rnr_retry == 0) { | ||
433 | send_status = IB_WC_RNR_RETRY_EXC_ERR; | ||
434 | goto serr; | ||
435 | } | ||
436 | if (sqp->s_rnr_retry_cnt < 7) | ||
437 | sqp->s_rnr_retry--; | ||
438 | spin_lock_irqsave(&sqp->s_lock, flags); | ||
439 | if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_RECV_OK)) | ||
440 | goto unlock; | ||
441 | dev->n_rnr_naks++; | ||
442 | sqp->s_rnr_timeout = ib_ipath_rnr_table[qp->r_min_rnr_timer]; | ||
443 | ipath_insert_rnr_queue(sqp); | ||
444 | goto unlock; | ||
445 | |||
446 | inv_err: | ||
447 | send_status = IB_WC_REM_INV_REQ_ERR; | ||
448 | wc.status = IB_WC_LOC_QP_OP_ERR; | ||
449 | goto err; | ||
450 | |||
451 | acc_err: | ||
452 | send_status = IB_WC_REM_ACCESS_ERR; | ||
453 | wc.status = IB_WC_LOC_PROT_ERR; | ||
454 | err: | ||
455 | /* responder goes to error state */ | ||
456 | ipath_rc_error(qp, wc.status); | ||
457 | |||
458 | serr: | ||
459 | spin_lock_irqsave(&sqp->s_lock, flags); | ||
460 | ipath_send_complete(sqp, wqe, send_status); | ||
461 | if (sqp->ibqp.qp_type == IB_QPT_RC) { | ||
462 | int lastwqe = ipath_error_qp(sqp, IB_WC_WR_FLUSH_ERR); | ||
463 | |||
464 | sqp->s_flags &= ~IPATH_S_BUSY; | ||
465 | spin_unlock_irqrestore(&sqp->s_lock, flags); | ||
466 | if (lastwqe) { | ||
467 | struct ib_event ev; | ||
468 | |||
469 | ev.device = sqp->ibqp.device; | ||
470 | ev.element.qp = &sqp->ibqp; | ||
471 | ev.event = IB_EVENT_QP_LAST_WQE_REACHED; | ||
472 | sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context); | ||
473 | } | ||
474 | goto done; | ||
475 | } | ||
476 | unlock: | ||
477 | spin_unlock_irqrestore(&sqp->s_lock, flags); | ||
479 | done: | 478 | done: |
480 | if (atomic_dec_and_test(&qp->refcount)) | 479 | if (atomic_dec_and_test(&qp->refcount)) |
481 | wake_up(&qp->wait); | 480 | wake_up(&qp->wait); |
@@ -651,21 +650,15 @@ void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe, | |||
651 | status != IB_WC_SUCCESS) { | 650 | status != IB_WC_SUCCESS) { |
652 | struct ib_wc wc; | 651 | struct ib_wc wc; |
653 | 652 | ||
653 | memset(&wc, 0, sizeof wc); | ||
654 | wc.wr_id = wqe->wr.wr_id; | 654 | wc.wr_id = wqe->wr.wr_id; |
655 | wc.status = status; | 655 | wc.status = status; |
656 | wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; | 656 | wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; |
657 | wc.vendor_err = 0; | ||
658 | wc.byte_len = wqe->length; | ||
659 | wc.imm_data = 0; | ||
660 | wc.qp = &qp->ibqp; | 657 | wc.qp = &qp->ibqp; |
661 | wc.src_qp = 0; | 658 | if (status == IB_WC_SUCCESS) |
662 | wc.wc_flags = 0; | 659 | wc.byte_len = wqe->length; |
663 | wc.pkey_index = 0; | 660 | ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, |
664 | wc.slid = 0; | 661 | status != IB_WC_SUCCESS); |
665 | wc.sl = 0; | ||
666 | wc.dlid_path_bits = 0; | ||
667 | wc.port_num = 0; | ||
668 | ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0); | ||
669 | } | 662 | } |
670 | 663 | ||
671 | spin_lock_irqsave(&qp->s_lock, flags); | 664 | spin_lock_irqsave(&qp->s_lock, flags); |