diff options
author | Ishai Rabinovitz <ishai@mellanox.co.il> | 2012-11-26 05:44:53 -0500 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2012-11-30 20:40:32 -0500 |
commit | 73aa89ed9e2bebf0c3fff4504e6dff1421b5c819 (patch) | |
tree | f42868513f2d3532a1ca3e37445cf6eab7b410c4 | |
parent | ef6c49d87c3418c442a22e55e3ce2f91b163d69e (diff) |
IB/srp: destroy and recreate QP and CQs when reconnecting
HW QP FATAL errors persist over a reset operation, but we can recover
from that by recreating the QP and associated CQs for each connection.
Creating a new QP/CQ also completely forecloses any possibility of
getting stale completions or packets on the new connection.
Signed-off-by: Ishai Rabinovitz <ishai@mellanox.co.il>
Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il>
[ updated to current code from OFED, cleaned up commit message ]
Signed-off-by: David Dillow <dillowda@ornl.gov>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.c | 66 |
1 files changed, 35 insertions, 31 deletions
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 95590a38e88..85771eba9c8 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c | |||
@@ -222,27 +222,29 @@ static int srp_new_cm_id(struct srp_target_port *target) | |||
222 | static int srp_create_target_ib(struct srp_target_port *target) | 222 | static int srp_create_target_ib(struct srp_target_port *target) |
223 | { | 223 | { |
224 | struct ib_qp_init_attr *init_attr; | 224 | struct ib_qp_init_attr *init_attr; |
225 | struct ib_cq *recv_cq, *send_cq; | ||
226 | struct ib_qp *qp; | ||
225 | int ret; | 227 | int ret; |
226 | 228 | ||
227 | init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); | 229 | init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); |
228 | if (!init_attr) | 230 | if (!init_attr) |
229 | return -ENOMEM; | 231 | return -ENOMEM; |
230 | 232 | ||
231 | target->recv_cq = ib_create_cq(target->srp_host->srp_dev->dev, | 233 | recv_cq = ib_create_cq(target->srp_host->srp_dev->dev, |
232 | srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0); | 234 | srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0); |
233 | if (IS_ERR(target->recv_cq)) { | 235 | if (IS_ERR(recv_cq)) { |
234 | ret = PTR_ERR(target->recv_cq); | 236 | ret = PTR_ERR(recv_cq); |
235 | goto err; | 237 | goto err; |
236 | } | 238 | } |
237 | 239 | ||
238 | target->send_cq = ib_create_cq(target->srp_host->srp_dev->dev, | 240 | send_cq = ib_create_cq(target->srp_host->srp_dev->dev, |
239 | srp_send_completion, NULL, target, SRP_SQ_SIZE, 0); | 241 | srp_send_completion, NULL, target, SRP_SQ_SIZE, 0); |
240 | if (IS_ERR(target->send_cq)) { | 242 | if (IS_ERR(send_cq)) { |
241 | ret = PTR_ERR(target->send_cq); | 243 | ret = PTR_ERR(send_cq); |
242 | goto err_recv_cq; | 244 | goto err_recv_cq; |
243 | } | 245 | } |
244 | 246 | ||
245 | ib_req_notify_cq(target->recv_cq, IB_CQ_NEXT_COMP); | 247 | ib_req_notify_cq(recv_cq, IB_CQ_NEXT_COMP); |
246 | 248 | ||
247 | init_attr->event_handler = srp_qp_event; | 249 | init_attr->event_handler = srp_qp_event; |
248 | init_attr->cap.max_send_wr = SRP_SQ_SIZE; | 250 | init_attr->cap.max_send_wr = SRP_SQ_SIZE; |
@@ -251,30 +253,41 @@ static int srp_create_target_ib(struct srp_target_port *target) | |||
251 | init_attr->cap.max_send_sge = 1; | 253 | init_attr->cap.max_send_sge = 1; |
252 | init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; | 254 | init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; |
253 | init_attr->qp_type = IB_QPT_RC; | 255 | init_attr->qp_type = IB_QPT_RC; |
254 | init_attr->send_cq = target->send_cq; | 256 | init_attr->send_cq = send_cq; |
255 | init_attr->recv_cq = target->recv_cq; | 257 | init_attr->recv_cq = recv_cq; |
256 | 258 | ||
257 | target->qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); | 259 | qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); |
258 | if (IS_ERR(target->qp)) { | 260 | if (IS_ERR(qp)) { |
259 | ret = PTR_ERR(target->qp); | 261 | ret = PTR_ERR(qp); |
260 | goto err_send_cq; | 262 | goto err_send_cq; |
261 | } | 263 | } |
262 | 264 | ||
263 | ret = srp_init_qp(target, target->qp); | 265 | ret = srp_init_qp(target, qp); |
264 | if (ret) | 266 | if (ret) |
265 | goto err_qp; | 267 | goto err_qp; |
266 | 268 | ||
269 | if (target->qp) | ||
270 | ib_destroy_qp(target->qp); | ||
271 | if (target->recv_cq) | ||
272 | ib_destroy_cq(target->recv_cq); | ||
273 | if (target->send_cq) | ||
274 | ib_destroy_cq(target->send_cq); | ||
275 | |||
276 | target->qp = qp; | ||
277 | target->recv_cq = recv_cq; | ||
278 | target->send_cq = send_cq; | ||
279 | |||
267 | kfree(init_attr); | 280 | kfree(init_attr); |
268 | return 0; | 281 | return 0; |
269 | 282 | ||
270 | err_qp: | 283 | err_qp: |
271 | ib_destroy_qp(target->qp); | 284 | ib_destroy_qp(qp); |
272 | 285 | ||
273 | err_send_cq: | 286 | err_send_cq: |
274 | ib_destroy_cq(target->send_cq); | 287 | ib_destroy_cq(send_cq); |
275 | 288 | ||
276 | err_recv_cq: | 289 | err_recv_cq: |
277 | ib_destroy_cq(target->recv_cq); | 290 | ib_destroy_cq(recv_cq); |
278 | 291 | ||
279 | err: | 292 | err: |
280 | kfree(init_attr); | 293 | kfree(init_attr); |
@@ -289,6 +302,9 @@ static void srp_free_target_ib(struct srp_target_port *target) | |||
289 | ib_destroy_cq(target->send_cq); | 302 | ib_destroy_cq(target->send_cq); |
290 | ib_destroy_cq(target->recv_cq); | 303 | ib_destroy_cq(target->recv_cq); |
291 | 304 | ||
305 | target->qp = NULL; | ||
306 | target->send_cq = target->recv_cq = NULL; | ||
307 | |||
292 | for (i = 0; i < SRP_RQ_SIZE; ++i) | 308 | for (i = 0; i < SRP_RQ_SIZE; ++i) |
293 | srp_free_iu(target->srp_host, target->rx_ring[i]); | 309 | srp_free_iu(target->srp_host, target->rx_ring[i]); |
294 | for (i = 0; i < SRP_SQ_SIZE; ++i) | 310 | for (i = 0; i < SRP_SQ_SIZE; ++i) |
@@ -678,8 +694,6 @@ static void srp_reset_req(struct srp_target_port *target, struct srp_request *re | |||
678 | static int srp_reconnect_target(struct srp_target_port *target) | 694 | static int srp_reconnect_target(struct srp_target_port *target) |
679 | { | 695 | { |
680 | struct Scsi_Host *shost = target->scsi_host; | 696 | struct Scsi_Host *shost = target->scsi_host; |
681 | struct ib_qp_attr qp_attr; | ||
682 | struct ib_wc wc; | ||
683 | int i, ret; | 697 | int i, ret; |
684 | 698 | ||
685 | if (target->state != SRP_TARGET_LIVE) | 699 | if (target->state != SRP_TARGET_LIVE) |
@@ -696,20 +710,10 @@ static int srp_reconnect_target(struct srp_target_port *target) | |||
696 | if (ret) | 710 | if (ret) |
697 | goto unblock; | 711 | goto unblock; |
698 | 712 | ||
699 | qp_attr.qp_state = IB_QPS_RESET; | 713 | ret = srp_create_target_ib(target); |
700 | ret = ib_modify_qp(target->qp, &qp_attr, IB_QP_STATE); | ||
701 | if (ret) | ||
702 | goto unblock; | ||
703 | |||
704 | ret = srp_init_qp(target, target->qp); | ||
705 | if (ret) | 714 | if (ret) |
706 | goto unblock; | 715 | goto unblock; |
707 | 716 | ||
708 | while (ib_poll_cq(target->recv_cq, 1, &wc) > 0) | ||
709 | ; /* nothing */ | ||
710 | while (ib_poll_cq(target->send_cq, 1, &wc) > 0) | ||
711 | ; /* nothing */ | ||
712 | |||
713 | for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { | 717 | for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { |
714 | struct srp_request *req = &target->req_ring[i]; | 718 | struct srp_request *req = &target->req_ring[i]; |
715 | if (req->scmnd) | 719 | if (req->scmnd) |