Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
c2_ae.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
3  * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
4  *
5  * This software is available to you under a choice of one of two
6  * licenses. You may choose to be licensed under the terms of the GNU
7  * General Public License (GPL) Version 2, available from the file
8  * COPYING in the main directory of this source tree, or the
9  * OpenIB.org BSD license below:
10  *
11  * Redistribution and use in source and binary forms, with or
12  * without modification, are permitted provided that the following
13  * conditions are met:
14  *
15  * - Redistributions of source code must retain the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer.
18  *
19  * - Redistributions in binary form must reproduce the above
20  * copyright notice, this list of conditions and the following
21  * disclaimer in the documentation and/or other materials
22  * provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33 #include "c2.h"
34 #include <rdma/iw_cm.h>
35 #include "c2_status.h"
36 #include "c2_ae.h"
37 
38 static int c2_convert_cm_status(u32 c2_status)
39 {
40  switch (c2_status) {
42  return 0;
44  return -ENETRESET;
46  return -ECONNREFUSED;
48  return -ETIMEDOUT;
50  return -ENETUNREACH;
52  return -EHOSTUNREACH;
54  return -EINVAL;
56  return -EINVAL;
58  return -EINVAL;
60  return -EADDRNOTAVAIL;
61  default:
63  "%s - Unable to convert CM status: %d\n",
64  __func__, c2_status);
65  return -EIO;
66  }
67 }
68 
69 static const char* to_event_str(int event)
70 {
71  static const char* event_str[] = {
72  "CCAE_REMOTE_SHUTDOWN",
73  "CCAE_ACTIVE_CONNECT_RESULTS",
74  "CCAE_CONNECTION_REQUEST",
75  "CCAE_LLP_CLOSE_COMPLETE",
76  "CCAE_TERMINATE_MESSAGE_RECEIVED",
77  "CCAE_LLP_CONNECTION_RESET",
78  "CCAE_LLP_CONNECTION_LOST",
79  "CCAE_LLP_SEGMENT_SIZE_INVALID",
80  "CCAE_LLP_INVALID_CRC",
81  "CCAE_LLP_BAD_FPDU",
82  "CCAE_INVALID_DDP_VERSION",
83  "CCAE_INVALID_RDMA_VERSION",
84  "CCAE_UNEXPECTED_OPCODE",
85  "CCAE_INVALID_DDP_QUEUE_NUMBER",
86  "CCAE_RDMA_READ_NOT_ENABLED",
87  "CCAE_RDMA_WRITE_NOT_ENABLED",
88  "CCAE_RDMA_READ_TOO_SMALL",
89  "CCAE_NO_L_BIT",
90  "CCAE_TAGGED_INVALID_STAG",
91  "CCAE_TAGGED_BASE_BOUNDS_VIOLATION",
92  "CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION",
93  "CCAE_TAGGED_INVALID_PD",
94  "CCAE_WRAP_ERROR",
95  "CCAE_BAD_CLOSE",
96  "CCAE_BAD_LLP_CLOSE",
97  "CCAE_INVALID_MSN_RANGE",
98  "CCAE_INVALID_MSN_GAP",
99  "CCAE_IRRQ_OVERFLOW",
100  "CCAE_IRRQ_MSN_GAP",
101  "CCAE_IRRQ_MSN_RANGE",
102  "CCAE_IRRQ_INVALID_STAG",
103  "CCAE_IRRQ_BASE_BOUNDS_VIOLATION",
104  "CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION",
105  "CCAE_IRRQ_INVALID_PD",
106  "CCAE_IRRQ_WRAP_ERROR",
107  "CCAE_CQ_SQ_COMPLETION_OVERFLOW",
108  "CCAE_CQ_RQ_COMPLETION_ERROR",
109  "CCAE_QP_SRQ_WQE_ERROR",
110  "CCAE_QP_LOCAL_CATASTROPHIC_ERROR",
111  "CCAE_CQ_OVERFLOW",
112  "CCAE_CQ_OPERATION_ERROR",
113  "CCAE_SRQ_LIMIT_REACHED",
114  "CCAE_QP_RQ_LIMIT_REACHED",
115  "CCAE_SRQ_CATASTROPHIC_ERROR",
116  "CCAE_RNIC_CATASTROPHIC_ERROR"
117  };
118 
119  if (event < CCAE_REMOTE_SHUTDOWN ||
121  return "<invalid event>";
122 
123  event -= CCAE_REMOTE_SHUTDOWN;
124  return event_str[event];
125 }
126 
127 static const char *to_qp_state_str(int state)
128 {
129  switch (state) {
130  case C2_QP_STATE_IDLE:
131  return "C2_QP_STATE_IDLE";
133  return "C2_QP_STATE_CONNECTING";
134  case C2_QP_STATE_RTS:
135  return "C2_QP_STATE_RTS";
136  case C2_QP_STATE_CLOSING:
137  return "C2_QP_STATE_CLOSING";
139  return "C2_QP_STATE_TERMINATE";
140  case C2_QP_STATE_ERROR:
141  return "C2_QP_STATE_ERROR";
142  default:
143  return "<invalid QP state>";
144  };
145 }
146 
147 void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
148 {
149  struct c2_mq *mq = c2dev->qptr_array[mq_index];
150  union c2wr *wr;
151  void *resource_user_context;
152  struct iw_cm_event cm_event;
153  struct ib_event ib_event;
154  enum c2_resource_indicator resource_indicator;
155  enum c2_event_id event_id;
156  unsigned long flags;
157  int status;
158 
159  /*
160  * retrieve the message
161  */
162  wr = c2_mq_consume(mq);
163  if (!wr)
164  return;
165 
166  memset(&ib_event, 0, sizeof(ib_event));
167  memset(&cm_event, 0, sizeof(cm_event));
168 
169  event_id = c2_wr_get_id(wr);
170  resource_indicator = be32_to_cpu(wr->ae.ae_generic.resource_type);
171  resource_user_context =
172  (void *) (unsigned long) wr->ae.ae_generic.user_context;
173 
174  status = cm_event.status = c2_convert_cm_status(c2_wr_get_result(wr));
175 
176  pr_debug("event received c2_dev=%p, event_id=%d, "
177  "resource_indicator=%d, user_context=%p, status = %d\n",
178  c2dev, event_id, resource_indicator, resource_user_context,
179  status);
180 
181  switch (resource_indicator) {
182  case C2_RES_IND_QP:{
183 
184  struct c2_qp *qp = (struct c2_qp *)resource_user_context;
185  struct iw_cm_id *cm_id = qp->cm_id;
187 
188  if (!cm_id) {
189  pr_debug("event received, but cm_id is <nul>, qp=%p!\n",
190  qp);
191  goto ignore_it;
192  }
193  pr_debug("%s: event = %s, user_context=%llx, "
194  "resource_type=%x, "
195  "resource=%x, qp_state=%s\n",
196  __func__,
197  to_event_str(event_id),
198  (unsigned long long) wr->ae.ae_generic.user_context,
199  be32_to_cpu(wr->ae.ae_generic.resource_type),
200  be32_to_cpu(wr->ae.ae_generic.resource),
201  to_qp_state_str(be32_to_cpu(wr->ae.ae_generic.qp_state)));
202 
203  c2_set_qp_state(qp, be32_to_cpu(wr->ae.ae_generic.qp_state));
204 
205  switch (event_id) {
207  res = &wr->ae.ae_active_connect_results;
208  cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
209  cm_event.local_addr.sin_addr.s_addr = res->laddr;
210  cm_event.remote_addr.sin_addr.s_addr = res->raddr;
211  cm_event.local_addr.sin_port = res->lport;
212  cm_event.remote_addr.sin_port = res->rport;
213  if (status == 0) {
214  cm_event.private_data_len =
216  cm_event.private_data = res->private_data;
217  } else {
218  spin_lock_irqsave(&qp->lock, flags);
219  if (qp->cm_id) {
220  qp->cm_id->rem_ref(qp->cm_id);
221  qp->cm_id = NULL;
222  }
223  spin_unlock_irqrestore(&qp->lock, flags);
224  cm_event.private_data_len = 0;
225  cm_event.private_data = NULL;
226  }
227  if (cm_id->event_handler)
228  cm_id->event_handler(cm_id, &cm_event);
229  break;
232  ib_event.device = &c2dev->ibdev;
233  ib_event.element.qp = &qp->ibqp;
234  ib_event.event = IB_EVENT_QP_REQ_ERR;
235 
236  if (qp->ibqp.event_handler)
237  qp->ibqp.event_handler(&ib_event,
238  qp->ibqp.
239  qp_context);
240  break;
241  case CCAE_BAD_CLOSE:
245  BUG_ON(cm_id->event_handler==(void*)0x6b6b6b6b);
246 
247  spin_lock_irqsave(&qp->lock, flags);
248  if (qp->cm_id) {
249  qp->cm_id->rem_ref(qp->cm_id);
250  qp->cm_id = NULL;
251  }
252  spin_unlock_irqrestore(&qp->lock, flags);
253  cm_event.event = IW_CM_EVENT_CLOSE;
254  cm_event.status = 0;
255  if (cm_id->event_handler)
256  cm_id->event_handler(cm_id, &cm_event);
257  break;
258  default:
259  BUG_ON(1);
260  pr_debug("%s:%d Unexpected event_id=%d on QP=%p, "
261  "CM_ID=%p\n",
262  __func__, __LINE__,
263  event_id, qp, cm_id);
264  break;
265  }
266  break;
267  }
268 
269  case C2_RES_IND_EP:{
270 
273  struct iw_cm_id *cm_id =
274  (struct iw_cm_id *)resource_user_context;
275 
276  pr_debug("C2_RES_IND_EP event_id=%d\n", event_id);
277  if (event_id != CCAE_CONNECTION_REQUEST) {
278  pr_debug("%s: Invalid event_id: %d\n",
279  __func__, event_id);
280  break;
281  }
283  cm_event.provider_data = (void*)(unsigned long)req->cr_handle;
284  cm_event.local_addr.sin_addr.s_addr = req->laddr;
285  cm_event.remote_addr.sin_addr.s_addr = req->raddr;
286  cm_event.local_addr.sin_port = req->lport;
287  cm_event.remote_addr.sin_port = req->rport;
288  cm_event.private_data_len =
290  cm_event.private_data = req->private_data;
291  /*
292  * Until ird/ord negotiation via MPAv2 support is added, send
293  * max supported values
294  */
295  cm_event.ird = cm_event.ord = 128;
296 
297  if (cm_id->event_handler)
298  cm_id->event_handler(cm_id, &cm_event);
299  break;
300  }
301 
302  case C2_RES_IND_CQ:{
303  struct c2_cq *cq =
304  (struct c2_cq *) resource_user_context;
305 
306  pr_debug("IB_EVENT_CQ_ERR\n");
307  ib_event.device = &c2dev->ibdev;
308  ib_event.element.cq = &cq->ibcq;
309  ib_event.event = IB_EVENT_CQ_ERR;
310 
311  if (cq->ibcq.event_handler)
312  cq->ibcq.event_handler(&ib_event,
313  cq->ibcq.cq_context);
314  }
315 
316  default:
317  printk("Bad resource indicator = %d\n",
318  resource_indicator);
319  break;
320  }
321 
322  ignore_it:
323  c2_mq_free(mq);
324 }