diff options
Diffstat (limited to 'drivers/infiniband/hw/amso1100/c2_ae.c')
-rw-r--r-- | drivers/infiniband/hw/amso1100/c2_ae.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/amso1100/c2_ae.c b/drivers/infiniband/hw/amso1100/c2_ae.c new file mode 100644 index 000000000000..08f46c83a3a4 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_ae.c | |||
@@ -0,0 +1,321 @@ | |||
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", | ||
64 | __FUNCTION__, c2_status); | ||
65 | return -EIO; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | #ifdef DEBUG | ||
70 | static const char* to_event_str(int event) | ||
71 | { | ||
72 | static const char* event_str[] = { | ||
73 | "CCAE_REMOTE_SHUTDOWN", | ||
74 | "CCAE_ACTIVE_CONNECT_RESULTS", | ||
75 | "CCAE_CONNECTION_REQUEST", | ||
76 | "CCAE_LLP_CLOSE_COMPLETE", | ||
77 | "CCAE_TERMINATE_MESSAGE_RECEIVED", | ||
78 | "CCAE_LLP_CONNECTION_RESET", | ||
79 | "CCAE_LLP_CONNECTION_LOST", | ||
80 | "CCAE_LLP_SEGMENT_SIZE_INVALID", | ||
81 | "CCAE_LLP_INVALID_CRC", | ||
82 | "CCAE_LLP_BAD_FPDU", | ||
83 | "CCAE_INVALID_DDP_VERSION", | ||
84 | "CCAE_INVALID_RDMA_VERSION", | ||
85 | "CCAE_UNEXPECTED_OPCODE", | ||
86 | "CCAE_INVALID_DDP_QUEUE_NUMBER", | ||
87 | "CCAE_RDMA_READ_NOT_ENABLED", | ||
88 | "CCAE_RDMA_WRITE_NOT_ENABLED", | ||
89 | "CCAE_RDMA_READ_TOO_SMALL", | ||
90 | "CCAE_NO_L_BIT", | ||
91 | "CCAE_TAGGED_INVALID_STAG", | ||
92 | "CCAE_TAGGED_BASE_BOUNDS_VIOLATION", | ||
93 | "CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION", | ||
94 | "CCAE_TAGGED_INVALID_PD", | ||
95 | "CCAE_WRAP_ERROR", | ||
96 | "CCAE_BAD_CLOSE", | ||
97 | "CCAE_BAD_LLP_CLOSE", | ||
98 | "CCAE_INVALID_MSN_RANGE", | ||
99 | "CCAE_INVALID_MSN_GAP", | ||
100 | "CCAE_IRRQ_OVERFLOW", | ||
101 | "CCAE_IRRQ_MSN_GAP", | ||
102 | "CCAE_IRRQ_MSN_RANGE", | ||
103 | "CCAE_IRRQ_INVALID_STAG", | ||
104 | "CCAE_IRRQ_BASE_BOUNDS_VIOLATION", | ||
105 | "CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION", | ||
106 | "CCAE_IRRQ_INVALID_PD", | ||
107 | "CCAE_IRRQ_WRAP_ERROR", | ||
108 | "CCAE_CQ_SQ_COMPLETION_OVERFLOW", | ||
109 | "CCAE_CQ_RQ_COMPLETION_ERROR", | ||
110 | "CCAE_QP_SRQ_WQE_ERROR", | ||
111 | "CCAE_QP_LOCAL_CATASTROPHIC_ERROR", | ||
112 | "CCAE_CQ_OVERFLOW", | ||
113 | "CCAE_CQ_OPERATION_ERROR", | ||
114 | "CCAE_SRQ_LIMIT_REACHED", | ||
115 | "CCAE_QP_RQ_LIMIT_REACHED", | ||
116 | "CCAE_SRQ_CATASTROPHIC_ERROR", | ||
117 | "CCAE_RNIC_CATASTROPHIC_ERROR" | ||
118 | }; | ||
119 | |||
120 | if (event < CCAE_REMOTE_SHUTDOWN || | ||
121 | event > CCAE_RNIC_CATASTROPHIC_ERROR) | ||
122 | return "<invalid event>"; | ||
123 | |||
124 | event -= CCAE_REMOTE_SHUTDOWN; | ||
125 | return event_str[event]; | ||
126 | } | ||
127 | |||
128 | static const char *to_qp_state_str(int state) | ||
129 | { | ||
130 | switch (state) { | ||
131 | case C2_QP_STATE_IDLE: | ||
132 | return "C2_QP_STATE_IDLE"; | ||
133 | case C2_QP_STATE_CONNECTING: | ||
134 | return "C2_QP_STATE_CONNECTING"; | ||
135 | case C2_QP_STATE_RTS: | ||
136 | return "C2_QP_STATE_RTS"; | ||
137 | case C2_QP_STATE_CLOSING: | ||
138 | return "C2_QP_STATE_CLOSING"; | ||
139 | case C2_QP_STATE_TERMINATE: | ||
140 | return "C2_QP_STATE_TERMINATE"; | ||
141 | case C2_QP_STATE_ERROR: | ||
142 | return "C2_QP_STATE_ERROR"; | ||
143 | default: | ||
144 | return "<invalid QP state>"; | ||
145 | }; | ||
146 | } | ||
147 | #endif | ||
148 | |||
149 | void c2_ae_event(struct c2_dev *c2dev, u32 mq_index) | ||
150 | { | ||
151 | struct c2_mq *mq = c2dev->qptr_array[mq_index]; | ||
152 | union c2wr *wr; | ||
153 | void *resource_user_context; | ||
154 | struct iw_cm_event cm_event; | ||
155 | struct ib_event ib_event; | ||
156 | enum c2_resource_indicator resource_indicator; | ||
157 | enum c2_event_id event_id; | ||
158 | unsigned long flags; | ||
159 | int status; | ||
160 | |||
161 | /* | ||
162 | * retreive the message | ||
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 | |||
186 | struct c2_qp *qp = (struct c2_qp *)resource_user_context; | ||
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", | ||
198 | __FUNCTION__, | ||
199 | to_event_str(event_id), | ||
200 | be64_to_cpu(wr->ae.ae_generic.user_context), | ||
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; | ||
211 | cm_event.local_addr.sin_addr.s_addr = res->laddr; | ||
212 | cm_event.remote_addr.sin_addr.s_addr = res->raddr; | ||
213 | cm_event.local_addr.sin_port = res->lport; | ||
214 | cm_event.remote_addr.sin_port = res->rport; | ||
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", | ||
264 | __FUNCTION__, __LINE__, | ||
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 = | ||
276 | (struct iw_cm_id *)resource_user_context; | ||
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", | ||
281 | __FUNCTION__, event_id); | ||
282 | break; | ||
283 | } | ||
284 | cm_event.event = IW_CM_EVENT_CONNECT_REQUEST; | ||
285 | cm_event.provider_data = (void*)(unsigned long)req->cr_handle; | ||
286 | cm_event.local_addr.sin_addr.s_addr = req->laddr; | ||
287 | cm_event.remote_addr.sin_addr.s_addr = req->raddr; | ||
288 | cm_event.local_addr.sin_port = req->lport; | ||
289 | cm_event.remote_addr.sin_port = req->rport; | ||
290 | cm_event.private_data_len = | ||
291 | be32_to_cpu(req->private_data_length); | ||
292 | cm_event.private_data = req->private_data; | ||
293 | |||
294 | if (cm_id->event_handler) | ||
295 | cm_id->event_handler(cm_id, &cm_event); | ||
296 | break; | ||
297 | } | ||
298 | |||
299 | case C2_RES_IND_CQ:{ | ||
300 | struct c2_cq *cq = | ||
301 | (struct c2_cq *) resource_user_context; | ||
302 | |||
303 | pr_debug("IB_EVENT_CQ_ERR\n"); | ||
304 | ib_event.device = &c2dev->ibdev; | ||
305 | ib_event.element.cq = &cq->ibcq; | ||
306 | ib_event.event = IB_EVENT_CQ_ERR; | ||
307 | |||
308 | if (cq->ibcq.event_handler) | ||
309 | cq->ibcq.event_handler(&ib_event, | ||
310 | cq->ibcq.cq_context); | ||
311 | } | ||
312 | |||
313 | default: | ||
314 | printk("Bad resource indicator = %d\n", | ||
315 | resource_indicator); | ||
316 | break; | ||
317 | } | ||
318 | |||
319 | ignore_it: | ||
320 | c2_mq_free(mq); | ||
321 | } | ||