Blame view

drivers/infiniband/core/mad_rmpp.c 27 KB
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
1
2
  /*
   * Copyright (c) 2005 Intel Inc. All rights reserved.
618a3c03f   Hal Rosenstock   IB/mad: RMPP supp...
3
   * Copyright (c) 2005-2006 Voltaire, Inc. All rights reserved.
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   *
   * This software is available to you under a choice of one of two
   * licenses.  You may choose to be licensed under the terms of the GNU
   * General Public License (GPL) Version 2, available from the file
   * COPYING in the main directory of this source tree, or the
   * OpenIB.org BSD license below:
   *
   *     Redistribution and use in source and binary forms, with or
   *     without modification, are permitted provided that the following
   *     conditions are met:
   *
   *      - Redistributions of source code must retain the above
   *        copyright notice, this list of conditions and the following
   *        disclaimer.
   *
   *      - Redistributions in binary form must reproduce the above
   *        copyright notice, this list of conditions and the following
   *        disclaimer in the documentation and/or other materials
   *        provided with the distribution.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
   * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
32
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
33
  #include <linux/slab.h>
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
34
35
36
37
38
39
  #include "mad_priv.h"
  #include "mad_rmpp.h"
  
  enum rmpp_state {
  	RMPP_STATE_ACTIVE,
  	RMPP_STATE_TIMEOUT,
0e442afd9   Roland Dreier   IB/mad: Fix lock-...
40
41
  	RMPP_STATE_COMPLETE,
  	RMPP_STATE_CANCELING
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
42
43
44
45
46
  };
  
  struct mad_rmpp_recv {
  	struct ib_mad_agent_private *agent;
  	struct list_head list;
c4028958b   David Howells   WorkStruct: make ...
47
48
  	struct delayed_work timeout_work;
  	struct delayed_work cleanup_work;
1b52fa98e   Sean Hefty   IB: refcount race...
49
  	struct completion comp;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
50
51
52
53
54
55
56
57
58
59
  	enum rmpp_state state;
  	spinlock_t lock;
  	atomic_t refcount;
  
  	struct ib_ah *ah;
  	struct ib_mad_recv_wc *rmpp_wc;
  	struct ib_mad_recv_buf *cur_seg_buf;
  	int last_ack;
  	int seg_num;
  	int newwin;
75ab13443   Sean Hefty   IB/mad: Add suppo...
60
  	int repwin;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
61

97f52eb43   Sean Hefty   [PATCH] IB: spars...
62
  	__be64 tid;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
63
64
65
66
67
68
  	u32 src_qp;
  	u16 slid;
  	u8 mgmt_class;
  	u8 class_version;
  	u8 method;
  };
1b52fa98e   Sean Hefty   IB: refcount race...
69
70
71
72
73
  static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv)
  {
  	if (atomic_dec_and_test(&rmpp_recv->refcount))
  		complete(&rmpp_recv->comp);
  }
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
74
75
  static void destroy_rmpp_recv(struct mad_rmpp_recv *rmpp_recv)
  {
1b52fa98e   Sean Hefty   IB: refcount race...
76
77
  	deref_rmpp_recv(rmpp_recv);
  	wait_for_completion(&rmpp_recv->comp);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
78
79
80
81
82
83
84
85
86
87
88
  	ib_destroy_ah(rmpp_recv->ah);
  	kfree(rmpp_recv);
  }
  
  void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent)
  {
  	struct mad_rmpp_recv *rmpp_recv, *temp_rmpp_recv;
  	unsigned long flags;
  
  	spin_lock_irqsave(&agent->lock, flags);
  	list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) {
0e442afd9   Roland Dreier   IB/mad: Fix lock-...
89
90
91
92
93
94
95
  		if (rmpp_recv->state != RMPP_STATE_COMPLETE)
  			ib_free_recv_mad(rmpp_recv->rmpp_wc);
  		rmpp_recv->state = RMPP_STATE_CANCELING;
  	}
  	spin_unlock_irqrestore(&agent->lock, flags);
  
  	list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) {
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
96
97
98
  		cancel_delayed_work(&rmpp_recv->timeout_work);
  		cancel_delayed_work(&rmpp_recv->cleanup_work);
  	}
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
99
100
101
102
103
104
  
  	flush_workqueue(agent->qp_info->port_priv->wq);
  
  	list_for_each_entry_safe(rmpp_recv, temp_rmpp_recv,
  				 &agent->rmpp_list, list) {
  		list_del(&rmpp_recv->list);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
105
106
107
  		destroy_rmpp_recv(rmpp_recv);
  	}
  }
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
108
  static void format_ack(struct ib_mad_send_buf *msg,
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
109
110
111
  		       struct ib_rmpp_mad *data,
  		       struct mad_rmpp_recv *rmpp_recv)
  {
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
112
  	struct ib_rmpp_mad *ack = msg->mad;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
113
  	unsigned long flags;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
114
  	memcpy(ack, &data->mad_hdr, msg->hdr_len);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  
  	ack->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
  	ack->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ACK;
  	ib_set_rmpp_flags(&ack->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
  
  	spin_lock_irqsave(&rmpp_recv->lock, flags);
  	rmpp_recv->last_ack = rmpp_recv->seg_num;
  	ack->rmpp_hdr.seg_num = cpu_to_be32(rmpp_recv->seg_num);
  	ack->rmpp_hdr.paylen_newwin = cpu_to_be32(rmpp_recv->newwin);
  	spin_unlock_irqrestore(&rmpp_recv->lock, flags);
  }
  
  static void ack_recv(struct mad_rmpp_recv *rmpp_recv,
  		     struct ib_mad_recv_wc *recv_wc)
  {
  	struct ib_mad_send_buf *msg;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
131
  	int ret, hdr_len;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
132

618a3c03f   Hal Rosenstock   IB/mad: RMPP supp...
133
  	hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
134
  	msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
135
136
  				 recv_wc->wc->pkey_index, 1, hdr_len,
  				 0, GFP_KERNEL);
cd55ef5a1   Julien Brunel   IB/mad: Test ib_c...
137
  	if (IS_ERR(msg))
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
138
  		return;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
139
  	format_ack(msg, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv);
34816ad98   Sean Hefty   [IB] Fix MAD laye...
140
141
  	msg->ah = rmpp_recv->ah;
  	ret = ib_post_send_mad(msg, NULL);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
142
143
144
  	if (ret)
  		ib_free_send_mad(msg);
  }
7cc656efb   Roland Dreier   [IB] simplify mad...
145
146
  static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent,
  						  struct ib_mad_recv_wc *recv_wc)
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
147
  {
7cc656efb   Roland Dreier   [IB] simplify mad...
148
  	struct ib_mad_send_buf *msg;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
149
  	struct ib_ah *ah;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
150
  	int hdr_len;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
151
152
153
154
  
  	ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc,
  				  recv_wc->recv_buf.grh, agent->port_num);
  	if (IS_ERR(ah))
7cc656efb   Roland Dreier   [IB] simplify mad...
155
  		return (void *) ah;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
156

618a3c03f   Hal Rosenstock   IB/mad: RMPP supp...
157
  	hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
7cc656efb   Roland Dreier   [IB] simplify mad...
158
159
  	msg = ib_create_send_mad(agent, recv_wc->wc->src_qp,
  				 recv_wc->wc->pkey_index, 1,
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
160
  				 hdr_len, 0, GFP_KERNEL);
7cc656efb   Roland Dreier   [IB] simplify mad...
161
  	if (IS_ERR(msg))
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
162
  		ib_destroy_ah(ah);
38d5af956   Sean Hefty   IB/mad: Fix addre...
163
  	else {
7cc656efb   Roland Dreier   [IB] simplify mad...
164
  		msg->ah = ah;
38d5af956   Sean Hefty   IB/mad: Fix addre...
165
166
  		msg->context[0] = ah;
  	}
7cc656efb   Roland Dreier   [IB] simplify mad...
167
168
  
  	return msg;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
169
  }
75ab13443   Sean Hefty   IB/mad: Add suppo...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  static void ack_ds_ack(struct ib_mad_agent_private *agent,
  		       struct ib_mad_recv_wc *recv_wc)
  {
  	struct ib_mad_send_buf *msg;
  	struct ib_rmpp_mad *rmpp_mad;
  	int ret;
  
  	msg = alloc_response_msg(&agent->agent, recv_wc);
  	if (IS_ERR(msg))
  		return;
  
  	rmpp_mad = msg->mad;
  	memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len);
  
  	rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
  	ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
  	rmpp_mad->rmpp_hdr.seg_num = 0;
  	rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(1);
  
  	ret = ib_post_send_mad(msg, NULL);
  	if (ret) {
  		ib_destroy_ah(msg->ah);
  		ib_free_send_mad(msg);
  	}
  }
34816ad98   Sean Hefty   [IB] Fix MAD laye...
195
  void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc)
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
196
  {
38d5af956   Sean Hefty   IB/mad: Fix addre...
197
  	if (mad_send_wc->send_buf->context[0] == mad_send_wc->send_buf->ah)
34816ad98   Sean Hefty   [IB] Fix MAD laye...
198
199
  		ib_destroy_ah(mad_send_wc->send_buf->ah);
  	ib_free_send_mad(mad_send_wc->send_buf);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
200
201
202
203
204
205
206
  }
  
  static void nack_recv(struct ib_mad_agent_private *agent,
  		      struct ib_mad_recv_wc *recv_wc, u8 rmpp_status)
  {
  	struct ib_mad_send_buf *msg;
  	struct ib_rmpp_mad *rmpp_mad;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
207
  	int ret;
7cc656efb   Roland Dreier   [IB] simplify mad...
208
209
  	msg = alloc_response_msg(&agent->agent, recv_wc);
  	if (IS_ERR(msg))
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
210
  		return;
34816ad98   Sean Hefty   [IB] Fix MAD laye...
211
  	rmpp_mad = msg->mad;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
212
  	memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
213
214
215
216
217
218
219
220
  
  	rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
  	rmpp_mad->rmpp_hdr.rmpp_version = IB_MGMT_RMPP_VERSION;
  	rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ABORT;
  	ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
  	rmpp_mad->rmpp_hdr.rmpp_status = rmpp_status;
  	rmpp_mad->rmpp_hdr.seg_num = 0;
  	rmpp_mad->rmpp_hdr.paylen_newwin = 0;
34816ad98   Sean Hefty   [IB] Fix MAD laye...
221
222
223
224
225
  	ret = ib_post_send_mad(msg, NULL);
  	if (ret) {
  		ib_destroy_ah(msg->ah);
  		ib_free_send_mad(msg);
  	}
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
226
  }
c4028958b   David Howells   WorkStruct: make ...
227
  static void recv_timeout_handler(struct work_struct *work)
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
228
  {
c4028958b   David Howells   WorkStruct: make ...
229
230
  	struct mad_rmpp_recv *rmpp_recv =
  		container_of(work, struct mad_rmpp_recv, timeout_work.work);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
231
232
233
234
235
236
237
238
239
240
241
  	struct ib_mad_recv_wc *rmpp_wc;
  	unsigned long flags;
  
  	spin_lock_irqsave(&rmpp_recv->agent->lock, flags);
  	if (rmpp_recv->state != RMPP_STATE_ACTIVE) {
  		spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags);
  		return;
  	}
  	rmpp_recv->state = RMPP_STATE_TIMEOUT;
  	list_del(&rmpp_recv->list);
  	spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
242
  	rmpp_wc = rmpp_recv->rmpp_wc;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
243
  	nack_recv(rmpp_recv->agent, rmpp_wc, IB_MGMT_RMPP_STATUS_T2L);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
244
245
246
  	destroy_rmpp_recv(rmpp_recv);
  	ib_free_recv_mad(rmpp_wc);
  }
c4028958b   David Howells   WorkStruct: make ...
247
  static void recv_cleanup_handler(struct work_struct *work)
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
248
  {
c4028958b   David Howells   WorkStruct: make ...
249
250
  	struct mad_rmpp_recv *rmpp_recv =
  		container_of(work, struct mad_rmpp_recv, cleanup_work.work);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
251
252
253
  	unsigned long flags;
  
  	spin_lock_irqsave(&rmpp_recv->agent->lock, flags);
0e442afd9   Roland Dreier   IB/mad: Fix lock-...
254
255
256
257
  	if (rmpp_recv->state == RMPP_STATE_CANCELING) {
  		spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags);
  		return;
  	}
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  	list_del(&rmpp_recv->list);
  	spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags);
  	destroy_rmpp_recv(rmpp_recv);
  }
  
  static struct mad_rmpp_recv *
  create_rmpp_recv(struct ib_mad_agent_private *agent,
  		 struct ib_mad_recv_wc *mad_recv_wc)
  {
  	struct mad_rmpp_recv *rmpp_recv;
  	struct ib_mad_hdr *mad_hdr;
  
  	rmpp_recv = kmalloc(sizeof *rmpp_recv, GFP_KERNEL);
  	if (!rmpp_recv)
  		return NULL;
  
  	rmpp_recv->ah = ib_create_ah_from_wc(agent->agent.qp->pd,
  					     mad_recv_wc->wc,
  					     mad_recv_wc->recv_buf.grh,
  					     agent->agent.port_num);
  	if (IS_ERR(rmpp_recv->ah))
  		goto error;
  
  	rmpp_recv->agent = agent;
1b52fa98e   Sean Hefty   IB: refcount race...
282
  	init_completion(&rmpp_recv->comp);
c4028958b   David Howells   WorkStruct: make ...
283
284
  	INIT_DELAYED_WORK(&rmpp_recv->timeout_work, recv_timeout_handler);
  	INIT_DELAYED_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
285
286
287
288
289
290
291
292
293
  	spin_lock_init(&rmpp_recv->lock);
  	rmpp_recv->state = RMPP_STATE_ACTIVE;
  	atomic_set(&rmpp_recv->refcount, 1);
  
  	rmpp_recv->rmpp_wc = mad_recv_wc;
  	rmpp_recv->cur_seg_buf = &mad_recv_wc->recv_buf;
  	rmpp_recv->newwin = 1;
  	rmpp_recv->seg_num = 1;
  	rmpp_recv->last_ack = 0;
75ab13443   Sean Hefty   IB/mad: Add suppo...
294
  	rmpp_recv->repwin = 1;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
295
296
297
298
299
300
301
302
303
304
305
306
307
  
  	mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr;
  	rmpp_recv->tid = mad_hdr->tid;
  	rmpp_recv->src_qp = mad_recv_wc->wc->src_qp;
  	rmpp_recv->slid = mad_recv_wc->wc->slid;
  	rmpp_recv->mgmt_class = mad_hdr->mgmt_class;
  	rmpp_recv->class_version = mad_hdr->class_version;
  	rmpp_recv->method  = mad_hdr->method;
  	return rmpp_recv;
  
  error:	kfree(rmpp_recv);
  	return NULL;
  }
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  static struct mad_rmpp_recv *
  find_rmpp_recv(struct ib_mad_agent_private *agent,
  	       struct ib_mad_recv_wc *mad_recv_wc)
  {
  	struct mad_rmpp_recv *rmpp_recv;
  	struct ib_mad_hdr *mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr;
  
  	list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) {
  		if (rmpp_recv->tid == mad_hdr->tid &&
  		    rmpp_recv->src_qp == mad_recv_wc->wc->src_qp &&
  		    rmpp_recv->slid == mad_recv_wc->wc->slid &&
  		    rmpp_recv->mgmt_class == mad_hdr->mgmt_class &&
  		    rmpp_recv->class_version == mad_hdr->class_version &&
  		    rmpp_recv->method == mad_hdr->method)
  			return rmpp_recv;
  	}
  	return NULL;
  }
  
  static struct mad_rmpp_recv *
  acquire_rmpp_recv(struct ib_mad_agent_private *agent,
  		  struct ib_mad_recv_wc *mad_recv_wc)
  {
  	struct mad_rmpp_recv *rmpp_recv;
  	unsigned long flags;
  
  	spin_lock_irqsave(&agent->lock, flags);
  	rmpp_recv = find_rmpp_recv(agent, mad_recv_wc);
  	if (rmpp_recv)
  		atomic_inc(&rmpp_recv->refcount);
  	spin_unlock_irqrestore(&agent->lock, flags);
  	return rmpp_recv;
  }
  
  static struct mad_rmpp_recv *
  insert_rmpp_recv(struct ib_mad_agent_private *agent,
  		 struct mad_rmpp_recv *rmpp_recv)
  {
  	struct mad_rmpp_recv *cur_rmpp_recv;
  
  	cur_rmpp_recv = find_rmpp_recv(agent, rmpp_recv->rmpp_wc);
  	if (!cur_rmpp_recv)
  		list_add_tail(&rmpp_recv->list, &agent->rmpp_list);
  
  	return cur_rmpp_recv;
  }
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  static inline int get_last_flag(struct ib_mad_recv_buf *seg)
  {
  	struct ib_rmpp_mad *rmpp_mad;
  
  	rmpp_mad = (struct ib_rmpp_mad *) seg->mad;
  	return ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_LAST;
  }
  
  static inline int get_seg_num(struct ib_mad_recv_buf *seg)
  {
  	struct ib_rmpp_mad *rmpp_mad;
  
  	rmpp_mad = (struct ib_rmpp_mad *) seg->mad;
  	return be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num);
  }
  
  static inline struct ib_mad_recv_buf * get_next_seg(struct list_head *rmpp_list,
  						    struct ib_mad_recv_buf *seg)
  {
  	if (seg->list.next == rmpp_list)
  		return NULL;
  
  	return container_of(seg->list.next, struct ib_mad_recv_buf, list);
  }
  
  static inline int window_size(struct ib_mad_agent_private *agent)
  {
  	return max(agent->qp_info->recv_queue.max_active >> 3, 1);
  }
  
  static struct ib_mad_recv_buf * find_seg_location(struct list_head *rmpp_list,
  						  int seg_num)
  {
3cd965646   Roland Dreier   IB: Whitespace fixes
387
  	struct ib_mad_recv_buf *seg_buf;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
  	int cur_seg_num;
  
  	list_for_each_entry_reverse(seg_buf, rmpp_list, list) {
  		cur_seg_num = get_seg_num(seg_buf);
  		if (seg_num > cur_seg_num)
  			return seg_buf;
  		if (seg_num == cur_seg_num)
  			break;
  	}
  	return NULL;
  }
  
  static void update_seg_num(struct mad_rmpp_recv *rmpp_recv,
  			   struct ib_mad_recv_buf *new_buf)
  {
  	struct list_head *rmpp_list = &rmpp_recv->rmpp_wc->rmpp_list;
  
  	while (new_buf && (get_seg_num(new_buf) == rmpp_recv->seg_num + 1)) {
  		rmpp_recv->cur_seg_buf = new_buf;
  		rmpp_recv->seg_num++;
  		new_buf = get_next_seg(rmpp_list, new_buf);
  	}
  }
  
  static inline int get_mad_len(struct mad_rmpp_recv *rmpp_recv)
  {
  	struct ib_rmpp_mad *rmpp_mad;
  	int hdr_size, data_size, pad;
  
  	rmpp_mad = (struct ib_rmpp_mad *)rmpp_recv->cur_seg_buf->mad;
618a3c03f   Hal Rosenstock   IB/mad: RMPP supp...
418
  	hdr_size = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
419
  	data_size = sizeof(struct ib_rmpp_mad) - hdr_size;
f2065e424   Hal Rosenstock   [IB] Fix RMPP rec...
420
421
  	pad = IB_MGMT_RMPP_DATA - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
  	if (pad > IB_MGMT_RMPP_DATA || pad < 0)
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
  		pad = 0;
  
  	return hdr_size + rmpp_recv->seg_num * data_size - pad;
  }
  
  static struct ib_mad_recv_wc * complete_rmpp(struct mad_rmpp_recv *rmpp_recv)
  {
  	struct ib_mad_recv_wc *rmpp_wc;
  
  	ack_recv(rmpp_recv, rmpp_recv->rmpp_wc);
  	if (rmpp_recv->seg_num > 1)
  		cancel_delayed_work(&rmpp_recv->timeout_work);
  
  	rmpp_wc = rmpp_recv->rmpp_wc;
  	rmpp_wc->mad_len = get_mad_len(rmpp_recv);
  	/* 10 seconds until we can find the packet lifetime */
  	queue_delayed_work(rmpp_recv->agent->qp_info->port_priv->wq,
  			   &rmpp_recv->cleanup_work, msecs_to_jiffies(10000));
  	return rmpp_wc;
  }
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
  static struct ib_mad_recv_wc *
  continue_rmpp(struct ib_mad_agent_private *agent,
  	      struct ib_mad_recv_wc *mad_recv_wc)
  {
  	struct mad_rmpp_recv *rmpp_recv;
  	struct ib_mad_recv_buf *prev_buf;
  	struct ib_mad_recv_wc *done_wc;
  	int seg_num;
  	unsigned long flags;
  
  	rmpp_recv = acquire_rmpp_recv(agent, mad_recv_wc);
  	if (!rmpp_recv)
  		goto drop1;
  
  	seg_num = get_seg_num(&mad_recv_wc->recv_buf);
  
  	spin_lock_irqsave(&rmpp_recv->lock, flags);
  	if ((rmpp_recv->state == RMPP_STATE_TIMEOUT) ||
  	    (seg_num > rmpp_recv->newwin))
  		goto drop3;
  
  	if ((seg_num <= rmpp_recv->last_ack) ||
  	    (rmpp_recv->state == RMPP_STATE_COMPLETE)) {
  		spin_unlock_irqrestore(&rmpp_recv->lock, flags);
  		ack_recv(rmpp_recv, mad_recv_wc);
  		goto drop2;
  	}
  
  	prev_buf = find_seg_location(&rmpp_recv->rmpp_wc->rmpp_list, seg_num);
  	if (!prev_buf)
  		goto drop3;
  
  	done_wc = NULL;
  	list_add(&mad_recv_wc->recv_buf.list, &prev_buf->list);
  	if (rmpp_recv->cur_seg_buf == prev_buf) {
  		update_seg_num(rmpp_recv, &mad_recv_wc->recv_buf);
  		if (get_last_flag(rmpp_recv->cur_seg_buf)) {
  			rmpp_recv->state = RMPP_STATE_COMPLETE;
  			spin_unlock_irqrestore(&rmpp_recv->lock, flags);
  			done_wc = complete_rmpp(rmpp_recv);
  			goto out;
  		} else if (rmpp_recv->seg_num == rmpp_recv->newwin) {
  			rmpp_recv->newwin += window_size(agent);
  			spin_unlock_irqrestore(&rmpp_recv->lock, flags);
  			ack_recv(rmpp_recv, mad_recv_wc);
  			goto out;
  		}
  	}
  	spin_unlock_irqrestore(&rmpp_recv->lock, flags);
  out:
  	deref_rmpp_recv(rmpp_recv);
  	return done_wc;
  
  drop3:	spin_unlock_irqrestore(&rmpp_recv->lock, flags);
  drop2:	deref_rmpp_recv(rmpp_recv);
  drop1:	ib_free_recv_mad(mad_recv_wc);
  	return NULL;
  }
  
  static struct ib_mad_recv_wc *
  start_rmpp(struct ib_mad_agent_private *agent,
  	   struct ib_mad_recv_wc *mad_recv_wc)
  {
  	struct mad_rmpp_recv *rmpp_recv;
  	unsigned long flags;
  
  	rmpp_recv = create_rmpp_recv(agent, mad_recv_wc);
  	if (!rmpp_recv) {
  		ib_free_recv_mad(mad_recv_wc);
  		return NULL;
  	}
  
  	spin_lock_irqsave(&agent->lock, flags);
  	if (insert_rmpp_recv(agent, rmpp_recv)) {
  		spin_unlock_irqrestore(&agent->lock, flags);
  		/* duplicate first MAD */
  		destroy_rmpp_recv(rmpp_recv);
  		return continue_rmpp(agent, mad_recv_wc);
  	}
  	atomic_inc(&rmpp_recv->refcount);
  
  	if (get_last_flag(&mad_recv_wc->recv_buf)) {
  		rmpp_recv->state = RMPP_STATE_COMPLETE;
  		spin_unlock_irqrestore(&agent->lock, flags);
  		complete_rmpp(rmpp_recv);
  	} else {
  		spin_unlock_irqrestore(&agent->lock, flags);
  		/* 40 seconds until we can find the packet lifetimes */
  		queue_delayed_work(agent->qp_info->port_priv->wq,
  				   &rmpp_recv->timeout_work,
  				   msecs_to_jiffies(40000));
  		rmpp_recv->newwin += window_size(agent);
  		ack_recv(rmpp_recv, mad_recv_wc);
  		mad_recv_wc = NULL;
  	}
  	deref_rmpp_recv(rmpp_recv);
  	return mad_recv_wc;
  }
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
540
541
542
543
  static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr)
  {
  	struct ib_rmpp_mad *rmpp_mad;
  	int timeout;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
544
  	u32 paylen = 0;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
545

34816ad98   Sean Hefty   [IB] Fix MAD laye...
546
  	rmpp_mad = mad_send_wr->send_buf.mad;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
547
  	ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
548
  	rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(++mad_send_wr->seg_num);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
549
550
551
  
  	if (mad_send_wr->seg_num == 1) {
  		rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_FIRST;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
552
  		paylen = mad_send_wr->send_buf.seg_count * IB_MGMT_RMPP_DATA -
972d512a1   Sean Hefty   [IB] Add MAD data...
553
  			 mad_send_wr->pad;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
554
  	}
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
555
  	if (mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count) {
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
556
  		rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_LAST;
972d512a1   Sean Hefty   [IB] Add MAD data...
557
  		paylen = IB_MGMT_RMPP_DATA - mad_send_wr->pad;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
558
  	}
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
559
  	rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
560
561
  
  	/* 2 seconds for an ACK until we can find the packet lifetime */
34816ad98   Sean Hefty   [IB] Fix MAD laye...
562
  	timeout = mad_send_wr->send_buf.timeout_ms;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
563
564
  	if (!timeout || timeout > 2000)
  		mad_send_wr->timeout = msecs_to_jiffies(2000);
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
565

fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
566
567
  	return ib_send_mad(mad_send_wr);
  }
