blob: 72d1db89db8f6d3393154eb542c0b47a39208714 [file] [log] [blame]
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001/*
Bryan O'Sullivan759d5762006-07-01 04:35:49 -07002 * Copyright (c) 2006 QLogic, Inc. All rights reserved.
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08003 * Copyright (c) 2005, 2006 PathScale, 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
34#include <rdma/ib_smi.h>
35
36#include "ipath_kernel.h"
37#include "ipath_verbs.h"
Bryan O'Sullivan27b678d2006-07-01 04:36:17 -070038#include "ipath_common.h"
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -080039
40#define IB_SMP_UNSUP_VERSION __constant_htons(0x0004)
41#define IB_SMP_UNSUP_METHOD __constant_htons(0x0008)
42#define IB_SMP_UNSUP_METH_ATTR __constant_htons(0x000C)
43#define IB_SMP_INVALID_FIELD __constant_htons(0x001C)
44
45static int reply(struct ib_smp *smp)
46{
47 /*
48 * The verbs framework will handle the directed/LID route
49 * packet changes.
50 */
51 smp->method = IB_MGMT_METHOD_GET_RESP;
52 if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
53 smp->status |= IB_SMP_DIRECTION;
54 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
55}
56
57static int recv_subn_get_nodedescription(struct ib_smp *smp,
58 struct ib_device *ibdev)
59{
60 if (smp->attr_mod)
61 smp->status |= IB_SMP_INVALID_FIELD;
62
63 strncpy(smp->data, ibdev->node_desc, sizeof(smp->data));
64
65 return reply(smp);
66}
67
68struct nodeinfo {
69 u8 base_version;
70 u8 class_version;
71 u8 node_type;
72 u8 num_ports;
73 __be64 sys_guid;
74 __be64 node_guid;
75 __be64 port_guid;
76 __be16 partition_cap;
77 __be16 device_id;
78 __be32 revision;
79 u8 local_port_num;
80 u8 vendor_id[3];
81} __attribute__ ((packed));
82
83static int recv_subn_get_nodeinfo(struct ib_smp *smp,
84 struct ib_device *ibdev, u8 port)
85{
86 struct nodeinfo *nip = (struct nodeinfo *)&smp->data;
87 struct ipath_devdata *dd = to_idev(ibdev)->dd;
Bryan O'Sullivane8a88f02006-07-01 04:35:57 -070088 u32 vendor, majrev, minrev;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -080089
90 if (smp->attr_mod)
91 smp->status |= IB_SMP_INVALID_FIELD;
92
93 nip->base_version = 1;
94 nip->class_version = 1;
95 nip->node_type = 1; /* channel adapter */
96 /*
97 * XXX The num_ports value will need a layer function to get
98 * the value if we ever have more than one IB port on a chip.
99 * We will also need to get the GUID for the port.
100 */
101 nip->num_ports = ibdev->phys_port_cnt;
102 /* This is already in network order */
103 nip->sys_guid = to_idev(ibdev)->sys_image_guid;
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700104 nip->node_guid = dd->ipath_guid;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800105 nip->port_guid = nip->sys_guid;
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700106 nip->partition_cap = cpu_to_be16(ipath_get_npkeys(dd));
107 nip->device_id = cpu_to_be16(dd->ipath_deviceid);
108 majrev = dd->ipath_majrev;
109 minrev = dd->ipath_minrev;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800110 nip->revision = cpu_to_be32((majrev << 16) | minrev);
111 nip->local_port_num = port;
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700112 vendor = dd->ipath_vendorid;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800113 nip->vendor_id[0] = 0;
114 nip->vendor_id[1] = vendor >> 8;
115 nip->vendor_id[2] = vendor;
116
117 return reply(smp);
118}
119
120static int recv_subn_get_guidinfo(struct ib_smp *smp,
121 struct ib_device *ibdev)
122{
123 u32 startgx = 8 * be32_to_cpu(smp->attr_mod);
124 __be64 *p = (__be64 *) smp->data;
125
126 /* 32 blocks of 8 64-bit GUIDs per block */
127
128 memset(smp->data, 0, sizeof(smp->data));
129
130 /*
131 * We only support one GUID for now. If this changes, the
132 * portinfo.guid_cap field needs to be updated too.
133 */
134 if (startgx == 0)
135 /* The first is a copy of the read-only HW GUID. */
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700136 *p = to_idev(ibdev)->dd->ipath_guid;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800137 else
138 smp->status |= IB_SMP_INVALID_FIELD;
139
140 return reply(smp);
141}
142
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700143
144static int get_overrunthreshold(struct ipath_devdata *dd)
145{
146 return (dd->ipath_ibcctrl >>
147 INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
148 INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
149}
150
151/**
152 * set_overrunthreshold - set the overrun threshold
153 * @dd: the infinipath device
154 * @n: the new threshold
155 *
156 * Note that this will only take effect when the link state changes.
157 */
158static int set_overrunthreshold(struct ipath_devdata *dd, unsigned n)
159{
160 unsigned v;
161
162 v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
163 INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
164 if (v != n) {
165 dd->ipath_ibcctrl &=
166 ~(INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK <<
167 INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT);
168 dd->ipath_ibcctrl |=
169 (u64) n << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT;
170 ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
171 dd->ipath_ibcctrl);
172 }
173 return 0;
174}
175
176static int get_phyerrthreshold(struct ipath_devdata *dd)
177{
178 return (dd->ipath_ibcctrl >>
179 INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
180 INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
181}
182
183/**
184 * set_phyerrthreshold - set the physical error threshold
185 * @dd: the infinipath device
186 * @n: the new threshold
187 *
188 * Note that this will only take effect when the link state changes.
189 */
190static int set_phyerrthreshold(struct ipath_devdata *dd, unsigned n)
191{
192 unsigned v;
193
194 v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
195 INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
196 if (v != n) {
197 dd->ipath_ibcctrl &=
198 ~(INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK <<
199 INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT);
200 dd->ipath_ibcctrl |=
201 (u64) n << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT;
202 ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
203 dd->ipath_ibcctrl);
204 }
205 return 0;
206}
207
208/**
209 * get_linkdowndefaultstate - get the default linkdown state
210 * @dd: the infinipath device
211 *
212 * Returns zero if the default is POLL, 1 if the default is SLEEP.
213 */
214static int get_linkdowndefaultstate(struct ipath_devdata *dd)
215{
216 return !!(dd->ipath_ibcctrl & INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE);
217}
218
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800219static int recv_subn_get_portinfo(struct ib_smp *smp,
220 struct ib_device *ibdev, u8 port)
221{
222 struct ipath_ibdev *dev;
Leonid Arshda2ab622006-06-17 20:37:36 -0700223 struct ib_port_info *pip = (struct ib_port_info *)smp->data;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800224 u16 lid;
225 u8 ibcstat;
226 u8 mtu;
227 int ret;
228
229 if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt) {
230 smp->status |= IB_SMP_INVALID_FIELD;
231 ret = reply(smp);
232 goto bail;
233 }
234
235 dev = to_idev(ibdev);
236
237 /* Clear all fields. Only set the non-zero fields. */
238 memset(smp->data, 0, sizeof(smp->data));
239
240 /* Only return the mkey if the protection field allows it. */
241 if (smp->method == IB_MGMT_METHOD_SET || dev->mkey == smp->mkey ||
242 (dev->mkeyprot_resv_lmc >> 6) == 0)
243 pip->mkey = dev->mkey;
244 pip->gid_prefix = dev->gid_prefix;
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700245 lid = dev->dd->ipath_lid;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800246 pip->lid = lid ? cpu_to_be16(lid) : IB_LID_PERMISSIVE;
247 pip->sm_lid = cpu_to_be16(dev->sm_lid);
248 pip->cap_mask = cpu_to_be32(dev->port_cap_flags);
249 /* pip->diag_code; */
250 pip->mkey_lease_period = cpu_to_be16(dev->mkey_lease_period);
251 pip->local_port_num = port;
252 pip->link_width_enabled = dev->link_width_enabled;
253 pip->link_width_supported = 3; /* 1x or 4x */
254 pip->link_width_active = 2; /* 4x */
255 pip->linkspeed_portstate = 0x10; /* 2.5Gbps */
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700256 ibcstat = dev->dd->ipath_lastibcstat;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800257 pip->linkspeed_portstate |= ((ibcstat >> 4) & 0x3) + 1;
258 pip->portphysstate_linkdown =
259 (ipath_cvt_physportstate[ibcstat & 0xf] << 4) |
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700260 (get_linkdowndefaultstate(dev->dd) ? 1 : 2);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800261 pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc;
262 pip->linkspeedactive_enabled = 0x11; /* 2.5Gbps, 2.5Gbps */
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700263 switch (dev->dd->ipath_ibmtu) {
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800264 case 4096:
265 mtu = IB_MTU_4096;
266 break;
267 case 2048:
268 mtu = IB_MTU_2048;
269 break;
270 case 1024:
271 mtu = IB_MTU_1024;
272 break;
273 case 512:
274 mtu = IB_MTU_512;
275 break;
276 case 256:
277 mtu = IB_MTU_256;
278 break;
279 default: /* oops, something is wrong */
280 mtu = IB_MTU_2048;
281 break;
282 }
283 pip->neighbormtu_mastersmsl = (mtu << 4) | dev->sm_sl;
284 pip->vlcap_inittype = 0x10; /* VLCap = VL0, InitType = 0 */
285 pip->vl_high_limit = dev->vl_high_limit;
286 /* pip->vl_arb_high_cap; // only one VL */
287 /* pip->vl_arb_low_cap; // only one VL */
288 /* InitTypeReply = 0 */
289 pip->inittypereply_mtucap = IB_MTU_4096;
290 // HCAs ignore VLStallCount and HOQLife
291 /* pip->vlstallcnt_hoqlife; */
292 pip->operationalvl_pei_peo_fpi_fpo = 0x10; /* OVLs = 1 */
293 pip->mkey_violations = cpu_to_be16(dev->mkey_violations);
294 /* P_KeyViolations are counted by hardware. */
295 pip->pkey_violations =
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700296 cpu_to_be16((ipath_get_cr_errpkey(dev->dd) -
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -0700297 dev->z_pkey_violations) & 0xFFFF);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800298 pip->qkey_violations = cpu_to_be16(dev->qkey_violations);
299 /* Only the hardware GUID is supported for now */
300 pip->guid_cap = 1;
301 pip->clientrereg_resv_subnetto = dev->subnet_timeout;
302 /* 32.768 usec. response time (guessing) */
303 pip->resv_resptimevalue = 3;
304 pip->localphyerrors_overrunerrors =
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700305 (get_phyerrthreshold(dev->dd) << 4) |
306 get_overrunthreshold(dev->dd);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800307 /* pip->max_credit_hint; */
308 /* pip->link_roundtrip_latency[3]; */
309
310 ret = reply(smp);
311
312bail:
313 return ret;
314}
315
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700316/**
317 * get_pkeys - return the PKEY table for port 0
318 * @dd: the infinipath device
319 * @pkeys: the pkey table is placed here
320 */
321static int get_pkeys(struct ipath_devdata *dd, u16 * pkeys)
322{
323 struct ipath_portdata *pd = dd->ipath_pd[0];
324
325 memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys));
326
327 return 0;
328}
329
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800330static int recv_subn_get_pkeytable(struct ib_smp *smp,
331 struct ib_device *ibdev)
332{
333 u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff);
334 u16 *p = (u16 *) smp->data;
335 __be16 *q = (__be16 *) smp->data;
336
337 /* 64 blocks of 32 16-bit P_Key entries */
338
339 memset(smp->data, 0, sizeof(smp->data));
340 if (startpx == 0) {
341 struct ipath_ibdev *dev = to_idev(ibdev);
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700342 unsigned i, n = ipath_get_npkeys(dev->dd);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800343
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700344 get_pkeys(dev->dd, p);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800345
346 for (i = 0; i < n; i++)
347 q[i] = cpu_to_be16(p[i]);
348 } else
349 smp->status |= IB_SMP_INVALID_FIELD;
350
351 return reply(smp);
352}
353
354static int recv_subn_set_guidinfo(struct ib_smp *smp,
355 struct ib_device *ibdev)
356{
357 /* The only GUID we support is the first read-only entry. */
358 return recv_subn_get_guidinfo(smp, ibdev);
359}
360
361/**
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700362 * set_linkdowndefaultstate - set the default linkdown state
363 * @dd: the infinipath device
364 * @sleep: the new state
365 *
366 * Note that this will only take effect when the link state changes.
367 */
368static int set_linkdowndefaultstate(struct ipath_devdata *dd, int sleep)
369{
370 if (sleep)
371 dd->ipath_ibcctrl |= INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
372 else
373 dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
374 ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
375 dd->ipath_ibcctrl);
376 return 0;
377}
378
379/**
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800380 * recv_subn_set_portinfo - set port information
381 * @smp: the incoming SM packet
382 * @ibdev: the infiniband device
383 * @port: the port on the device
384 *
385 * Set Portinfo (see ch. 14.2.5.6).
386 */
387static int recv_subn_set_portinfo(struct ib_smp *smp,
388 struct ib_device *ibdev, u8 port)
389{
Leonid Arshda2ab622006-06-17 20:37:36 -0700390 struct ib_port_info *pip = (struct ib_port_info *)smp->data;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800391 struct ib_event event;
392 struct ipath_ibdev *dev;
393 u32 flags;
394 char clientrereg = 0;
395 u16 lid, smlid;
396 u8 lwe;
397 u8 lse;
398 u8 state;
399 u16 lstate;
400 u32 mtu;
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700401 int ret, ore;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800402
403 if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt)
404 goto err;
405
406 dev = to_idev(ibdev);
407 event.device = ibdev;
408 event.element.port_num = port;
409
410 dev->mkey = pip->mkey;
411 dev->gid_prefix = pip->gid_prefix;
412 dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period);
413
414 lid = be16_to_cpu(pip->lid);
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700415 if (lid != dev->dd->ipath_lid) {
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800416 /* Must be a valid unicast LID address. */
Bryan O'Sullivan27b678d2006-07-01 04:36:17 -0700417 if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE)
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800418 goto err;
Bryan O'Sullivan1eb68b92006-07-01 04:36:11 -0700419 ipath_set_lid(dev->dd, lid, pip->mkeyprot_resv_lmc & 7);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800420 event.event = IB_EVENT_LID_CHANGE;
421 ib_dispatch_event(&event);
422 }
423
424 smlid = be16_to_cpu(pip->sm_lid);
425 if (smlid != dev->sm_lid) {
426 /* Must be a valid unicast LID address. */
Bryan O'Sullivan27b678d2006-07-01 04:36:17 -0700427 if (smlid == 0 || smlid >= IPATH_MULTICAST_LID_BASE)
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800428 goto err;
429 dev->sm_lid = smlid;
430 event.event = IB_EVENT_SM_CHANGE;
431 ib_dispatch_event(&event);
432 }
433
434 /* Only 4x supported but allow 1x or 4x to be set (see 14.2.6.6). */
435 lwe = pip->link_width_enabled;
436 if ((lwe >= 4 && lwe <= 8) || (lwe >= 0xC && lwe <= 0xFE))
437 goto err;
438 if (lwe == 0xFF)
439 dev->link_width_enabled = 3; /* 1x or 4x */
440 else if (lwe)
441 dev->link_width_enabled = lwe;
442
443 /* Only 2.5 Gbs supported. */
444 lse = pip->linkspeedactive_enabled & 0xF;
445 if (lse >= 2 && lse <= 0xE)
446 goto err;
447
448 /* Set link down default state. */
449 switch (pip->portphysstate_linkdown & 0xF) {
450 case 0: /* NOP */
451 break;
452 case 1: /* SLEEP */
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700453 if (set_linkdowndefaultstate(dev->dd, 1))
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800454 goto err;
455 break;
456 case 2: /* POLL */
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700457 if (set_linkdowndefaultstate(dev->dd, 0))
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800458 goto err;
459 break;
460 default:
461 goto err;
462 }
463
464 dev->mkeyprot_resv_lmc = pip->mkeyprot_resv_lmc;
465 dev->vl_high_limit = pip->vl_high_limit;
466
467 switch ((pip->neighbormtu_mastersmsl >> 4) & 0xF) {
468 case IB_MTU_256:
469 mtu = 256;
470 break;
471 case IB_MTU_512:
472 mtu = 512;
473 break;
474 case IB_MTU_1024:
475 mtu = 1024;
476 break;
477 case IB_MTU_2048:
478 mtu = 2048;
479 break;
480 case IB_MTU_4096:
481 mtu = 4096;
482 break;
483 default:
484 /* XXX We have already partially updated our state! */
485 goto err;
486 }
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700487 ipath_set_mtu(dev->dd, mtu);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800488
489 dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF;
490
491 /* We only support VL0 */
492 if (((pip->operationalvl_pei_peo_fpi_fpo >> 4) & 0xF) > 1)
493 goto err;
494
495 if (pip->mkey_violations == 0)
496 dev->mkey_violations = 0;
497
498 /*
499 * Hardware counter can't be reset so snapshot and subtract
500 * later.
501 */
502 if (pip->pkey_violations == 0)
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700503 dev->z_pkey_violations = ipath_get_cr_errpkey(dev->dd);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800504
505 if (pip->qkey_violations == 0)
506 dev->qkey_violations = 0;
507
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700508 ore = pip->localphyerrors_overrunerrors;
509 if (set_phyerrthreshold(dev->dd, (ore >> 4) & 0xF))
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800510 goto err;
511
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700512 if (set_overrunthreshold(dev->dd, (ore & 0xF)))
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800513 goto err;
514
515 dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
516
517 if (pip->clientrereg_resv_subnetto & 0x80) {
518 clientrereg = 1;
Roland Dreier6eddb5c2006-06-17 20:37:37 -0700519 event.event = IB_EVENT_CLIENT_REREGISTER;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800520 ib_dispatch_event(&event);
521 }
522
523 /*
524 * Do the port state change now that the other link parameters
525 * have been set.
526 * Changing the port physical state only makes sense if the link
527 * is down or is being set to down.
528 */
529 state = pip->linkspeed_portstate & 0xF;
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700530 flags = dev->dd->ipath_flags;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800531 lstate = (pip->portphysstate_linkdown >> 4) & 0xF;
532 if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))
533 goto err;
534
535 /*
536 * Only state changes of DOWN, ARM, and ACTIVE are valid
537 * and must be in the correct state to take effect (see 7.2.6).
538 */
539 switch (state) {
540 case IB_PORT_NOP:
541 if (lstate == 0)
542 break;
543 /* FALLTHROUGH */
544 case IB_PORT_DOWN:
545 if (lstate == 0)
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700546 if (get_linkdowndefaultstate(dev->dd))
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800547 lstate = IPATH_IB_LINKDOWN_SLEEP;
548 else
549 lstate = IPATH_IB_LINKDOWN;
550 else if (lstate == 1)
551 lstate = IPATH_IB_LINKDOWN_SLEEP;
552 else if (lstate == 2)
553 lstate = IPATH_IB_LINKDOWN;
554 else if (lstate == 3)
555 lstate = IPATH_IB_LINKDOWN_DISABLE;
556 else
557 goto err;
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700558 ipath_set_linkstate(dev->dd, lstate);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800559 if (flags & IPATH_LINKACTIVE) {
560 event.event = IB_EVENT_PORT_ERR;
561 ib_dispatch_event(&event);
562 }
563 break;
564 case IB_PORT_ARMED:
565 if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE)))
566 break;
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700567 ipath_set_linkstate(dev->dd, IPATH_IB_LINKARM);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800568 if (flags & IPATH_LINKACTIVE) {
569 event.event = IB_EVENT_PORT_ERR;
570 ib_dispatch_event(&event);
571 }
572 break;
573 case IB_PORT_ACTIVE:
574 if (!(flags & IPATH_LINKARMED))
575 break;
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700576 ipath_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800577 event.event = IB_EVENT_PORT_ACTIVE;
578 ib_dispatch_event(&event);
579 break;
580 default:
581 /* XXX We have already partially updated our state! */
582 goto err;
583 }
584
585 ret = recv_subn_get_portinfo(smp, ibdev, port);
586
587 if (clientrereg)
588 pip->clientrereg_resv_subnetto |= 0x80;
589
590 goto done;
591
592err:
593 smp->status |= IB_SMP_INVALID_FIELD;
594 ret = recv_subn_get_portinfo(smp, ibdev, port);
595
596done:
597 return ret;
598}
599
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700600/**
601 * rm_pkey - decrecment the reference count for the given PKEY
602 * @dd: the infinipath device
603 * @key: the PKEY index
604 *
605 * Return true if this was the last reference and the hardware table entry
606 * needs to be changed.
607 */
608static int rm_pkey(struct ipath_devdata *dd, u16 key)
609{
610 int i;
611 int ret;
612
613 for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
614 if (dd->ipath_pkeys[i] != key)
615 continue;
616 if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) {
617 dd->ipath_pkeys[i] = 0;
618 ret = 1;
619 goto bail;
620 }
621 break;
622 }
623
624 ret = 0;
625
626bail:
627 return ret;
628}
629
630/**
631 * add_pkey - add the given PKEY to the hardware table
632 * @dd: the infinipath device
633 * @key: the PKEY
634 *
635 * Return an error code if unable to add the entry, zero if no change,
636 * or 1 if the hardware PKEY register needs to be updated.
637 */
638static int add_pkey(struct ipath_devdata *dd, u16 key)
639{
640 int i;
641 u16 lkey = key & 0x7FFF;
642 int any = 0;
643 int ret;
644
645 if (lkey == 0x7FFF) {
646 ret = 0;
647 goto bail;
648 }
649
650 /* Look for an empty slot or a matching PKEY. */
651 for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
652 if (!dd->ipath_pkeys[i]) {
653 any++;
654 continue;
655 }
656 /* If it matches exactly, try to increment the ref count */
657 if (dd->ipath_pkeys[i] == key) {
658 if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) {
659 ret = 0;
660 goto bail;
661 }
662 /* Lost the race. Look for an empty slot below. */
663 atomic_dec(&dd->ipath_pkeyrefs[i]);
664 any++;
665 }
666 /*
667 * It makes no sense to have both the limited and unlimited
668 * PKEY set at the same time since the unlimited one will
669 * disable the limited one.
670 */
671 if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) {
672 ret = -EEXIST;
673 goto bail;
674 }
675 }
676 if (!any) {
677 ret = -EBUSY;
678 goto bail;
679 }
680 for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
681 if (!dd->ipath_pkeys[i] &&
682 atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) {
683 /* for ipathstats, etc. */
684 ipath_stats.sps_pkeys[i] = lkey;
685 dd->ipath_pkeys[i] = key;
686 ret = 1;
687 goto bail;
688 }
689 }
690 ret = -EBUSY;
691
692bail:
693 return ret;
694}
695
696/**
697 * set_pkeys - set the PKEY table for port 0
698 * @dd: the infinipath device
699 * @pkeys: the PKEY table
700 */
701static int set_pkeys(struct ipath_devdata *dd, u16 *pkeys)
702{
703 struct ipath_portdata *pd;
704 int i;
705 int changed = 0;
706
707 pd = dd->ipath_pd[0];
708
709 for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {
710 u16 key = pkeys[i];
711 u16 okey = pd->port_pkeys[i];
712
713 if (key == okey)
714 continue;
715 /*
716 * The value of this PKEY table entry is changing.
717 * Remove the old entry in the hardware's array of PKEYs.
718 */
719 if (okey & 0x7FFF)
720 changed |= rm_pkey(dd, okey);
721 if (key & 0x7FFF) {
722 int ret = add_pkey(dd, key);
723
724 if (ret < 0)
725 key = 0;
726 else
727 changed |= ret;
728 }
729 pd->port_pkeys[i] = key;
730 }
731 if (changed) {
732 u64 pkey;
733
734 pkey = (u64) dd->ipath_pkeys[0] |
735 ((u64) dd->ipath_pkeys[1] << 16) |
736 ((u64) dd->ipath_pkeys[2] << 32) |
737 ((u64) dd->ipath_pkeys[3] << 48);
738 ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n",
739 (unsigned long long) pkey);
740 ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey,
741 pkey);
742 }
743 return 0;
744}
745
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800746static int recv_subn_set_pkeytable(struct ib_smp *smp,
747 struct ib_device *ibdev)
748{
749 u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff);
750 __be16 *p = (__be16 *) smp->data;
751 u16 *q = (u16 *) smp->data;
752 struct ipath_ibdev *dev = to_idev(ibdev);
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700753 unsigned i, n = ipath_get_npkeys(dev->dd);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800754
755 for (i = 0; i < n; i++)
756 q[i] = be16_to_cpu(p[i]);
757
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -0700758 if (startpx != 0 || set_pkeys(dev->dd, q) != 0)
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800759 smp->status |= IB_SMP_INVALID_FIELD;
760
761 return recv_subn_get_pkeytable(smp, ibdev);
762}
763
764#define IB_PMA_CLASS_PORT_INFO __constant_htons(0x0001)
765#define IB_PMA_PORT_SAMPLES_CONTROL __constant_htons(0x0010)
766#define IB_PMA_PORT_SAMPLES_RESULT __constant_htons(0x0011)
767#define IB_PMA_PORT_COUNTERS __constant_htons(0x0012)
768#define IB_PMA_PORT_COUNTERS_EXT __constant_htons(0x001D)
769#define IB_PMA_PORT_SAMPLES_RESULT_EXT __constant_htons(0x001E)
770
771struct ib_perf {
772 u8 base_version;
773 u8 mgmt_class;
774 u8 class_version;
775 u8 method;
776 __be16 status;
777 __be16 unused;
778 __be64 tid;
779 __be16 attr_id;
780 __be16 resv;
781 __be32 attr_mod;
782 u8 reserved[40];
783 u8 data[192];
784} __attribute__ ((packed));
785
786struct ib_pma_classportinfo {
787 u8 base_version;
788 u8 class_version;
789 __be16 cap_mask;
790 u8 reserved[3];
791 u8 resp_time_value; /* only lower 5 bits */
792 union ib_gid redirect_gid;
793 __be32 redirect_tc_sl_fl; /* 8, 4, 20 bits respectively */
794 __be16 redirect_lid;
795 __be16 redirect_pkey;
796 __be32 redirect_qp; /* only lower 24 bits */
797 __be32 redirect_qkey;
798 union ib_gid trap_gid;
799 __be32 trap_tc_sl_fl; /* 8, 4, 20 bits respectively */
800 __be16 trap_lid;
801 __be16 trap_pkey;
802 __be32 trap_hl_qp; /* 8, 24 bits respectively */
803 __be32 trap_qkey;
804} __attribute__ ((packed));
805
806struct ib_pma_portsamplescontrol {
807 u8 opcode;
808 u8 port_select;
809 u8 tick;
810 u8 counter_width; /* only lower 3 bits */
811 __be32 counter_mask0_9; /* 2, 10 * 3, bits */
812 __be16 counter_mask10_14; /* 1, 5 * 3, bits */
813 u8 sample_mechanisms;
814 u8 sample_status; /* only lower 2 bits */
815 __be64 option_mask;
816 __be64 vendor_mask;
817 __be32 sample_start;
818 __be32 sample_interval;
819 __be16 tag;
820 __be16 counter_select[15];
821} __attribute__ ((packed));
822
823struct ib_pma_portsamplesresult {
824 __be16 tag;
825 __be16 sample_status; /* only lower 2 bits */
826 __be32 counter[15];
827} __attribute__ ((packed));
828
829struct ib_pma_portsamplesresult_ext {
830 __be16 tag;
831 __be16 sample_status; /* only lower 2 bits */
832 __be32 extended_width; /* only upper 2 bits */
833 __be64 counter[15];
834} __attribute__ ((packed));
835
836struct ib_pma_portcounters {
837 u8 reserved;
838 u8 port_select;
839 __be16 counter_select;
840 __be16 symbol_error_counter;
841 u8 link_error_recovery_counter;
842 u8 link_downed_counter;
843 __be16 port_rcv_errors;
844 __be16 port_rcv_remphys_errors;
845 __be16 port_rcv_switch_relay_errors;
846 __be16 port_xmit_discards;
847 u8 port_xmit_constraint_errors;
848 u8 port_rcv_constraint_errors;
849 u8 reserved1;
850 u8 lli_ebor_errors; /* 4, 4, bits */
851 __be16 reserved2;
852 __be16 vl15_dropped;
853 __be32 port_xmit_data;
854 __be32 port_rcv_data;
855 __be32 port_xmit_packets;
856 __be32 port_rcv_packets;
857} __attribute__ ((packed));
858
859#define IB_PMA_SEL_SYMBOL_ERROR __constant_htons(0x0001)
860#define IB_PMA_SEL_LINK_ERROR_RECOVERY __constant_htons(0x0002)
861#define IB_PMA_SEL_LINK_DOWNED __constant_htons(0x0004)
862#define IB_PMA_SEL_PORT_RCV_ERRORS __constant_htons(0x0008)
863#define IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS __constant_htons(0x0010)
864#define IB_PMA_SEL_PORT_XMIT_DISCARDS __constant_htons(0x0040)
Bryan O'Sullivanfba75202006-07-01 04:36:09 -0700865#define IB_PMA_SEL_LOCAL_LINK_INTEGRITY_ERRORS __constant_htons(0x0200)
866#define IB_PMA_SEL_EXCESSIVE_BUFFER_OVERRUNS __constant_htons(0x0400)
867#define IB_PMA_SEL_PORT_VL15_DROPPED __constant_htons(0x0800)
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -0800868#define IB_PMA_SEL_PORT_XMIT_DATA __constant_htons(0x1000)
869#define IB_PMA_SEL_PORT_RCV_DATA __constant_htons(0x2000)
870#define IB_PMA_SEL_PORT_XMIT_PACKETS __constant_htons(0x4000)
871#define IB_PMA_SEL_PORT_RCV_PACKETS __constant_htons(0x8000)
872
873struct ib_pma_portcounters_ext {
874 u8 reserved;
875 u8 port_select;
876 __be16 counter_select;
877 __be32 reserved1;
878 __be64 port_xmit_data;
879 __be64 port_rcv_data;
880 __be64 port_xmit_packets;
881 __be64 port_rcv_packets;
882 __be64 port_unicast_xmit_packets;
883 __be64 port_unicast_rcv_packets;
884 __be64 port_multicast_xmit_packets;
885 __be64 port_multicast_rcv_packets;
886} __attribute__ ((packed));
887
888#define IB_PMA_SELX_PORT_XMIT_DATA __constant_htons(0x0001)
889#define IB_PMA_SELX_PORT_RCV_DATA __constant_htons(0x0002)
890#define IB_PMA_SELX_PORT_XMIT_PACKETS __constant_htons(0x0004)
891#define IB_PMA_SELX_PORT_RCV_PACKETS __constant_htons(0x0008)
892#define IB_PMA_SELX_PORT_UNI_XMIT_PACKETS __constant_htons(0x0010)
893#define IB_PMA_SELX_PORT_UNI_RCV_PACKETS __constant_htons(0x0020)
894#define IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS __constant_htons(0x0040)
895#define IB_PMA_SELX_PORT_MULTI_RCV_PACKETS __constant_htons(0x0080)
896
897static int recv_pma_get_classportinfo(struct ib_perf *pmp)
898{
899 struct ib_pma_classportinfo *p =
900 (struct ib_pma_classportinfo *)pmp->data;
901
902 memset(pmp->data, 0, sizeof(pmp->data));
903
904 if (pmp->attr_mod != 0)
905 pmp->status |= IB_SMP_INVALID_FIELD;
906
907 /* Indicate AllPortSelect is valid (only one port anyway) */
908 p->cap_mask = __constant_cpu_to_be16(1 << 8);
909 p->base_version = 1;
910 p->class_version = 1;
911 /*
912 * Expected response time is 4.096 usec. * 2^18 == 1.073741824
913 * sec.
914 */
915 p->resp_time_value = 18;
916
917 return reply((struct ib_smp *) pmp);
918}
919
920/*
921 * The PortSamplesControl.CounterMasks field is an array of 3 bit fields
922 * which specify the N'th counter's capabilities. See ch. 16.1.3.2.
923 * We support 5 counters which only count the mandatory quantities.
924 */
925#define COUNTER_MASK(q, n) (q << ((9 - n) * 3))
926#define COUNTER_MASK0_9 \
927 __constant_cpu_to_be32(COUNTER_MASK(1, 0) | \
928 COUNTER_MASK(1, 1) | \
929 COUNTER_MASK(1, 2) | \
930 COUNTER_MASK(1, 3) | \
931 COUNTER_MASK(1, 4))
932
933static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp,
934 struct ib_device *ibdev, u8 port)
935{
936 struct ib_pma_portsamplescontrol *p =
937 (struct ib_pma_portsamplescontrol *)pmp->data;
938 struct ipath_ibdev *dev = to_idev(ibdev);
939 unsigned long flags;
940 u8 port_select = p->port_select;
941
942 memset(pmp->data, 0, sizeof(pmp->data));
943
944 p->port_select = port_select;
945 if (pmp->attr_mod != 0 ||
946 (port_select != port && port_select != 0xFF))
947 pmp->status |= IB_SMP_INVALID_FIELD;
948 /*
949 * Ticks are 10x the link transfer period which for 2.5Gbs is 4
950 * nsec. 0 == 4 nsec., 1 == 8 nsec., ..., 255 == 1020 nsec. Sample
951 * intervals are counted in ticks. Since we use Linux timers, that
952 * count in jiffies, we can't sample for less than 1000 ticks if HZ
953 * == 1000 (4000 ticks if HZ is 250).
954 */
955 /* XXX This is WRONG. */
956 p->tick = 250; /* 1 usec. */
957 p->counter_width = 4; /* 32 bit counters */
958 p->counter_mask0_9 = COUNTER_MASK0_9;
959 spin_lock_irqsave(&dev->pending_lock, flags);
960 p->sample_status = dev->pma_sample_status;
961 p->sample_start = cpu_to_be32(dev->pma_sample_start);
962 p->sample_interval = cpu_to_be32(dev->pma_sample_interval);
963 p->tag = cpu_to_be16(dev->pma_tag);
964 p->counter_select[0] = dev->pma_counter_select[0];
965 p->counter_select[1] = dev->pma_counter_select[1];
966 p->counter_select[2] = dev->pma_counter_select[2];
967 p->counter_select[3] = dev->pma_counter_select[3];
968 p->counter_select[4] = dev->pma_counter_select[4];
969 spin_unlock_irqrestore(&dev->pending_lock, flags);
970
971 return reply((struct ib_smp *) pmp);
972}
973
974static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp,
975 struct ib_device *ibdev, u8 port)
976{
977 struct ib_pma_portsamplescontrol *p =
978 (struct ib_pma_portsamplescontrol *)pmp->data;
979 struct ipath_ibdev *dev = to_idev(ibdev);
980 unsigned long flags;
981 u32 start;
982 int ret;
983
984 if (pmp->attr_mod != 0 ||
985 (p->port_select != port && p->port_select != 0xFF)) {
986 pmp->status |= IB_SMP_INVALID_FIELD;
987 ret = reply((struct ib_smp *) pmp);
988 goto bail;
989 }
990
991 start = be32_to_cpu(p->sample_start);
992 if (start != 0) {
993 spin_lock_irqsave(&dev->pending_lock, flags);
994 if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_DONE) {
995 dev->pma_sample_status =
996 IB_PMA_SAMPLE_STATUS_STARTED;
997 dev->pma_sample_start = start;
998 dev->pma_sample_interval =
999 be32_to_cpu(p->sample_interval);
1000 dev->pma_tag = be16_to_cpu(p->tag);
1001 if (p->counter_select[0])
1002 dev->pma_counter_select[0] =
1003 p->counter_select[0];
1004 if (p->counter_select[1])
1005 dev->pma_counter_select[1] =
1006 p->counter_select[1];
1007 if (p->counter_select[2])
1008 dev->pma_counter_select[2] =
1009 p->counter_select[2];
1010 if (p->counter_select[3])
1011 dev->pma_counter_select[3] =
1012 p->counter_select[3];
1013 if (p->counter_select[4])
1014 dev->pma_counter_select[4] =
1015 p->counter_select[4];
1016 }
1017 spin_unlock_irqrestore(&dev->pending_lock, flags);
1018 }
1019 ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port);
1020
1021bail:
1022 return ret;
1023}
1024
1025static u64 get_counter(struct ipath_ibdev *dev, __be16 sel)
1026{
1027 u64 ret;
1028
1029 switch (sel) {
1030 case IB_PMA_PORT_XMIT_DATA:
1031 ret = dev->ipath_sword;
1032 break;
1033 case IB_PMA_PORT_RCV_DATA:
1034 ret = dev->ipath_rword;
1035 break;
1036 case IB_PMA_PORT_XMIT_PKTS:
1037 ret = dev->ipath_spkts;
1038 break;
1039 case IB_PMA_PORT_RCV_PKTS:
1040 ret = dev->ipath_rpkts;
1041 break;
1042 case IB_PMA_PORT_XMIT_WAIT:
1043 ret = dev->ipath_xmit_wait;
1044 break;
1045 default:
1046 ret = 0;
1047 }
1048
1049 return ret;
1050}
1051
1052static int recv_pma_get_portsamplesresult(struct ib_perf *pmp,
1053 struct ib_device *ibdev)
1054{
1055 struct ib_pma_portsamplesresult *p =
1056 (struct ib_pma_portsamplesresult *)pmp->data;
1057 struct ipath_ibdev *dev = to_idev(ibdev);
1058 int i;
1059
1060 memset(pmp->data, 0, sizeof(pmp->data));
1061 p->tag = cpu_to_be16(dev->pma_tag);
1062 p->sample_status = cpu_to_be16(dev->pma_sample_status);
1063 for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
1064 p->counter[i] = cpu_to_be32(
1065 get_counter(dev, dev->pma_counter_select[i]));
1066
1067 return reply((struct ib_smp *) pmp);
1068}
1069
1070static int recv_pma_get_portsamplesresult_ext(struct ib_perf *pmp,
1071 struct ib_device *ibdev)
1072{
1073 struct ib_pma_portsamplesresult_ext *p =
1074 (struct ib_pma_portsamplesresult_ext *)pmp->data;
1075 struct ipath_ibdev *dev = to_idev(ibdev);
1076 int i;
1077
1078 memset(pmp->data, 0, sizeof(pmp->data));
1079 p->tag = cpu_to_be16(dev->pma_tag);
1080 p->sample_status = cpu_to_be16(dev->pma_sample_status);
1081 /* 64 bits */
1082 p->extended_width = __constant_cpu_to_be32(0x80000000);
1083 for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
1084 p->counter[i] = cpu_to_be64(
1085 get_counter(dev, dev->pma_counter_select[i]));
1086
1087 return reply((struct ib_smp *) pmp);
1088}
1089
1090static int recv_pma_get_portcounters(struct ib_perf *pmp,
1091 struct ib_device *ibdev, u8 port)
1092{
1093 struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
1094 pmp->data;
1095 struct ipath_ibdev *dev = to_idev(ibdev);
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -07001096 struct ipath_verbs_counters cntrs;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001097 u8 port_select = p->port_select;
1098
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -07001099 ipath_get_counters(dev->dd, &cntrs);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001100
1101 /* Adjust counters for any resets done. */
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001102 cntrs.symbol_error_counter -= dev->z_symbol_error_counter;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001103 cntrs.link_error_recovery_counter -=
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001104 dev->z_link_error_recovery_counter;
1105 cntrs.link_downed_counter -= dev->z_link_downed_counter;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001106 cntrs.port_rcv_errors += dev->rcv_errors;
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001107 cntrs.port_rcv_errors -= dev->z_port_rcv_errors;
1108 cntrs.port_rcv_remphys_errors -= dev->z_port_rcv_remphys_errors;
1109 cntrs.port_xmit_discards -= dev->z_port_xmit_discards;
1110 cntrs.port_xmit_data -= dev->z_port_xmit_data;
1111 cntrs.port_rcv_data -= dev->z_port_rcv_data;
1112 cntrs.port_xmit_packets -= dev->z_port_xmit_packets;
1113 cntrs.port_rcv_packets -= dev->z_port_rcv_packets;
Bryan O'Sullivanfba75202006-07-01 04:36:09 -07001114 cntrs.local_link_integrity_errors -=
1115 dev->z_local_link_integrity_errors;
1116 cntrs.excessive_buffer_overrun_errors -=
1117 dev->z_excessive_buffer_overrun_errors;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001118
1119 memset(pmp->data, 0, sizeof(pmp->data));
1120
1121 p->port_select = port_select;
1122 if (pmp->attr_mod != 0 ||
1123 (port_select != port && port_select != 0xFF))
1124 pmp->status |= IB_SMP_INVALID_FIELD;
1125
1126 if (cntrs.symbol_error_counter > 0xFFFFUL)
1127 p->symbol_error_counter = __constant_cpu_to_be16(0xFFFF);
1128 else
1129 p->symbol_error_counter =
1130 cpu_to_be16((u16)cntrs.symbol_error_counter);
1131 if (cntrs.link_error_recovery_counter > 0xFFUL)
1132 p->link_error_recovery_counter = 0xFF;
1133 else
1134 p->link_error_recovery_counter =
1135 (u8)cntrs.link_error_recovery_counter;
1136 if (cntrs.link_downed_counter > 0xFFUL)
1137 p->link_downed_counter = 0xFF;
1138 else
1139 p->link_downed_counter = (u8)cntrs.link_downed_counter;
1140 if (cntrs.port_rcv_errors > 0xFFFFUL)
1141 p->port_rcv_errors = __constant_cpu_to_be16(0xFFFF);
1142 else
1143 p->port_rcv_errors =
1144 cpu_to_be16((u16) cntrs.port_rcv_errors);
1145 if (cntrs.port_rcv_remphys_errors > 0xFFFFUL)
1146 p->port_rcv_remphys_errors = __constant_cpu_to_be16(0xFFFF);
1147 else
1148 p->port_rcv_remphys_errors =
1149 cpu_to_be16((u16)cntrs.port_rcv_remphys_errors);
1150 if (cntrs.port_xmit_discards > 0xFFFFUL)
1151 p->port_xmit_discards = __constant_cpu_to_be16(0xFFFF);
1152 else
1153 p->port_xmit_discards =
1154 cpu_to_be16((u16)cntrs.port_xmit_discards);
Bryan O'Sullivanfba75202006-07-01 04:36:09 -07001155 if (cntrs.local_link_integrity_errors > 0xFUL)
1156 cntrs.local_link_integrity_errors = 0xFUL;
1157 if (cntrs.excessive_buffer_overrun_errors > 0xFUL)
1158 cntrs.excessive_buffer_overrun_errors = 0xFUL;
1159 p->lli_ebor_errors = (cntrs.local_link_integrity_errors << 4) |
1160 cntrs.excessive_buffer_overrun_errors;
1161 if (dev->n_vl15_dropped > 0xFFFFUL)
1162 p->vl15_dropped = __constant_cpu_to_be16(0xFFFF);
1163 else
1164 p->vl15_dropped = cpu_to_be16((u16)dev->n_vl15_dropped);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001165 if (cntrs.port_xmit_data > 0xFFFFFFFFUL)
1166 p->port_xmit_data = __constant_cpu_to_be32(0xFFFFFFFF);
1167 else
1168 p->port_xmit_data = cpu_to_be32((u32)cntrs.port_xmit_data);
1169 if (cntrs.port_rcv_data > 0xFFFFFFFFUL)
1170 p->port_rcv_data = __constant_cpu_to_be32(0xFFFFFFFF);
1171 else
1172 p->port_rcv_data = cpu_to_be32((u32)cntrs.port_rcv_data);
1173 if (cntrs.port_xmit_packets > 0xFFFFFFFFUL)
1174 p->port_xmit_packets = __constant_cpu_to_be32(0xFFFFFFFF);
1175 else
1176 p->port_xmit_packets =
1177 cpu_to_be32((u32)cntrs.port_xmit_packets);
1178 if (cntrs.port_rcv_packets > 0xFFFFFFFFUL)
1179 p->port_rcv_packets = __constant_cpu_to_be32(0xFFFFFFFF);
1180 else
1181 p->port_rcv_packets =
1182 cpu_to_be32((u32) cntrs.port_rcv_packets);
1183
1184 return reply((struct ib_smp *) pmp);
1185}
1186
1187static int recv_pma_get_portcounters_ext(struct ib_perf *pmp,
1188 struct ib_device *ibdev, u8 port)
1189{
1190 struct ib_pma_portcounters_ext *p =
1191 (struct ib_pma_portcounters_ext *)pmp->data;
1192 struct ipath_ibdev *dev = to_idev(ibdev);
1193 u64 swords, rwords, spkts, rpkts, xwait;
1194 u8 port_select = p->port_select;
1195
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -07001196 ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
1197 &rpkts, &xwait);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001198
1199 /* Adjust counters for any resets done. */
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001200 swords -= dev->z_port_xmit_data;
1201 rwords -= dev->z_port_rcv_data;
1202 spkts -= dev->z_port_xmit_packets;
1203 rpkts -= dev->z_port_rcv_packets;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001204
1205 memset(pmp->data, 0, sizeof(pmp->data));
1206
1207 p->port_select = port_select;
1208 if (pmp->attr_mod != 0 ||
1209 (port_select != port && port_select != 0xFF))
1210 pmp->status |= IB_SMP_INVALID_FIELD;
1211
1212 p->port_xmit_data = cpu_to_be64(swords);
1213 p->port_rcv_data = cpu_to_be64(rwords);
1214 p->port_xmit_packets = cpu_to_be64(spkts);
1215 p->port_rcv_packets = cpu_to_be64(rpkts);
1216 p->port_unicast_xmit_packets = cpu_to_be64(dev->n_unicast_xmit);
1217 p->port_unicast_rcv_packets = cpu_to_be64(dev->n_unicast_rcv);
1218 p->port_multicast_xmit_packets = cpu_to_be64(dev->n_multicast_xmit);
1219 p->port_multicast_rcv_packets = cpu_to_be64(dev->n_multicast_rcv);
1220
1221 return reply((struct ib_smp *) pmp);
1222}
1223
1224static int recv_pma_set_portcounters(struct ib_perf *pmp,
1225 struct ib_device *ibdev, u8 port)
1226{
1227 struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
1228 pmp->data;
1229 struct ipath_ibdev *dev = to_idev(ibdev);
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -07001230 struct ipath_verbs_counters cntrs;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001231
1232 /*
1233 * Since the HW doesn't support clearing counters, we save the
1234 * current count and subtract it from future responses.
1235 */
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -07001236 ipath_get_counters(dev->dd, &cntrs);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001237
1238 if (p->counter_select & IB_PMA_SEL_SYMBOL_ERROR)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001239 dev->z_symbol_error_counter = cntrs.symbol_error_counter;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001240
1241 if (p->counter_select & IB_PMA_SEL_LINK_ERROR_RECOVERY)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001242 dev->z_link_error_recovery_counter =
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001243 cntrs.link_error_recovery_counter;
1244
1245 if (p->counter_select & IB_PMA_SEL_LINK_DOWNED)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001246 dev->z_link_downed_counter = cntrs.link_downed_counter;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001247
1248 if (p->counter_select & IB_PMA_SEL_PORT_RCV_ERRORS)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001249 dev->z_port_rcv_errors =
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001250 cntrs.port_rcv_errors + dev->rcv_errors;
1251
1252 if (p->counter_select & IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001253 dev->z_port_rcv_remphys_errors =
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001254 cntrs.port_rcv_remphys_errors;
1255
1256 if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DISCARDS)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001257 dev->z_port_xmit_discards = cntrs.port_xmit_discards;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001258
Bryan O'Sullivanfba75202006-07-01 04:36:09 -07001259 if (p->counter_select & IB_PMA_SEL_LOCAL_LINK_INTEGRITY_ERRORS)
1260 dev->z_local_link_integrity_errors =
1261 cntrs.local_link_integrity_errors;
1262
1263 if (p->counter_select & IB_PMA_SEL_EXCESSIVE_BUFFER_OVERRUNS)
1264 dev->z_excessive_buffer_overrun_errors =
1265 cntrs.excessive_buffer_overrun_errors;
1266
1267 if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED)
1268 dev->n_vl15_dropped = 0;
1269
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001270 if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001271 dev->z_port_xmit_data = cntrs.port_xmit_data;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001272
1273 if (p->counter_select & IB_PMA_SEL_PORT_RCV_DATA)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001274 dev->z_port_rcv_data = cntrs.port_rcv_data;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001275
1276 if (p->counter_select & IB_PMA_SEL_PORT_XMIT_PACKETS)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001277 dev->z_port_xmit_packets = cntrs.port_xmit_packets;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001278
1279 if (p->counter_select & IB_PMA_SEL_PORT_RCV_PACKETS)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001280 dev->z_port_rcv_packets = cntrs.port_rcv_packets;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001281
1282 return recv_pma_get_portcounters(pmp, ibdev, port);
1283}
1284
1285static int recv_pma_set_portcounters_ext(struct ib_perf *pmp,
1286 struct ib_device *ibdev, u8 port)
1287{
1288 struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
1289 pmp->data;
1290 struct ipath_ibdev *dev = to_idev(ibdev);
1291 u64 swords, rwords, spkts, rpkts, xwait;
1292
Bryan O'Sullivan34b2aaf2006-08-25 11:24:32 -07001293 ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
1294 &rpkts, &xwait);
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001295
1296 if (p->counter_select & IB_PMA_SELX_PORT_XMIT_DATA)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001297 dev->z_port_xmit_data = swords;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001298
1299 if (p->counter_select & IB_PMA_SELX_PORT_RCV_DATA)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001300 dev->z_port_rcv_data = rwords;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001301
1302 if (p->counter_select & IB_PMA_SELX_PORT_XMIT_PACKETS)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001303 dev->z_port_xmit_packets = spkts;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001304
1305 if (p->counter_select & IB_PMA_SELX_PORT_RCV_PACKETS)
Bryan O'Sullivan443a64a2006-07-01 04:35:48 -07001306 dev->z_port_rcv_packets = rpkts;
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001307
1308 if (p->counter_select & IB_PMA_SELX_PORT_UNI_XMIT_PACKETS)
1309 dev->n_unicast_xmit = 0;
1310
1311 if (p->counter_select & IB_PMA_SELX_PORT_UNI_RCV_PACKETS)
1312 dev->n_unicast_rcv = 0;
1313
1314 if (p->counter_select & IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS)
1315 dev->n_multicast_xmit = 0;
1316
1317 if (p->counter_select & IB_PMA_SELX_PORT_MULTI_RCV_PACKETS)
1318 dev->n_multicast_rcv = 0;
1319
1320 return recv_pma_get_portcounters_ext(pmp, ibdev, port);
1321}
1322
1323static int process_subn(struct ib_device *ibdev, int mad_flags,
1324 u8 port_num, struct ib_mad *in_mad,
1325 struct ib_mad *out_mad)
1326{
1327 struct ib_smp *smp = (struct ib_smp *)out_mad;
1328 struct ipath_ibdev *dev = to_idev(ibdev);
1329 int ret;
1330
1331 *out_mad = *in_mad;
1332 if (smp->class_version != 1) {
1333 smp->status |= IB_SMP_UNSUP_VERSION;
1334 ret = reply(smp);
1335 goto bail;
1336 }
1337
1338 /* Is the mkey in the process of expiring? */
1339 if (dev->mkey_lease_timeout && jiffies >= dev->mkey_lease_timeout) {
1340 /* Clear timeout and mkey protection field. */
1341 dev->mkey_lease_timeout = 0;
1342 dev->mkeyprot_resv_lmc &= 0x3F;
1343 }
1344
1345 /*
1346 * M_Key checking depends on
1347 * Portinfo:M_Key_protect_bits
1348 */
1349 if ((mad_flags & IB_MAD_IGNORE_MKEY) == 0 && dev->mkey != 0 &&
1350 dev->mkey != smp->mkey &&
1351 (smp->method == IB_MGMT_METHOD_SET ||
1352 (smp->method == IB_MGMT_METHOD_GET &&
1353 (dev->mkeyprot_resv_lmc >> 7) != 0))) {
1354 if (dev->mkey_violations != 0xFFFF)
1355 ++dev->mkey_violations;
1356 if (dev->mkey_lease_timeout ||
1357 dev->mkey_lease_period == 0) {
1358 ret = IB_MAD_RESULT_SUCCESS |
1359 IB_MAD_RESULT_CONSUMED;
1360 goto bail;
1361 }
1362 dev->mkey_lease_timeout = jiffies +
1363 dev->mkey_lease_period * HZ;
1364 /* Future: Generate a trap notice. */
1365 ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
1366 goto bail;
1367 } else if (dev->mkey_lease_timeout)
1368 dev->mkey_lease_timeout = 0;
1369
1370 switch (smp->method) {
1371 case IB_MGMT_METHOD_GET:
1372 switch (smp->attr_id) {
1373 case IB_SMP_ATTR_NODE_DESC:
1374 ret = recv_subn_get_nodedescription(smp, ibdev);
1375 goto bail;
1376 case IB_SMP_ATTR_NODE_INFO:
1377 ret = recv_subn_get_nodeinfo(smp, ibdev, port_num);
1378 goto bail;
1379 case IB_SMP_ATTR_GUID_INFO:
1380 ret = recv_subn_get_guidinfo(smp, ibdev);
1381 goto bail;
1382 case IB_SMP_ATTR_PORT_INFO:
1383 ret = recv_subn_get_portinfo(smp, ibdev, port_num);
1384 goto bail;
1385 case IB_SMP_ATTR_PKEY_TABLE:
1386 ret = recv_subn_get_pkeytable(smp, ibdev);
1387 goto bail;
1388 case IB_SMP_ATTR_SM_INFO:
1389 if (dev->port_cap_flags & IB_PORT_SM_DISABLED) {
1390 ret = IB_MAD_RESULT_SUCCESS |
1391 IB_MAD_RESULT_CONSUMED;
1392 goto bail;
1393 }
1394 if (dev->port_cap_flags & IB_PORT_SM) {
1395 ret = IB_MAD_RESULT_SUCCESS;
1396 goto bail;
1397 }
1398 /* FALLTHROUGH */
1399 default:
1400 smp->status |= IB_SMP_UNSUP_METH_ATTR;
1401 ret = reply(smp);
1402 goto bail;
1403 }
1404
1405 case IB_MGMT_METHOD_SET:
1406 switch (smp->attr_id) {
1407 case IB_SMP_ATTR_GUID_INFO:
1408 ret = recv_subn_set_guidinfo(smp, ibdev);
1409 goto bail;
1410 case IB_SMP_ATTR_PORT_INFO:
1411 ret = recv_subn_set_portinfo(smp, ibdev, port_num);
1412 goto bail;
1413 case IB_SMP_ATTR_PKEY_TABLE:
1414 ret = recv_subn_set_pkeytable(smp, ibdev);
1415 goto bail;
1416 case IB_SMP_ATTR_SM_INFO:
1417 if (dev->port_cap_flags & IB_PORT_SM_DISABLED) {
1418 ret = IB_MAD_RESULT_SUCCESS |
1419 IB_MAD_RESULT_CONSUMED;
1420 goto bail;
1421 }
1422 if (dev->port_cap_flags & IB_PORT_SM) {
1423 ret = IB_MAD_RESULT_SUCCESS;
1424 goto bail;
1425 }
1426 /* FALLTHROUGH */
1427 default:
1428 smp->status |= IB_SMP_UNSUP_METH_ATTR;
1429 ret = reply(smp);
1430 goto bail;
1431 }
1432
1433 case IB_MGMT_METHOD_GET_RESP:
1434 /*
1435 * The ib_mad module will call us to process responses
1436 * before checking for other consumers.
1437 * Just tell the caller to process it normally.
1438 */
1439 ret = IB_MAD_RESULT_FAILURE;
1440 goto bail;
1441 default:
1442 smp->status |= IB_SMP_UNSUP_METHOD;
1443 ret = reply(smp);
1444 }
1445
1446bail:
1447 return ret;
1448}
1449
1450static int process_perf(struct ib_device *ibdev, u8 port_num,
1451 struct ib_mad *in_mad,
1452 struct ib_mad *out_mad)
1453{
1454 struct ib_perf *pmp = (struct ib_perf *)out_mad;
1455 int ret;
1456
1457 *out_mad = *in_mad;
1458 if (pmp->class_version != 1) {
1459 pmp->status |= IB_SMP_UNSUP_VERSION;
1460 ret = reply((struct ib_smp *) pmp);
1461 goto bail;
1462 }
1463
1464 switch (pmp->method) {
1465 case IB_MGMT_METHOD_GET:
1466 switch (pmp->attr_id) {
1467 case IB_PMA_CLASS_PORT_INFO:
1468 ret = recv_pma_get_classportinfo(pmp);
1469 goto bail;
1470 case IB_PMA_PORT_SAMPLES_CONTROL:
1471 ret = recv_pma_get_portsamplescontrol(pmp, ibdev,
1472 port_num);
1473 goto bail;
1474 case IB_PMA_PORT_SAMPLES_RESULT:
1475 ret = recv_pma_get_portsamplesresult(pmp, ibdev);
1476 goto bail;
1477 case IB_PMA_PORT_SAMPLES_RESULT_EXT:
1478 ret = recv_pma_get_portsamplesresult_ext(pmp,
1479 ibdev);
1480 goto bail;
1481 case IB_PMA_PORT_COUNTERS:
1482 ret = recv_pma_get_portcounters(pmp, ibdev,
1483 port_num);
1484 goto bail;
1485 case IB_PMA_PORT_COUNTERS_EXT:
1486 ret = recv_pma_get_portcounters_ext(pmp, ibdev,
1487 port_num);
1488 goto bail;
1489 default:
1490 pmp->status |= IB_SMP_UNSUP_METH_ATTR;
1491 ret = reply((struct ib_smp *) pmp);
1492 goto bail;
1493 }
1494
1495 case IB_MGMT_METHOD_SET:
1496 switch (pmp->attr_id) {
1497 case IB_PMA_PORT_SAMPLES_CONTROL:
1498 ret = recv_pma_set_portsamplescontrol(pmp, ibdev,
1499 port_num);
1500 goto bail;
1501 case IB_PMA_PORT_COUNTERS:
1502 ret = recv_pma_set_portcounters(pmp, ibdev,
1503 port_num);
1504 goto bail;
1505 case IB_PMA_PORT_COUNTERS_EXT:
1506 ret = recv_pma_set_portcounters_ext(pmp, ibdev,
1507 port_num);
1508 goto bail;
1509 default:
1510 pmp->status |= IB_SMP_UNSUP_METH_ATTR;
1511 ret = reply((struct ib_smp *) pmp);
1512 goto bail;
1513 }
1514
1515 case IB_MGMT_METHOD_GET_RESP:
1516 /*
1517 * The ib_mad module will call us to process responses
1518 * before checking for other consumers.
1519 * Just tell the caller to process it normally.
1520 */
1521 ret = IB_MAD_RESULT_FAILURE;
1522 goto bail;
1523 default:
1524 pmp->status |= IB_SMP_UNSUP_METHOD;
1525 ret = reply((struct ib_smp *) pmp);
1526 }
1527
1528bail:
1529 return ret;
1530}
1531
1532/**
1533 * ipath_process_mad - process an incoming MAD packet
1534 * @ibdev: the infiniband device this packet came in on
1535 * @mad_flags: MAD flags
1536 * @port_num: the port number this packet came in on
1537 * @in_wc: the work completion entry for this packet
1538 * @in_grh: the global route header for this packet
1539 * @in_mad: the incoming MAD
1540 * @out_mad: any outgoing MAD reply
1541 *
1542 * Returns IB_MAD_RESULT_SUCCESS if this is a MAD that we are not
1543 * interested in processing.
1544 *
1545 * Note that the verbs framework has already done the MAD sanity checks,
1546 * and hop count/pointer updating for IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE
1547 * MADs.
1548 *
1549 * This is called by the ib_mad module.
1550 */
1551int ipath_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
1552 struct ib_wc *in_wc, struct ib_grh *in_grh,
1553 struct ib_mad *in_mad, struct ib_mad *out_mad)
1554{
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001555 int ret;
1556
Bryan O'Sullivane28c00a2006-03-29 15:23:37 -08001557 switch (in_mad->mad_hdr.mgmt_class) {
1558 case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
1559 case IB_MGMT_CLASS_SUBN_LID_ROUTED:
1560 ret = process_subn(ibdev, mad_flags, port_num,
1561 in_mad, out_mad);
1562 goto bail;
1563 case IB_MGMT_CLASS_PERF_MGMT:
1564 ret = process_perf(ibdev, port_num, in_mad, out_mad);
1565 goto bail;
1566 default:
1567 ret = IB_MAD_RESULT_SUCCESS;
1568 }
1569
1570bail:
1571 return ret;
1572}