Commit | Line | Data |
---|---|---|
f94b533d TT |
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) { | |
41 | case C2_CONN_STATUS_SUCCESS: | |
42 | return 0; | |
43 | case C2_CONN_STATUS_REJECTED: | |
44 | return -ENETRESET; | |
45 | case C2_CONN_STATUS_REFUSED: | |
46 | return -ECONNREFUSED; | |
47 | case C2_CONN_STATUS_TIMEDOUT: | |
48 | return -ETIMEDOUT; | |
49 | case C2_CONN_STATUS_NETUNREACH: | |
50 | return -ENETUNREACH; | |
51 | case C2_CONN_STATUS_HOSTUNREACH: | |
52 | return -EHOSTUNREACH; | |
53 | case C2_CONN_STATUS_INVALID_RNIC: | |
54 | return -EINVAL; | |
55 | case C2_CONN_STATUS_INVALID_QP: | |
56 | return -EINVAL; | |
57 | case C2_CONN_STATUS_INVALID_QP_STATE: | |
58 | return -EINVAL; | |
59 | case C2_CONN_STATUS_ADDR_NOT_AVAIL: | |
60 | return -EADDRNOTAVAIL; | |
61 | default: | |
62 | printk(KERN_ERR PFX | |
63 | "%s - Unable to convert CM status: %d\n", | |
33718363 | 64 | __func__, c2_status); |
f94b533d TT |
65 | return -EIO; |
66 | } | |
67 | } | |
68 | ||
f94b533d TT |
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 || | |
120 | event > CCAE_RNIC_CATASTROPHIC_ERROR) | |
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"; | |
132 | case C2_QP_STATE_CONNECTING: | |
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"; | |
138 | case C2_QP_STATE_TERMINATE: | |
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 | } | |
f94b533d TT |
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 | * retreive 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; | |
186 | struct c2wr_ae_active_connect_results *res; | |
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", | |
33718363 | 196 | __func__, |
f94b533d | 197 | to_event_str(event_id), |
dc544bc9 | 198 | (unsigned long long) wr->ae.ae_generic.user_context, |
f94b533d TT |
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) { | |
206 | case CCAE_ACTIVE_CONNECT_RESULTS: | |
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 = | |
215 | be32_to_cpu(res->private_data_length); | |
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; | |
230 | case CCAE_TERMINATE_MESSAGE_RECEIVED: | |
231 | case CCAE_CQ_SQ_COMPLETION_OVERFLOW: | |
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: | |
242 | case CCAE_LLP_CLOSE_COMPLETE: | |
243 | case CCAE_LLP_CONNECTION_RESET: | |
244 | case CCAE_LLP_CONNECTION_LOST: | |
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", | |
33718363 | 262 | __func__, __LINE__, |
f94b533d TT |
263 | event_id, qp, cm_id); |
264 | break; | |
265 | } | |
266 | break; | |
267 | } | |
268 | ||
269 | case C2_RES_IND_EP:{ | |
270 | ||
271 | struct c2wr_ae_connection_request *req = | |
272 | &wr->ae.ae_connection_request; | |
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", | |
33718363 | 279 | __func__, event_id); |
f94b533d TT |
280 | break; |
281 | } | |
282 | cm_event.event = IW_CM_EVENT_CONNECT_REQUEST; | |
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 = | |
289 | be32_to_cpu(req->private_data_length); | |
290 | cm_event.private_data = req->private_data; | |
291 | ||
292 | if (cm_id->event_handler) | |
293 | cm_id->event_handler(cm_id, &cm_event); | |
294 | break; | |
295 | } | |
296 | ||
297 | case C2_RES_IND_CQ:{ | |
298 | struct c2_cq *cq = | |
299 | (struct c2_cq *) resource_user_context; | |
300 | ||
301 | pr_debug("IB_EVENT_CQ_ERR\n"); | |
302 | ib_event.device = &c2dev->ibdev; | |
303 | ib_event.element.cq = &cq->ibcq; | |
304 | ib_event.event = IB_EVENT_CQ_ERR; | |
305 | ||
306 | if (cq->ibcq.event_handler) | |
307 | cq->ibcq.event_handler(&ib_event, | |
308 | cq->ibcq.cq_context); | |
309 | } | |
310 | ||
311 | default: | |
312 | printk("Bad resource indicator = %d\n", | |
313 | resource_indicator); | |
314 | break; | |
315 | } | |
316 | ||
317 | ignore_it: | |
318 | c2_mq_free(mq); | |
319 | } |