fa9656bbd   Jack Morgenstein   IB/mad: include G...
568
569
  static void abort_send(struct ib_mad_agent_private *agent,
  		       struct ib_mad_recv_wc *mad_recv_wc, u8 rmpp_status)
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
570
571
572
573
574
575
  {
  	struct ib_mad_send_wr_private *mad_send_wr;
  	struct ib_mad_send_wc wc;
  	unsigned long flags;
  
  	spin_lock_irqsave(&agent->lock, flags);
fa9656bbd   Jack Morgenstein   IB/mad: include G...
576
  	mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
577
578
  	if (!mad_send_wr)
  		goto out;	/* Unmatched send */
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
579
  	if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
580
581
582
583
584
585
586
587
  	    (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
  		goto out;	/* Send is already done */
  
  	ib_mark_mad_done(mad_send_wr);
  	spin_unlock_irqrestore(&agent->lock, flags);
  
  	wc.status = IB_WC_REM_ABORT_ERR;
  	wc.vendor_err = rmpp_status;
34816ad98   Sean Hefty   [IB] Fix MAD laye...
588
  	wc.send_buf = &mad_send_wr->send_buf;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
589
590
591
592
593
  	ib_mad_complete_send_wr(mad_send_wr, &wc);
  	return;
  out:
  	spin_unlock_irqrestore(&agent->lock, flags);
  }
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
594
595
596
597
598
599
600
601
602
603
604
  static inline void adjust_last_ack(struct ib_mad_send_wr_private *wr,
  				   int seg_num)
  {
  	struct list_head *list;
  
  	wr->last_ack = seg_num;
  	list = &wr->last_ack_seg->list;
  	list_for_each_entry(wr->last_ack_seg, list, list)
  		if (wr->last_ack_seg->num == seg_num)
  			break;
  }
75ab13443   Sean Hefty   IB/mad: Add suppo...
605
606
607
608
609
610
611
612
613
  static void process_ds_ack(struct ib_mad_agent_private *agent,
  			   struct ib_mad_recv_wc *mad_recv_wc, int newwin)
  {
  	struct mad_rmpp_recv *rmpp_recv;
  
  	rmpp_recv = find_rmpp_recv(agent, mad_recv_wc);
  	if (rmpp_recv && rmpp_recv->state == RMPP_STATE_COMPLETE)
  		rmpp_recv->repwin = newwin;
  }
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
614
615
616
617
618
619
620
621
622
  static void process_rmpp_ack(struct ib_mad_agent_private *agent,
  			     struct ib_mad_recv_wc *mad_recv_wc)
  {
  	struct ib_mad_send_wr_private *mad_send_wr;
  	struct ib_rmpp_mad *rmpp_mad;
  	unsigned long flags;
  	int seg_num, newwin, ret;
  
  	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
623
  	if (rmpp_mad->rmpp_hdr.rmpp_status) {
fa9656bbd   Jack Morgenstein   IB/mad: include G...
624
  		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
625
  		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
626
  		return;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
627
  	}
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
628
629
630
  
  	seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num);
  	newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
631
  	if (newwin < seg_num) {
fa9656bbd   Jack Morgenstein   IB/mad: include G...
632
  		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
633
634
635
  		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);
  		return;
  	}
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
636
637
  
  	spin_lock_irqsave(&agent->lock, flags);
