]>
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>"; | |
2b50176d | 144 | } |
f94b533d | 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; | |
24d44a39 SW |
158 | struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_event.local_addr; |
159 | struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_event.remote_addr; | |
f94b533d TT |
160 | |
161 | /* | |
25985edc | 162 | * retrieve the message |
f94b533d TT |
163 | */ |
164 | wr = c2_mq_consume(mq); | |
165 | if (!wr) | |
166 | return; | |
167 | ||
168 | memset(&ib_event, 0, sizeof(ib_event)); | |
169 | memset(&cm_event, 0, sizeof(cm_event)); | |
170 | ||
171 | event_id = c2_wr_get_id(wr); | |
172 | resource_indicator = be32_to_cpu(wr->ae.ae_generic.resource_type); | |
173 | resource_user_context = | |
174 | (void *) (unsigned long) wr->ae.ae_generic.user_context; | |
175 | ||
176 | status = cm_event.status = c2_convert_cm_status(c2_wr_get_result(wr)); | |
177 | ||
178 | pr_debug("event received c2_dev=%p, event_id=%d, " | |
179 | "resource_indicator=%d, user_context=%p, status = %d\n", | |
180 | c2dev, event_id, resource_indicator, resource_user_context, | |
181 | status); | |
182 | ||
183 | switch (resource_indicator) { | |
184 | case C2_RES_IND_QP:{ | |
185 | ||
25122333 | 186 | struct c2_qp *qp = resource_user_context; |
f94b533d TT |
187 | struct iw_cm_id *cm_id = qp->cm_id; |
188 | struct c2wr_ae_active_connect_results *res; | |
189 | ||
190 | if (!cm_id) { | |
191 | pr_debug("event received, but cm_id is <nul>, qp=%p!\n", | |
192 | qp); | |
193 | goto ignore_it; | |
194 | } | |
195 | pr_debug("%s: event = %s, user_context=%llx, " | |
196 | "resource_type=%x, " | |
197 | "resource=%x, qp_state=%s\n", | |
33718363 | 198 | __func__, |
f94b533d | 199 | to_event_str(event_id), |
dc544bc9 | 200 | (unsigned long long) wr->ae.ae_generic.user_context, |
f94b533d TT |
201 | be32_to_cpu(wr->ae.ae_generic.resource_type), |
202 | be32_to_cpu(wr->ae.ae_generic.resource), | |
203 | to_qp_state_str(be32_to_cpu(wr->ae.ae_generic.qp_state))); | |
204 | ||
205 | c2_set_qp_state(qp, be32_to_cpu(wr->ae.ae_generic.qp_state)); | |
206 | ||
207 | switch (event_id) { | |
208 | case CCAE_ACTIVE_CONNECT_RESULTS: | |
209 | res = &wr->ae.ae_active_connect_results; | |
210 | cm_event.event = IW_CM_EVENT_CONNECT_REPLY; | |
24d44a39 SW |
211 | laddr->sin_addr.s_addr = res->laddr; |
212 | raddr->sin_addr.s_addr = res->raddr; | |
213 | laddr->sin_port = res->lport; | |
214 | raddr->sin_port = res->rport; | |
f94b533d TT |
215 | if (status == 0) { |
216 | cm_event.private_data_len = | |
217 | be32_to_cpu(res->private_data_length); | |
218 | cm_event.private_data = res->private_data; | |
219 | } else { | |
220 | spin_lock_irqsave(&qp->lock, flags); | |
221 | if (qp->cm_id) { | |
222 | qp->cm_id->rem_ref(qp->cm_id); | |
223 | qp->cm_id = NULL; | |
224 | } | |
225 | spin_unlock_irqrestore(&qp->lock, flags); | |
226 | cm_event.private_data_len = 0; | |
227 | cm_event.private_data = NULL; | |
228 | } | |
229 | if (cm_id->event_handler) | |
230 | cm_id->event_handler(cm_id, &cm_event); | |
231 | break; | |
232 | case CCAE_TERMINATE_MESSAGE_RECEIVED: | |
233 | case CCAE_CQ_SQ_COMPLETION_OVERFLOW: | |
234 | ib_event.device = &c2dev->ibdev; | |
235 | ib_event.element.qp = &qp->ibqp; | |
236 | ib_event.event = IB_EVENT_QP_REQ_ERR; | |
237 | ||
238 | if (qp->ibqp.event_handler) | |
239 | qp->ibqp.event_handler(&ib_event, | |
240 | qp->ibqp. | |
241 | qp_context); | |
242 | break; | |
243 | case CCAE_BAD_CLOSE: | |
244 | case CCAE_LLP_CLOSE_COMPLETE: | |
245 | case CCAE_LLP_CONNECTION_RESET: | |
246 | case CCAE_LLP_CONNECTION_LOST: | |
247 | BUG_ON(cm_id->event_handler==(void*)0x6b6b6b6b); | |
248 | ||
249 | spin_lock_irqsave(&qp->lock, flags); | |
250 | if (qp->cm_id) { | |
251 | qp->cm_id->rem_ref(qp->cm_id); | |
252 | qp->cm_id = NULL; | |
253 | } | |
254 | spin_unlock_irqrestore(&qp->lock, flags); | |
255 | cm_event.event = IW_CM_EVENT_CLOSE; | |
256 | cm_event.status = 0; | |
257 | if (cm_id->event_handler) | |
258 | cm_id->event_handler(cm_id, &cm_event); | |
259 | break; | |
260 | default: | |
261 | BUG_ON(1); | |
262 | pr_debug("%s:%d Unexpected event_id=%d on QP=%p, " | |
263 | "CM_ID=%p\n", | |
33718363 | 264 | __func__, __LINE__, |
f94b533d TT |
265 | event_id, qp, cm_id); |
266 | break; | |
267 | } | |
268 | break; | |
269 | } | |
270 | ||
271 | case C2_RES_IND_EP:{ | |
272 | ||
273 | struct c2wr_ae_connection_request *req = | |
274 | &wr->ae.ae_connection_request; | |
275 | struct iw_cm_id *cm_id = | |
25122333 | 276 | resource_user_context; |
f94b533d TT |
277 | |
278 | pr_debug("C2_RES_IND_EP event_id=%d\n", event_id); | |
279 | if (event_id != CCAE_CONNECTION_REQUEST) { | |
280 | pr_debug("%s: Invalid event_id: %d\n", | |
33718363 | 281 | __func__, event_id); |
f94b533d TT |
282 | break; |
283 | } | |
284 | cm_event.event = IW_CM_EVENT_CONNECT_REQUEST; | |
285 | cm_event.provider_data = (void*)(unsigned long)req->cr_handle; | |
24d44a39 SW |
286 | laddr->sin_addr.s_addr = req->laddr; |
287 | raddr->sin_addr.s_addr = req->raddr; | |
288 | laddr->sin_port = req->lport; | |
289 | raddr->sin_port = req->rport; | |
f94b533d TT |
290 | cm_event.private_data_len = |
291 | be32_to_cpu(req->private_data_length); | |
292 | cm_event.private_data = req->private_data; | |
56da00fc KS |
293 | /* |
294 | * Until ird/ord negotiation via MPAv2 support is added, send | |
295 | * max supported values | |
296 | */ | |
297 | cm_event.ird = cm_event.ord = 128; | |
f94b533d TT |
298 | |
299 | if (cm_id->event_handler) | |
300 | cm_id->event_handler(cm_id, &cm_event); | |
301 | break; | |
302 | } | |
303 | ||
304 | case C2_RES_IND_CQ:{ | |
305 | struct c2_cq *cq = | |
25122333 | 306 | resource_user_context; |
f94b533d TT |
307 | |
308 | pr_debug("IB_EVENT_CQ_ERR\n"); | |
309 | ib_event.device = &c2dev->ibdev; | |
310 | ib_event.element.cq = &cq->ibcq; | |
311 | ib_event.event = IB_EVENT_CQ_ERR; | |
312 | ||
313 | if (cq->ibcq.event_handler) | |
314 | cq->ibcq.event_handler(&ib_event, | |
315 | cq->ibcq.cq_context); | |
c9795bd7 | 316 | break; |
f94b533d TT |
317 | } |
318 | ||
319 | default: | |
320 | printk("Bad resource indicator = %d\n", | |
321 | resource_indicator); | |
322 | break; | |
323 | } | |
324 | ||
325 | ignore_it: | |
326 | c2_mq_free(mq); | |
327 | } |