fa9656bbd   Jack Morgenstein   IB/mad: include G...
638
  	mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);
75ab13443   Sean Hefty   IB/mad: Add suppo...
639
640
641
642
643
644
645
646
647
648
649
650
  	if (!mad_send_wr) {
  		if (!seg_num)
  			process_ds_ack(agent, mad_recv_wc, newwin);
  		goto out;	/* Unmatched or DS RMPP ACK */
  	}
  
  	if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) &&
  	    (mad_send_wr->timeout)) {
  		spin_unlock_irqrestore(&agent->lock, flags);
  		ack_ds_ack(agent, mad_recv_wc);
  		return;		/* Repeated ACK for DS RMPP transaction */
  	}
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
651

f36e1793e   Jack Morgenstein   IB/umad: Add supp...
652
  	if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
653
654
  	    (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
  		goto out;	/* Send is already done */
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
655
656
  	if (seg_num > mad_send_wr->send_buf.seg_count ||
  	    seg_num > mad_send_wr->newwin) {
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
657
  		spin_unlock_irqrestore(&agent->lock, flags);
fa9656bbd   Jack Morgenstein   IB/mad: include G...
658
  		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
659
660
661
  		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);
  		return;
  	}
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
662
663
664
665
666
  
  	if (newwin < mad_send_wr->newwin || seg_num < mad_send_wr->last_ack)
  		goto out;	/* Old ACK */
  
  	if (seg_num > mad_send_wr->last_ack) {
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
667
  		adjust_last_ack(mad_send_wr, seg_num);
4fc8cd491   Sean Hefty   IB/mad: Report nu...
668
  		mad_send_wr->retries_left = mad_send_wr->max_retries;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
669
670
  	}
  	mad_send_wr->newwin = newwin;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
671
  	if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
672
  		/* If no response is expected, the ACK completes the send */
34816ad98   Sean Hefty   [IB] Fix MAD laye...
673
  		if (!mad_send_wr->send_buf.timeout_ms) {
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
674
675
676
677
678
679
680
  			struct ib_mad_send_wc wc;
  
  			ib_mark_mad_done(mad_send_wr);
  			spin_unlock_irqrestore(&agent->lock, flags);
  
  			wc.status = IB_WC_SUCCESS;
  			wc.vendor_err = 0;
34816ad98   Sean Hefty   [IB] Fix MAD laye...
681
  			wc.send_buf = &mad_send_wr->send_buf;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
682
683
684
685
  			ib_mad_complete_send_wr(mad_send_wr, &wc);
  			return;
  		}
  		if (mad_send_wr->refcount == 1)
34816ad98   Sean Hefty   [IB] Fix MAD laye...
686
687
  			ib_reset_mad_timeout(mad_send_wr,
  					     mad_send_wr->send_buf.timeout_ms);
75ab13443   Sean Hefty   IB/mad: Add suppo...
688
689
690
  		spin_unlock_irqrestore(&agent->lock, flags);
  		ack_ds_ack(agent, mad_recv_wc);
  		return;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
691
692
  	} else if (mad_send_wr->refcount == 1 &&
  		   mad_send_wr->seg_num < mad_send_wr->newwin &&
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
693
  		   mad_send_wr->seg_num < mad_send_wr->send_buf.seg_count) {
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
694
695
696
697
698
699
  		/* Send failure will just result in a timeout/retry */
  		ret = send_next_seg(mad_send_wr);
  		if (ret)
  			goto out;
  
  		mad_send_wr->refcount++;
179e09172   Akinobu Mita   [PATCH] drivers: ...
700
  		list_move_tail(&mad_send_wr->agent_list,
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
701
702
703
704
705
  			      &mad_send_wr->mad_agent_priv->send_list);
  	}
  out:
  	spin_unlock_irqrestore(&agent->lock, flags);
  }
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
706
707
708
709
710
711
712
713
714
715
716
717
718
  static struct ib_mad_recv_wc *
  process_rmpp_data(struct ib_mad_agent_private *agent,
  		  struct ib_mad_recv_wc *mad_recv_wc)
  {
  	struct ib_rmpp_hdr *rmpp_hdr;
  	u8 rmpp_status;
  
  	rmpp_hdr = &((struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad)->rmpp_hdr;
  
  	if (rmpp_hdr->rmpp_status) {
  		rmpp_status = IB_MGMT_RMPP_STATUS_BAD_STATUS;
  		goto bad;
  	}
9c3da0991   Harvey Harrison   IB: Remove __cons...
719
  	if (rmpp_hdr->seg_num == cpu_to_be32(1)) {
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
  		if (!(ib_get_rmpp_flags(rmpp_hdr) & IB_MGMT_RMPP_FLAG_FIRST)) {
  			rmpp_status = IB_MGMT_RMPP_STATUS_BAD_SEG;
  			goto bad;
  		}
  		return start_rmpp(agent, mad_recv_wc);
  	} else {
  		if (ib_get_rmpp_flags(rmpp_hdr) & IB_MGMT_RMPP_FLAG_FIRST) {
  			rmpp_status = IB_MGMT_RMPP_STATUS_BAD_SEG;
  			goto bad;
  		}
  		return continue_rmpp(agent, mad_recv_wc);
  	}
  bad:
  	nack_recv(agent, mad_recv_wc, rmpp_status);
  	ib_free_recv_mad(mad_recv_wc);
  	return NULL;
  }
  
  static void process_rmpp_stop(struct ib_mad_agent_private *agent,
  			      struct ib_mad_recv_wc *mad_recv_wc)
  {
  	struct ib_rmpp_mad *rmpp_mad;
  
  	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
  
  	if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) {
fa9656bbd   Jack Morgenstein   IB/mad: include G...
746
  		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
747
748
  		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
  	} else
fa9656bbd   Jack Morgenstein   IB/mad: include G...
749
  		abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
750
751
752
753
754
755
756
757
758
759
760
  }
  
  static void process_rmpp_abort(struct ib_mad_agent_private *agent,
  			       struct ib_mad_recv_wc *mad_recv_wc)
  {
  	struct ib_rmpp_mad *rmpp_mad;
  
  	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
  
  	if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN ||
  	    rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) {
fa9656bbd   Jack Morgenstein   IB/mad: include G...
761
  		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
762
763
  		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
  	} else
fa9656bbd   Jack Morgenstein   IB/mad: include G...
764
  		abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
765
  }
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
766
767
768
769
770
771
772
773
774
  struct ib_mad_recv_wc *
  ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent,
  			struct ib_mad_recv_wc *mad_recv_wc)
  {
  	struct ib_rmpp_mad *rmpp_mad;
  
  	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
  	if (!(rmpp_mad->rmpp_hdr.rmpp_rtime_flags & IB_MGMT_RMPP_FLAG_ACTIVE))
  		return mad_recv_wc;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
775
  	if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) {
fa9656bbd   Jack Morgenstein   IB/mad: include G...
776
  		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
777
  		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
778
  		goto out;
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
779
  	}
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
780
781
782
  
  	switch (rmpp_mad->rmpp_hdr.rmpp_type) {
  	case IB_MGMT_RMPP_TYPE_DATA:
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
783
  		return process_rmpp_data(agent, mad_recv_wc);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
784
785
786
787
  	case IB_MGMT_RMPP_TYPE_ACK:
  		process_rmpp_ack(agent, mad_recv_wc);
  		break;
  	case IB_MGMT_RMPP_TYPE_STOP:
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
788
789
  		process_rmpp_stop(agent, mad_recv_wc);
  		break;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
790
  	case IB_MGMT_RMPP_TYPE_ABORT:
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
791
  		process_rmpp_abort(agent, mad_recv_wc);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
792
793
  		break;
  	default:
fa9656bbd   Jack Morgenstein   IB/mad: include G...
794
  		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);
fe9e08e17   Sean Hefty   [PATCH] IB: Add h...
795
  		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
796
797
798
799
800
801
  		break;
  	}
  out:
  	ib_free_recv_mad(mad_recv_wc);
  	return NULL;
  }
75ab13443   Sean Hefty   IB/mad: Add suppo...
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
  static int init_newwin(struct ib_mad_send_wr_private *mad_send_wr)
  {
  	struct ib_mad_agent_private *agent = mad_send_wr->mad_agent_priv;
  	struct ib_mad_hdr *mad_hdr = mad_send_wr->send_buf.mad;
  	struct mad_rmpp_recv *rmpp_recv;
  	struct ib_ah_attr ah_attr;
  	unsigned long flags;
  	int newwin = 1;
  
  	if (!(mad_hdr->method & IB_MGMT_METHOD_RESP))
  		goto out;
  
  	spin_lock_irqsave(&agent->lock, flags);
  	list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) {
  		if (rmpp_recv->tid != mad_hdr->tid ||
  		    rmpp_recv->mgmt_class != mad_hdr->mgmt_class ||
  		    rmpp_recv->class_version != mad_hdr->class_version ||
  		    (rmpp_recv->method & IB_MGMT_METHOD_RESP))
  			continue;
  
  		if (ib_query_ah(mad_send_wr->send_buf.ah, &ah_attr))
  			continue;
  
  		if (rmpp_recv->slid == ah_attr.dlid) {
  			newwin = rmpp_recv->repwin;
  			break;
  		}
  	}
  	spin_unlock_irqrestore(&agent->lock, flags);
  out:
  	return newwin;
  }
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
834
835
836
  int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr)
  {
  	struct ib_rmpp_mad *rmpp_mad;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
837
  	int ret;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
838

34816ad98   Sean Hefty   [IB] Fix MAD laye...
839
  	rmpp_mad = mad_send_wr->send_buf.mad;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
840
841
842
  	if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
  	      IB_MGMT_RMPP_FLAG_ACTIVE))
  		return IB_RMPP_RESULT_UNHANDLED;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
843
844
  	if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) {
  		mad_send_wr->seg_num = 1;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
845
  		return IB_RMPP_RESULT_INTERNAL;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
846
  	}
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
847

75ab13443   Sean Hefty   IB/mad: Add suppo...
848
  	mad_send_wr->newwin = init_newwin(mad_send_wr);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
849
850
851
852
853
854
855
856
857
858
859
860
861
  
  	/* We need to wait for the final ACK even if there isn't a response */
  	mad_send_wr->refcount += (mad_send_wr->timeout == 0);
  	ret = send_next_seg(mad_send_wr);
  	if (!ret)
  		return IB_RMPP_RESULT_CONSUMED;
  	return ret;
  }
  
  int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr,
  			    struct ib_mad_send_wc *mad_send_wc)
  {
  	struct ib_rmpp_mad *rmpp_mad;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
862
  	int ret;
34816ad98   Sean Hefty   [IB] Fix MAD laye...
863
  	rmpp_mad = mad_send_wr->send_buf.mad;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
864
865
866
  	if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
  	      IB_MGMT_RMPP_FLAG_ACTIVE))
  		return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */
34816ad98   Sean Hefty   [IB] Fix MAD laye...
867
  	if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA)
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
868
  		return IB_RMPP_RESULT_INTERNAL;	 /* ACK, STOP, or ABORT */
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
869
870
871
872
873
874
875
  
  	if (mad_send_wc->status != IB_WC_SUCCESS ||
  	    mad_send_wr->status != IB_WC_SUCCESS)
  		return IB_RMPP_RESULT_PROCESSED; /* Canceled or send error */
  
  	if (!mad_send_wr->timeout)
  		return IB_RMPP_RESULT_PROCESSED; /* Response received */
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
876
  	if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
877
  		mad_send_wr->timeout =
34816ad98   Sean Hefty   [IB] Fix MAD laye...
878
  			msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
879
880
  		return IB_RMPP_RESULT_PROCESSED; /* Send done */
  	}
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
881
882
  	if (mad_send_wr->seg_num == mad_send_wr->newwin ||
  	    mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count)
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
883
884
885
886
887
888
889
890
891
892
893
894
895
896
  		return IB_RMPP_RESULT_PROCESSED; /* Wait for ACK */
  
  	ret = send_next_seg(mad_send_wr);
  	if (ret) {
  		mad_send_wc->status = IB_WC_GENERAL_ERR;
  		return IB_RMPP_RESULT_PROCESSED;
  	}
  	return IB_RMPP_RESULT_CONSUMED;
  }
  
  int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr)
  {
  	struct ib_rmpp_mad *rmpp_mad;
  	int ret;
34816ad98   Sean Hefty   [IB] Fix MAD laye...
897
  	rmpp_mad = mad_send_wr->send_buf.mad;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
898
899
900
  	if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
  	      IB_MGMT_RMPP_FLAG_ACTIVE))
  		return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
901
  	if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count)
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
902
  		return IB_RMPP_RESULT_PROCESSED;
f36e1793e   Jack Morgenstein   IB/umad: Add supp...
903
904
  	mad_send_wr->seg_num = mad_send_wr->last_ack;
  	mad_send_wr->cur_seg = mad_send_wr->last_ack_seg;
fa619a770   Hal Rosenstock   [PATCH] IB: Add R...
905
906
907
908
909
910
  	ret = send_next_seg(mad_send_wr);
  	if (ret)
  		return IB_RMPP_RESULT_PROCESSED;
  
  	return IB_RMPP_RESULT_CONSUMED;
  }