1e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan/*
2e7eacd36865ae0707f5efae8e4dda421ffcd1b66Ralph Campbell * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
3e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
4e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *
5e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * This software is available to you under a choice of one of two
6e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * licenses.  You may choose to be licensed under the terms of the GNU
7e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * General Public License (GPL) Version 2, available from the file
8e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * COPYING in the main directory of this source tree, or the
9e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * OpenIB.org BSD license below:
10e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *
11e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *     Redistribution and use in source and binary forms, with or
12e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *     without modification, are permitted provided that the following
13e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *     conditions are met:
14e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *
15e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *      - Redistributions of source code must retain the above
16e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *        copyright notice, this list of conditions and the following
17e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *        disclaimer.
18e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *
19e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *      - Redistributions in binary form must reproduce the above
20e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *        copyright notice, this list of conditions and the following
21e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *        disclaimer in the documentation and/or other materials
22e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *        provided with the distribution.
23e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *
24e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * SOFTWARE.
32e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan */
33e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
34e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan#include <rdma/ib_smi.h>
356aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz#include <rdma/ib_pma.h>
36e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
37e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan#include "ipath_kernel.h"
38e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan#include "ipath_verbs.h"
3927b678dd04a636f2c351816f4b3042c8815d4e9dBryan O'Sullivan#include "ipath_common.h"
40e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
419c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison#define IB_SMP_UNSUP_VERSION	cpu_to_be16(0x0004)
429c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison#define IB_SMP_UNSUP_METHOD	cpu_to_be16(0x0008)
439c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison#define IB_SMP_UNSUP_METH_ATTR	cpu_to_be16(0x000C)
449c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison#define IB_SMP_INVALID_FIELD	cpu_to_be16(0x001C)
45e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
46e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int reply(struct ib_smp *smp)
47e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
48e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/*
49e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * The verbs framework will handle the directed/LID route
50e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * packet changes.
51e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 */
52e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	smp->method = IB_MGMT_METHOD_GET_RESP;
53e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
54e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		smp->status |= IB_SMP_DIRECTION;
55e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
56e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
57e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
58e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int recv_subn_get_nodedescription(struct ib_smp *smp,
59e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan					 struct ib_device *ibdev)
60e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
61e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (smp->attr_mod)
62e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		smp->status |= IB_SMP_INVALID_FIELD;
63e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
64286b63d09660de0fbd0d7748984d7ae491c7fdb6Roel Kluin	memcpy(smp->data, ibdev->node_desc, sizeof(smp->data));
65e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
66e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return reply(smp);
67e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
68e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
69e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstruct nodeinfo {
70e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 base_version;
71e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 class_version;
72e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 node_type;
73e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 num_ports;
74e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	__be64 sys_guid;
75e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	__be64 node_guid;
76e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	__be64 port_guid;
77e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	__be16 partition_cap;
78e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	__be16 device_id;
79e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	__be32 revision;
80e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 local_port_num;
81e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 vendor_id[3];
82e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan} __attribute__ ((packed));
83e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
84e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int recv_subn_get_nodeinfo(struct ib_smp *smp,
85e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				  struct ib_device *ibdev, u8 port)
86e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
87e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct nodeinfo *nip = (struct nodeinfo *)&smp->data;
88e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_devdata *dd = to_idev(ibdev)->dd;
89e8a88f09f21c55a7e7f570290ecde570e2c37771Bryan O'Sullivan	u32 vendor, majrev, minrev;
90e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
9111b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan	/* GUID 0 is illegal */
9211b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan	if (smp->attr_mod || (dd->ipath_guid == 0))
93e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		smp->status |= IB_SMP_INVALID_FIELD;
94e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
95e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	nip->base_version = 1;
96e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	nip->class_version = 1;
97e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	nip->node_type = 1;	/* channel adapter */
98e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/*
99e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * XXX The num_ports value will need a layer function to get
100e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * the value if we ever have more than one IB port on a chip.
101e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * We will also need to get the GUID for the port.
102e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 */
103e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	nip->num_ports = ibdev->phys_port_cnt;
104e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* This is already in network order */
105e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	nip->sys_guid = to_idev(ibdev)->sys_image_guid;
10634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	nip->node_guid = dd->ipath_guid;
107f41d229865c984015914221959675b1c8723f6a7Sean Hefty	nip->port_guid = dd->ipath_guid;
10834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	nip->partition_cap = cpu_to_be16(ipath_get_npkeys(dd));
10934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	nip->device_id = cpu_to_be16(dd->ipath_deviceid);
11034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	majrev = dd->ipath_majrev;
11134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	minrev = dd->ipath_minrev;
112e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	nip->revision = cpu_to_be32((majrev << 16) | minrev);
113e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	nip->local_port_num = port;
11434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	vendor = dd->ipath_vendorid;
115df8666198dd058b9498ebdbc52c61957206d30a5Ralph Campbell	nip->vendor_id[0] = IPATH_SRC_OUI_1;
116df8666198dd058b9498ebdbc52c61957206d30a5Ralph Campbell	nip->vendor_id[1] = IPATH_SRC_OUI_2;
117df8666198dd058b9498ebdbc52c61957206d30a5Ralph Campbell	nip->vendor_id[2] = IPATH_SRC_OUI_3;
118e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
119e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return reply(smp);
120e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
121e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
122e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int recv_subn_get_guidinfo(struct ib_smp *smp,
123e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				  struct ib_device *ibdev)
124e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
125e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u32 startgx = 8 * be32_to_cpu(smp->attr_mod);
126e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	__be64 *p = (__be64 *) smp->data;
127e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
128e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* 32 blocks of 8 64-bit GUIDs per block */
129e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
130e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	memset(smp->data, 0, sizeof(smp->data));
131e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
132e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/*
133e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * We only support one GUID for now.  If this changes, the
134e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * portinfo.guid_cap field needs to be updated too.
135e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 */
13611b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan	if (startgx == 0) {
13711b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan		__be64 g = to_idev(ibdev)->dd->ipath_guid;
13811b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan		if (g == 0)
13911b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan			/* GUID 0 is illegal */
14011b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan			smp->status |= IB_SMP_INVALID_FIELD;
14111b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan		else
14211b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan			/* The first is a copy of the read-only HW GUID. */
14311b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan			*p = g;
14411b054fe1d453954449a86de178bb98274bb86efBryan O'Sullivan	} else
145e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		smp->status |= IB_SMP_INVALID_FIELD;
146e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
147e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return reply(smp);
148e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
149e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
150a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbellstatic void set_link_width_enabled(struct ipath_devdata *dd, u32 w)
151a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell{
152a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	(void) dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB, w);
153a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell}
154a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell
155a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbellstatic void set_link_speed_enabled(struct ipath_devdata *dd, u32 s)
156a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell{
157a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	(void) dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB, s);
158a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell}
15934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
16034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanstatic int get_overrunthreshold(struct ipath_devdata *dd)
16134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan{
16234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	return (dd->ipath_ibcctrl >>
16334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
16434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
16534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan}
16634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
16734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan/**
16834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * set_overrunthreshold - set the overrun threshold
16934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @dd: the infinipath device
17034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @n: the new threshold
17134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan *
17234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * Note that this will only take effect when the link state changes.
17334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan */
17434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanstatic int set_overrunthreshold(struct ipath_devdata *dd, unsigned n)
17534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan{
17634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	unsigned v;
17734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
17834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
17934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
18034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	if (v != n) {
18134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		dd->ipath_ibcctrl &=
18234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			~(INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK <<
18334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			  INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT);
18434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		dd->ipath_ibcctrl |=
18534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			(u64) n << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT;
18634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
18734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan				 dd->ipath_ibcctrl);
18834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	}
18934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	return 0;
19034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan}
19134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
19234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanstatic int get_phyerrthreshold(struct ipath_devdata *dd)
19334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan{
19434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	return (dd->ipath_ibcctrl >>
19534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
19634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
19734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan}
19834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
19934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan/**
20034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * set_phyerrthreshold - set the physical error threshold
20134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @dd: the infinipath device
20234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @n: the new threshold
20334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan *
20434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * Note that this will only take effect when the link state changes.
20534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan */
20634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanstatic int set_phyerrthreshold(struct ipath_devdata *dd, unsigned n)
20734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan{
20834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	unsigned v;
20934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
21034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
21134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
21234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	if (v != n) {
21334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		dd->ipath_ibcctrl &=
21434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			~(INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK <<
21534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			  INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT);
21634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		dd->ipath_ibcctrl |=
21734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			(u64) n << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT;
21834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
21934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan				 dd->ipath_ibcctrl);
22034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	}
22134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	return 0;
22234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan}
22334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
22434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan/**
22534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * get_linkdowndefaultstate - get the default linkdown state
22634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @dd: the infinipath device
22734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan *
22834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * Returns zero if the default is POLL, 1 if the default is SLEEP.
22934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan */
23034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanstatic int get_linkdowndefaultstate(struct ipath_devdata *dd)
23134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan{
23234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	return !!(dd->ipath_ibcctrl & INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE);
23334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan}
23434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
235e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int recv_subn_get_portinfo(struct ib_smp *smp,
236e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				  struct ib_device *ibdev, u8 port)
237e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
238e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev;
239a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	struct ipath_devdata *dd;
240da2ab62ab5e430e6ffafc2d0e6046dcd2780f570Leonid Arsh	struct ib_port_info *pip = (struct ib_port_info *)smp->data;
241e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u16 lid;
242e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 ibcstat;
243e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 mtu;
244e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	int ret;
245e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
246e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt) {
247e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		smp->status |= IB_SMP_INVALID_FIELD;
248e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = reply(smp);
249e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto bail;
250e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
251e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
252e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	dev = to_idev(ibdev);
253a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	dd = dev->dd;
254e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
255e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* Clear all fields.  Only set the non-zero fields. */
256e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	memset(smp->data, 0, sizeof(smp->data));
257e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
258e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* Only return the mkey if the protection field allows it. */
259e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (smp->method == IB_MGMT_METHOD_SET || dev->mkey == smp->mkey ||
260542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell	    dev->mkeyprot == 0)
261e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		pip->mkey = dev->mkey;
262e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->gid_prefix = dev->gid_prefix;
263a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	lid = dd->ipath_lid;
264e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->lid = lid ? cpu_to_be16(lid) : IB_LID_PERMISSIVE;
265e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->sm_lid = cpu_to_be16(dev->sm_lid);
266e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->cap_mask = cpu_to_be32(dev->port_cap_flags);
267e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* pip->diag_code; */
268e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->mkey_lease_period = cpu_to_be16(dev->mkey_lease_period);
269e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->local_port_num = port;
270a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	pip->link_width_enabled = dd->ipath_link_width_enabled;
271a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	pip->link_width_supported = dd->ipath_link_width_supported;
272a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	pip->link_width_active = dd->ipath_link_width_active;
273a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	pip->linkspeed_portstate = dd->ipath_link_speed_supported << 4;
274a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	ibcstat = dd->ipath_lastibcstat;
275a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	/* map LinkState to IB portinfo values.  */
276a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	pip->linkspeed_portstate |= ipath_ib_linkstate(dd, ibcstat) + 1;
277a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell
278e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->portphysstate_linkdown =
279a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		(ipath_cvt_physportstate[ibcstat & dd->ibcs_lts_mask] << 4) |
280a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		(get_linkdowndefaultstate(dd) ? 1 : 2);
281a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	pip->mkeyprot_resv_lmc = (dev->mkeyprot << 6) | dd->ipath_lmc;
282a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	pip->linkspeedactive_enabled = (dd->ipath_link_speed_active << 4) |
283a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		dd->ipath_link_speed_enabled;
284a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	switch (dd->ipath_ibmtu) {
285e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case 4096:
286e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = IB_MTU_4096;
287e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
288e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case 2048:
289e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = IB_MTU_2048;
290e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
291e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case 1024:
292e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = IB_MTU_1024;
293e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
294e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case 512:
295e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = IB_MTU_512;
296e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
297e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case 256:
298e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = IB_MTU_256;
299e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
300e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	default:		/* oops, something is wrong */
301e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = IB_MTU_2048;
302e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
303e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
304e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->neighbormtu_mastersmsl = (mtu << 4) | dev->sm_sl;
305e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->vlcap_inittype = 0x10;	/* VLCap = VL0, InitType = 0 */
306e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->vl_high_limit = dev->vl_high_limit;
307e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* pip->vl_arb_high_cap; // only one VL */
308e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* pip->vl_arb_low_cap; // only one VL */
309e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* InitTypeReply = 0 */
310826d801009fb3c82832f2d92149446cce354bf61Dave Olson	/* our mtu cap depends on whether 4K MTU enabled or not */
311826d801009fb3c82832f2d92149446cce354bf61Dave Olson	pip->inittypereply_mtucap = ipath_mtu4096 ? IB_MTU_4096 : IB_MTU_2048;
312826d801009fb3c82832f2d92149446cce354bf61Dave Olson	/* HCAs ignore VLStallCount and HOQLife */
313e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* pip->vlstallcnt_hoqlife; */
314e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->operationalvl_pei_peo_fpi_fpo = 0x10;	/* OVLs = 1 */
315e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->mkey_violations = cpu_to_be16(dev->mkey_violations);
316e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* P_KeyViolations are counted by hardware. */
317e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->pkey_violations =
318a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		cpu_to_be16((ipath_get_cr_errpkey(dd) -
319443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan			     dev->z_pkey_violations) & 0xFFFF);
320e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->qkey_violations = cpu_to_be16(dev->qkey_violations);
321e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* Only the hardware GUID is supported for now */
322e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->guid_cap = 1;
323e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->clientrereg_resv_subnetto = dev->subnet_timeout;
324e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* 32.768 usec. response time (guessing) */
325e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->resv_resptimevalue = 3;
326e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	pip->localphyerrors_overrunerrors =
327a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		(get_phyerrthreshold(dd) << 4) |
328a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		get_overrunthreshold(dd);
329e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* pip->max_credit_hint; */
330a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	if (dev->port_cap_flags & IB_PORT_LINK_LATENCY_SUP) {
331a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		u32 v;
332a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell
333a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		v = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LINKLATENCY);
334a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		pip->link_roundtrip_latency[0] = v >> 16;
335a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		pip->link_roundtrip_latency[1] = v >> 8;
336a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		pip->link_roundtrip_latency[2] = v;
337a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	}
338e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
339e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	ret = reply(smp);
340e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
341e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanbail:
342e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return ret;
343e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
344e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
34534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan/**
34634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * get_pkeys - return the PKEY table for port 0
34734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @dd: the infinipath device
34834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @pkeys: the pkey table is placed here
34934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan */
35034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanstatic int get_pkeys(struct ipath_devdata *dd, u16 * pkeys)
35134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan{
3523d0890985ac4dff781b7feba19fedda547314749Dave Olson	/* always a kernel port, no locking needed */
35334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	struct ipath_portdata *pd = dd->ipath_pd[0];
35434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
35534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys));
35634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
35734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	return 0;
35834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan}
35934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
360e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int recv_subn_get_pkeytable(struct ib_smp *smp,
361e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				   struct ib_device *ibdev)
362e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
363e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff);
364e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u16 *p = (u16 *) smp->data;
365e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	__be16 *q = (__be16 *) smp->data;
366e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
367e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* 64 blocks of 32 16-bit P_Key entries */
368e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
369e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	memset(smp->data, 0, sizeof(smp->data));
370e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (startpx == 0) {
371e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		struct ipath_ibdev *dev = to_idev(ibdev);
37234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		unsigned i, n = ipath_get_npkeys(dev->dd);
373e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
37434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		get_pkeys(dev->dd, p);
375e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
376e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		for (i = 0; i < n; i++)
377e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			q[i] = cpu_to_be16(p[i]);
378e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	} else
379e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		smp->status |= IB_SMP_INVALID_FIELD;
380e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
381e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return reply(smp);
382e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
383e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
384e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int recv_subn_set_guidinfo(struct ib_smp *smp,
385e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				  struct ib_device *ibdev)
386e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
387e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* The only GUID we support is the first read-only entry. */
388e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return recv_subn_get_guidinfo(smp, ibdev);
389e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
390e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
391e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan/**
39234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * set_linkdowndefaultstate - set the default linkdown state
39334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @dd: the infinipath device
39434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @sleep: the new state
39534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan *
39634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * Note that this will only take effect when the link state changes.
39734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan */
39834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanstatic int set_linkdowndefaultstate(struct ipath_devdata *dd, int sleep)
39934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan{
40034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	if (sleep)
40134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		dd->ipath_ibcctrl |= INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
40234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	else
40334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
40434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
40534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			 dd->ipath_ibcctrl);
40634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	return 0;
40734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan}
40834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
40934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan/**
410e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * recv_subn_set_portinfo - set port information
411e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * @smp: the incoming SM packet
412e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * @ibdev: the infiniband device
413e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * @port: the port on the device
414e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *
415e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * Set Portinfo (see ch. 14.2.5.6).
416e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan */
417e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int recv_subn_set_portinfo(struct ib_smp *smp,
418e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				  struct ib_device *ibdev, u8 port)
419e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
420da2ab62ab5e430e6ffafc2d0e6046dcd2780f570Leonid Arsh	struct ib_port_info *pip = (struct ib_port_info *)smp->data;
421e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ib_event event;
422e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev;
423542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell	struct ipath_devdata *dd;
424e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	char clientrereg = 0;
425e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u16 lid, smlid;
426e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 lwe;
427e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 lse;
428e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 state;
429e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u16 lstate;
430e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u32 mtu;
43134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	int ret, ore;
432e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
433e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt)
434e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto err;
435e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
436e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	dev = to_idev(ibdev);
437542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell	dd = dev->dd;
438e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	event.device = ibdev;
439e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	event.element.port_num = port;
440e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
441e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	dev->mkey = pip->mkey;
442e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	dev->gid_prefix = pip->gid_prefix;
443e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period);
444e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
445e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	lid = be16_to_cpu(pip->lid);
446542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell	if (dd->ipath_lid != lid ||
447542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell	    dd->ipath_lmc != (pip->mkeyprot_resv_lmc & 7)) {
448e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		/* Must be a valid unicast LID address. */
44927b678dd04a636f2c351816f4b3042c8815d4e9dBryan O'Sullivan		if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE)
450e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto err;
451542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell		ipath_set_lid(dd, lid, pip->mkeyprot_resv_lmc & 7);
452e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		event.event = IB_EVENT_LID_CHANGE;
453e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ib_dispatch_event(&event);
454e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
455e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
456e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	smlid = be16_to_cpu(pip->sm_lid);
457e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (smlid != dev->sm_lid) {
458e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		/* Must be a valid unicast LID address. */
45927b678dd04a636f2c351816f4b3042c8815d4e9dBryan O'Sullivan		if (smlid == 0 || smlid >= IPATH_MULTICAST_LID_BASE)
460e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto err;
461e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		dev->sm_lid = smlid;
462e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		event.event = IB_EVENT_SM_CHANGE;
463e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ib_dispatch_event(&event);
464e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
465e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
466a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	/* Allow 1x or 4x to be set (see 14.2.6.6). */
467e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	lwe = pip->link_width_enabled;
468a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	if (lwe) {
469a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		if (lwe == 0xFF)
470a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell			lwe = dd->ipath_link_width_supported;
471a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		else if (lwe >= 16 || (lwe & ~dd->ipath_link_width_supported))
472a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell			goto err;
473a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		set_link_width_enabled(dd, lwe);
474a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	}
475e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
476a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	/* Allow 2.5 or 5.0 Gbs. */
477e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	lse = pip->linkspeedactive_enabled & 0xF;
478a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	if (lse) {
479a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		if (lse == 15)
480a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell			lse = dd->ipath_link_speed_supported;
481a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		else if (lse >= 8 || (lse & ~dd->ipath_link_speed_supported))
482a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell			goto err;
483a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		set_link_speed_enabled(dd, lse);
484a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	}
485e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
486e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* Set link down default state. */
487e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	switch (pip->portphysstate_linkdown & 0xF) {
488e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case 0: /* NOP */
489e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
490e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case 1: /* SLEEP */
491542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell		if (set_linkdowndefaultstate(dd, 1))
492e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto err;
493e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
494e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case 2: /* POLL */
495542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell		if (set_linkdowndefaultstate(dd, 0))
496e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto err;
497e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
498e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	default:
499e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto err;
500e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
501e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
502542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell	dev->mkeyprot = pip->mkeyprot_resv_lmc >> 6;
503e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	dev->vl_high_limit = pip->vl_high_limit;
504e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
505e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	switch ((pip->neighbormtu_mastersmsl >> 4) & 0xF) {
506e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MTU_256:
507e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = 256;
508e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
509e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MTU_512:
510e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = 512;
511e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
512e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MTU_1024:
513e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = 1024;
514e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
515e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MTU_2048:
516e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = 2048;
517e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
518e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MTU_4096:
519826d801009fb3c82832f2d92149446cce354bf61Dave Olson		if (!ipath_mtu4096)
520826d801009fb3c82832f2d92149446cce354bf61Dave Olson			goto err;
521e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		mtu = 4096;
522e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
523e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	default:
524e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		/* XXX We have already partially updated our state! */
525e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto err;
526e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
527542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell	ipath_set_mtu(dd, mtu);
528e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
529e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF;
530e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
531e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* We only support VL0 */
532e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (((pip->operationalvl_pei_peo_fpi_fpo >> 4) & 0xF) > 1)
533e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto err;
534e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
535e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (pip->mkey_violations == 0)
536e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		dev->mkey_violations = 0;
537e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
538e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/*
539e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * Hardware counter can't be reset so snapshot and subtract
540e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * later.
541e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 */
542e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (pip->pkey_violations == 0)
543542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell		dev->z_pkey_violations = ipath_get_cr_errpkey(dd);
544e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
545e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (pip->qkey_violations == 0)
546e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		dev->qkey_violations = 0;
547e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
54834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	ore = pip->localphyerrors_overrunerrors;
549542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell	if (set_phyerrthreshold(dd, (ore >> 4) & 0xF))
550e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto err;
551e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
552542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell	if (set_overrunthreshold(dd, (ore & 0xF)))
553e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto err;
554e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
555e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
556e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
557e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (pip->clientrereg_resv_subnetto & 0x80) {
558e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		clientrereg = 1;
5596eddb5cb906ac5c9a17a1b76464eadacd88b6c92Roland Dreier		event.event = IB_EVENT_CLIENT_REREGISTER;
560e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ib_dispatch_event(&event);
561e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
562e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
563e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/*
564e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * Do the port state change now that the other link parameters
565e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * have been set.
566e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * Changing the port physical state only makes sense if the link
567e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * is down or is being set to down.
568e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 */
569e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	state = pip->linkspeed_portstate & 0xF;
570e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	lstate = (pip->portphysstate_linkdown >> 4) & 0xF;
571e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))
572e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto err;
573e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
574e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/*
575e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * Only state changes of DOWN, ARM, and ACTIVE are valid
576e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * and must be in the correct state to take effect (see 7.2.6).
577e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 */
578e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	switch (state) {
579e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_PORT_NOP:
580e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		if (lstate == 0)
581e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			break;
582e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		/* FALLTHROUGH */
583e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_PORT_DOWN:
584e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		if (lstate == 0)
585140277e9a710202608914b5b731948d2769399bcRalph Campbell			lstate = IPATH_IB_LINKDOWN_ONLY;
586e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		else if (lstate == 1)
587e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			lstate = IPATH_IB_LINKDOWN_SLEEP;
588e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		else if (lstate == 2)
589e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			lstate = IPATH_IB_LINKDOWN;
590e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		else if (lstate == 3)
591e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			lstate = IPATH_IB_LINKDOWN_DISABLE;
592e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		else
593e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto err;
594542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell		ipath_set_linkstate(dd, lstate);
5954330e4dad780467d930b394b5119c0218a1e2dbeMichael Albaugh		if (lstate == IPATH_IB_LINKDOWN_DISABLE) {
5964330e4dad780467d930b394b5119c0218a1e2dbeMichael Albaugh			ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
5974330e4dad780467d930b394b5119c0218a1e2dbeMichael Albaugh			goto done;
5984330e4dad780467d930b394b5119c0218a1e2dbeMichael Albaugh		}
599140277e9a710202608914b5b731948d2769399bcRalph Campbell		ipath_wait_linkstate(dd, IPATH_LINKINIT | IPATH_LINKARMED |
600140277e9a710202608914b5b731948d2769399bcRalph Campbell				IPATH_LINKACTIVE, 1000);
601e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
602e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_PORT_ARMED:
603542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell		ipath_set_linkstate(dd, IPATH_IB_LINKARM);
604e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
605e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_PORT_ACTIVE:
606542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell		ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
607e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
608e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	default:
609e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		/* XXX We have already partially updated our state! */
610e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto err;
611e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
612e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
613e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	ret = recv_subn_get_portinfo(smp, ibdev, port);
614e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
615e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (clientrereg)
616e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		pip->clientrereg_resv_subnetto |= 0x80;
617e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
618e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	goto done;
619e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
620e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanerr:
621e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	smp->status |= IB_SMP_INVALID_FIELD;
622e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	ret = recv_subn_get_portinfo(smp, ibdev, port);
623e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
624e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivandone:
625e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return ret;
626e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
627e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
62834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan/**
62934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * rm_pkey - decrecment the reference count for the given PKEY
63034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @dd: the infinipath device
63134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @key: the PKEY index
63234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan *
63334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * Return true if this was the last reference and the hardware table entry
63434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * needs to be changed.
63534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan */
63634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanstatic int rm_pkey(struct ipath_devdata *dd, u16 key)
63734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan{
63834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	int i;
63934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	int ret;
64034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
64134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
64234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		if (dd->ipath_pkeys[i] != key)
64334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			continue;
64434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) {
64534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			dd->ipath_pkeys[i] = 0;
64634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			ret = 1;
64734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			goto bail;
64834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		}
64934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		break;
65034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	}
65134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
65234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	ret = 0;
65334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
65434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanbail:
65534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	return ret;
65634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan}
65734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
65834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan/**
65934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * add_pkey - add the given PKEY to the hardware table
66034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @dd: the infinipath device
66134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @key: the PKEY
66234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan *
66334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * Return an error code if unable to add the entry, zero if no change,
66434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * or 1 if the hardware PKEY register needs to be updated.
66534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan */
66634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanstatic int add_pkey(struct ipath_devdata *dd, u16 key)
66734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan{
66834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	int i;
66934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	u16 lkey = key & 0x7FFF;
67034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	int any = 0;
67134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	int ret;
67234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
67334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	if (lkey == 0x7FFF) {
67434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		ret = 0;
67534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		goto bail;
67634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	}
67734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
67834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	/* Look for an empty slot or a matching PKEY. */
67934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
68034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		if (!dd->ipath_pkeys[i]) {
68134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			any++;
68234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			continue;
68334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		}
68434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		/* If it matches exactly, try to increment the ref count */
68534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		if (dd->ipath_pkeys[i] == key) {
68634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) {
68734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan				ret = 0;
68834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan				goto bail;
68934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			}
69034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			/* Lost the race. Look for an empty slot below. */
69134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			atomic_dec(&dd->ipath_pkeyrefs[i]);
69234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			any++;
69334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		}
69434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		/*
69534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		 * It makes no sense to have both the limited and unlimited
69634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		 * PKEY set at the same time since the unlimited one will
69734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		 * disable the limited one.
69834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		 */
69934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) {
70034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			ret = -EEXIST;
70134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			goto bail;
70234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		}
70334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	}
70434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	if (!any) {
70534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		ret = -EBUSY;
70634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		goto bail;
70734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	}
70834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
70934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		if (!dd->ipath_pkeys[i] &&
71034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		    atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) {
71134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			/* for ipathstats, etc. */
71234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			ipath_stats.sps_pkeys[i] = lkey;
71334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			dd->ipath_pkeys[i] = key;
71434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			ret = 1;
71534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			goto bail;
71634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		}
71734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	}
71834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	ret = -EBUSY;
71934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
72034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanbail:
72134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	return ret;
72234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan}
72334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
72434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan/**
72534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * set_pkeys - set the PKEY table for port 0
72634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @dd: the infinipath device
72734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan * @pkeys: the PKEY table
72834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan */
72934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivanstatic int set_pkeys(struct ipath_devdata *dd, u16 *pkeys)
73034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan{
73134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	struct ipath_portdata *pd;
73234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	int i;
73334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	int changed = 0;
73434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
7353d0890985ac4dff781b7feba19fedda547314749Dave Olson	/* always a kernel port, no locking needed */
73634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	pd = dd->ipath_pd[0];
73734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
73834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {
73934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		u16 key = pkeys[i];
74034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		u16 okey = pd->port_pkeys[i];
74134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
74234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		if (key == okey)
74334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			continue;
74434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		/*
74534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		 * The value of this PKEY table entry is changing.
74634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		 * Remove the old entry in the hardware's array of PKEYs.
74734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		 */
74834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		if (okey & 0x7FFF)
74934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			changed |= rm_pkey(dd, okey);
75034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		if (key & 0x7FFF) {
75134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			int ret = add_pkey(dd, key);
75234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
75334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			if (ret < 0)
75434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan				key = 0;
75534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			else
75634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan				changed |= ret;
75734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		}
75834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		pd->port_pkeys[i] = key;
75934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	}
76034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	if (changed) {
76134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		u64 pkey;
76234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
76334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		pkey = (u64) dd->ipath_pkeys[0] |
76434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			((u64) dd->ipath_pkeys[1] << 16) |
76534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			((u64) dd->ipath_pkeys[2] << 32) |
76634b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			((u64) dd->ipath_pkeys[3] << 48);
76734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n",
76834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan			   (unsigned long long) pkey);
76934b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan		ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey,
77034b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan				 pkey);
77134b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	}
77234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	return 0;
77334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan}
77434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan
775e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int recv_subn_set_pkeytable(struct ib_smp *smp,
776e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				   struct ib_device *ibdev)
777e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
778e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff);
779e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	__be16 *p = (__be16 *) smp->data;
780e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u16 *q = (u16 *) smp->data;
781e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev = to_idev(ibdev);
78234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	unsigned i, n = ipath_get_npkeys(dev->dd);
783e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
784e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	for (i = 0; i < n; i++)
785e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		q[i] = be16_to_cpu(p[i]);
786e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
78734b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	if (startpx != 0 || set_pkeys(dev->dd, q) != 0)
788e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		smp->status |= IB_SMP_INVALID_FIELD;
789e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
790e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return recv_subn_get_pkeytable(smp, ibdev);
791e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
792e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
7936aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitzstatic int recv_pma_get_classportinfo(struct ib_pma_mad *pmp)
794e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
7956aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	struct ib_class_port_info *p =
7966aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz		(struct ib_class_port_info *)pmp->data;
797e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
798e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	memset(pmp->data, 0, sizeof(pmp->data));
799e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
8006aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	if (pmp->mad_hdr.attr_mod != 0)
8016aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz		pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
802e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
803e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* Indicate AllPortSelect is valid (only one port anyway) */
8046aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	p->capability_mask = cpu_to_be16(1 << 8);
805e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->base_version = 1;
806e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->class_version = 1;
807e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/*
808e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * Expected response time is 4.096 usec. * 2^18 == 1.073741824
809e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * sec.
810e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 */
811e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->resp_time_value = 18;
812e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
813e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return reply((struct ib_smp *) pmp);
814e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
815e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
816e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan/*
817e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * The PortSamplesControl.CounterMasks field is an array of 3 bit fields
818e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * which specify the N'th counter's capabilities. See ch. 16.1.3.2.
819e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * We support 5 counters which only count the mandatory quantities.
820e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan */
821e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan#define COUNTER_MASK(q, n) (q << ((9 - n) * 3))
8229c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison#define COUNTER_MASK0_9 cpu_to_be32(COUNTER_MASK(1, 0) | \
8239c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison				    COUNTER_MASK(1, 1) | \
8249c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison				    COUNTER_MASK(1, 2) | \
8259c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison				    COUNTER_MASK(1, 3) | \
8269c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison				    COUNTER_MASK(1, 4))
827e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
8286aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitzstatic int recv_pma_get_portsamplescontrol(struct ib_pma_mad *pmp,
829e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan					   struct ib_device *ibdev, u8 port)
830e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
831e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ib_pma_portsamplescontrol *p =
832e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		(struct ib_pma_portsamplescontrol *)pmp->data;
833e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev = to_idev(ibdev);
8346c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
835e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	unsigned long flags;
836e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 port_select = p->port_select;
837e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
838e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	memset(pmp->data, 0, sizeof(pmp->data));
839e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
840e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_select = port_select;
8416aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	if (pmp->mad_hdr.attr_mod != 0 ||
842e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	    (port_select != port && port_select != 0xFF))
8436aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz		pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
844e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/*
845e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * Ticks are 10x the link transfer period which for 2.5Gbs is 4
846e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * nsec.  0 == 4 nsec., 1 == 8 nsec., ..., 255 == 1020 nsec.  Sample
847e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * intervals are counted in ticks.  Since we use Linux timers, that
848e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * count in jiffies, we can't sample for less than 1000 ticks if HZ
849a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	 * == 1000 (4000 ticks if HZ is 250).  link_speed_active returns 2 for
850a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	 * DDR, 1 for SDR, set the tick to 1 for DDR, 0 for SDR on chips that
851a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	 * have hardware support for delaying packets.
852e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 */
853a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	if (crp->cr_psstat)
854a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		p->tick = dev->dd->ipath_link_speed_active - 1;
855a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell	else
856a51a2513a8cb201f02d83c37e106909938d2f761Ralph Campbell		p->tick = 250;		/* 1 usec. */
857e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->counter_width = 4;	/* 32 bit counters */
858e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->counter_mask0_9 = COUNTER_MASK0_9;
859e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	spin_lock_irqsave(&dev->pending_lock, flags);
8606c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	if (crp->cr_psstat)
8616c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		p->sample_status = ipath_read_creg32(dev->dd, crp->cr_psstat);
8626c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	else
8636c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		p->sample_status = dev->pma_sample_status;
864e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->sample_start = cpu_to_be32(dev->pma_sample_start);
865e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->sample_interval = cpu_to_be32(dev->pma_sample_interval);
866e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->tag = cpu_to_be16(dev->pma_tag);
867e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->counter_select[0] = dev->pma_counter_select[0];
868e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->counter_select[1] = dev->pma_counter_select[1];
869e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->counter_select[2] = dev->pma_counter_select[2];
870e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->counter_select[3] = dev->pma_counter_select[3];
871e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->counter_select[4] = dev->pma_counter_select[4];
872e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	spin_unlock_irqrestore(&dev->pending_lock, flags);
873e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
874e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return reply((struct ib_smp *) pmp);
875e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
876e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
8776aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitzstatic int recv_pma_set_portsamplescontrol(struct ib_pma_mad *pmp,
878e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan					   struct ib_device *ibdev, u8 port)
879e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
880e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ib_pma_portsamplescontrol *p =
881e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		(struct ib_pma_portsamplescontrol *)pmp->data;
882e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev = to_idev(ibdev);
8836c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
884e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	unsigned long flags;
8856c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	u8 status;
886e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	int ret;
887e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
8886aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	if (pmp->mad_hdr.attr_mod != 0 ||
889e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	    (p->port_select != port && p->port_select != 0xFF)) {
8906aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz		pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
891e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = reply((struct ib_smp *) pmp);
892e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto bail;
893e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
894e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
8956c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	spin_lock_irqsave(&dev->pending_lock, flags);
8966c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	if (crp->cr_psstat)
8976c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
8986c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	else
8996c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		status = dev->pma_sample_status;
9006c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	if (status == IB_PMA_SAMPLE_STATUS_DONE) {
9016c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		dev->pma_sample_start = be32_to_cpu(p->sample_start);
9026c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		dev->pma_sample_interval = be32_to_cpu(p->sample_interval);
9036c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		dev->pma_tag = be16_to_cpu(p->tag);
9046c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		dev->pma_counter_select[0] = p->counter_select[0];
9056c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		dev->pma_counter_select[1] = p->counter_select[1];
9066c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		dev->pma_counter_select[2] = p->counter_select[2];
9076c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		dev->pma_counter_select[3] = p->counter_select[3];
9086c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		dev->pma_counter_select[4] = p->counter_select[4];
9096c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		if (crp->cr_psstat) {
9106c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			ipath_write_creg(dev->dd, crp->cr_psinterval,
9116c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell					 dev->pma_sample_interval);
9126c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			ipath_write_creg(dev->dd, crp->cr_psstart,
9136c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell					 dev->pma_sample_start);
9146c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		} else
9156c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_STARTED;
916e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
9176c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	spin_unlock_irqrestore(&dev->pending_lock, flags);
9186c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell
919e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port);
920e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
921e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanbail:
922e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return ret;
923e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
924e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
9256c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbellstatic u64 get_counter(struct ipath_ibdev *dev,
9266c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		       struct ipath_cregs const *crp,
9276c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		       __be16 sel)
928e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
929e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u64 ret;
930e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
931e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	switch (sel) {
932e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_PMA_PORT_XMIT_DATA:
9336c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		ret = (crp->cr_psxmitdatacount) ?
9346c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			ipath_read_creg32(dev->dd, crp->cr_psxmitdatacount) :
9356c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			dev->ipath_sword;
936e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
937e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_PMA_PORT_RCV_DATA:
9386c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		ret = (crp->cr_psrcvdatacount) ?
9396c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			ipath_read_creg32(dev->dd, crp->cr_psrcvdatacount) :
9406c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			dev->ipath_rword;
941e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
942e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_PMA_PORT_XMIT_PKTS:
9436c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		ret = (crp->cr_psxmitpktscount) ?
9446c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			ipath_read_creg32(dev->dd, crp->cr_psxmitpktscount) :
9456c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			dev->ipath_spkts;
946e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
947e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_PMA_PORT_RCV_PKTS:
9486c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		ret = (crp->cr_psrcvpktscount) ?
9496c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			ipath_read_creg32(dev->dd, crp->cr_psrcvpktscount) :
9506c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			dev->ipath_rpkts;
951e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
952e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_PMA_PORT_XMIT_WAIT:
9536c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		ret = (crp->cr_psxmitwaitcount) ?
9546c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			ipath_read_creg32(dev->dd, crp->cr_psxmitwaitcount) :
9556c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			dev->ipath_xmit_wait;
956e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		break;
957e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	default:
958e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = 0;
959e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
960e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
961e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return ret;
962e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
963e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
9646aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitzstatic int recv_pma_get_portsamplesresult(struct ib_pma_mad *pmp,
965e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan					  struct ib_device *ibdev)
966e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
967e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ib_pma_portsamplesresult *p =
968e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		(struct ib_pma_portsamplesresult *)pmp->data;
969e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev = to_idev(ibdev);
9706c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
9716c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	u8 status;
972e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	int i;
973e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
974e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	memset(pmp->data, 0, sizeof(pmp->data));
975e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->tag = cpu_to_be16(dev->pma_tag);
9766c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	if (crp->cr_psstat)
9776c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
9786c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	else
9796c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		status = dev->pma_sample_status;
9806c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	p->sample_status = cpu_to_be16(status);
981e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
9826c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
9836c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		    cpu_to_be32(
9846c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			get_counter(dev, crp, dev->pma_counter_select[i]));
985e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
986e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return reply((struct ib_smp *) pmp);
987e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
988e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
9896aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitzstatic int recv_pma_get_portsamplesresult_ext(struct ib_pma_mad *pmp,
990e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan					      struct ib_device *ibdev)
991e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
992e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ib_pma_portsamplesresult_ext *p =
993e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		(struct ib_pma_portsamplesresult_ext *)pmp->data;
994e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev = to_idev(ibdev);
9956c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
9966c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	u8 status;
997e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	int i;
998e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
999e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	memset(pmp->data, 0, sizeof(pmp->data));
1000e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->tag = cpu_to_be16(dev->pma_tag);
10016c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	if (crp->cr_psstat)
10026c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
10036c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	else
10046c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		status = dev->pma_sample_status;
10056c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	p->sample_status = cpu_to_be16(status);
1006e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* 64 bits */
10079c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison	p->extended_width = cpu_to_be32(0x80000000);
1008e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
10096c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
10106c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		    cpu_to_be64(
10116c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell			get_counter(dev, crp, dev->pma_counter_select[i]));
1012e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1013e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return reply((struct ib_smp *) pmp);
1014e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
1015e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
10166aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitzstatic int recv_pma_get_portcounters(struct ib_pma_mad *pmp,
1017e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				     struct ib_device *ibdev, u8 port)
1018e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
1019e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
1020e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		pmp->data;
1021e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev = to_idev(ibdev);
102234b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	struct ipath_verbs_counters cntrs;
1023e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 port_select = p->port_select;
1024e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
102534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	ipath_get_counters(dev->dd, &cntrs);
1026e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1027e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* Adjust counters for any resets done. */
1028443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	cntrs.symbol_error_counter -= dev->z_symbol_error_counter;
1029e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	cntrs.link_error_recovery_counter -=
1030443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_link_error_recovery_counter;
1031443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	cntrs.link_downed_counter -= dev->z_link_downed_counter;
1032e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	cntrs.port_rcv_errors += dev->rcv_errors;
1033443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	cntrs.port_rcv_errors -= dev->z_port_rcv_errors;
1034443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	cntrs.port_rcv_remphys_errors -= dev->z_port_rcv_remphys_errors;
1035443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	cntrs.port_xmit_discards -= dev->z_port_xmit_discards;
1036443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	cntrs.port_xmit_data -= dev->z_port_xmit_data;
1037443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	cntrs.port_rcv_data -= dev->z_port_rcv_data;
1038443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	cntrs.port_xmit_packets -= dev->z_port_xmit_packets;
1039443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	cntrs.port_rcv_packets -= dev->z_port_rcv_packets;
1040fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan	cntrs.local_link_integrity_errors -=
1041fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan		dev->z_local_link_integrity_errors;
1042fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan	cntrs.excessive_buffer_overrun_errors -=
1043fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan		dev->z_excessive_buffer_overrun_errors;
10446c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	cntrs.vl15_dropped -= dev->z_vl15_dropped;
10456c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	cntrs.vl15_dropped += dev->n_vl15_dropped;
1046e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1047e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	memset(pmp->data, 0, sizeof(pmp->data));
1048e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1049e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_select = port_select;
10506aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	if (pmp->mad_hdr.attr_mod != 0 ||
1051e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	    (port_select != port && port_select != 0xFF))
10526aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz		pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
1053e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1054e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (cntrs.symbol_error_counter > 0xFFFFUL)
10559c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison		p->symbol_error_counter = cpu_to_be16(0xFFFF);
1056e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	else
1057e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->symbol_error_counter =
1058e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			cpu_to_be16((u16)cntrs.symbol_error_counter);
1059e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (cntrs.link_error_recovery_counter > 0xFFUL)
1060e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->link_error_recovery_counter = 0xFF;
1061e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	else
1062e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->link_error_recovery_counter =
1063e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			(u8)cntrs.link_error_recovery_counter;
1064e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (cntrs.link_downed_counter > 0xFFUL)
1065e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->link_downed_counter = 0xFF;
1066e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	else
1067e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->link_downed_counter = (u8)cntrs.link_downed_counter;
1068e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (cntrs.port_rcv_errors > 0xFFFFUL)
10699c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison		p->port_rcv_errors = cpu_to_be16(0xFFFF);
1070e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	else
1071e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->port_rcv_errors =
1072e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			cpu_to_be16((u16) cntrs.port_rcv_errors);
1073e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (cntrs.port_rcv_remphys_errors > 0xFFFFUL)
10749c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison		p->port_rcv_remphys_errors = cpu_to_be16(0xFFFF);
1075e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	else
1076e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->port_rcv_remphys_errors =
1077e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			cpu_to_be16((u16)cntrs.port_rcv_remphys_errors);
1078e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (cntrs.port_xmit_discards > 0xFFFFUL)
10799c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison		p->port_xmit_discards = cpu_to_be16(0xFFFF);
1080e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	else
1081e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->port_xmit_discards =
1082e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			cpu_to_be16((u16)cntrs.port_xmit_discards);
1083fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan	if (cntrs.local_link_integrity_errors > 0xFUL)
1084fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan		cntrs.local_link_integrity_errors = 0xFUL;
1085fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan	if (cntrs.excessive_buffer_overrun_errors > 0xFUL)
1086fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan		cntrs.excessive_buffer_overrun_errors = 0xFUL;
10876aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	p->link_overrun_errors = (cntrs.local_link_integrity_errors << 4) |
1088fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan		cntrs.excessive_buffer_overrun_errors;
10896c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	if (cntrs.vl15_dropped > 0xFFFFUL)
10909c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison		p->vl15_dropped = cpu_to_be16(0xFFFF);
1091fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan	else
10926c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		p->vl15_dropped = cpu_to_be16((u16)cntrs.vl15_dropped);
1093e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (cntrs.port_xmit_data > 0xFFFFFFFFUL)
10949c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison		p->port_xmit_data = cpu_to_be32(0xFFFFFFFF);
1095e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	else
1096e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->port_xmit_data = cpu_to_be32((u32)cntrs.port_xmit_data);
1097e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (cntrs.port_rcv_data > 0xFFFFFFFFUL)
10989c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison		p->port_rcv_data = cpu_to_be32(0xFFFFFFFF);
1099e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	else
1100e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->port_rcv_data = cpu_to_be32((u32)cntrs.port_rcv_data);
1101e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (cntrs.port_xmit_packets > 0xFFFFFFFFUL)
11029c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison		p->port_xmit_packets = cpu_to_be32(0xFFFFFFFF);
1103e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	else
1104e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->port_xmit_packets =
1105e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			cpu_to_be32((u32)cntrs.port_xmit_packets);
1106e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (cntrs.port_rcv_packets > 0xFFFFFFFFUL)
11079c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison		p->port_rcv_packets = cpu_to_be32(0xFFFFFFFF);
1108e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	else
1109e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		p->port_rcv_packets =
1110e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			cpu_to_be32((u32) cntrs.port_rcv_packets);
1111e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1112e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return reply((struct ib_smp *) pmp);
1113e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
1114e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
11156aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitzstatic int recv_pma_get_portcounters_ext(struct ib_pma_mad *pmp,
1116e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan					 struct ib_device *ibdev, u8 port)
1117e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
1118e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ib_pma_portcounters_ext *p =
1119e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		(struct ib_pma_portcounters_ext *)pmp->data;
1120e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev = to_idev(ibdev);
1121e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u64 swords, rwords, spkts, rpkts, xwait;
1122e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u8 port_select = p->port_select;
1123e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
112434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
112534b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan				&rpkts, &xwait);
1126e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1127e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* Adjust counters for any resets done. */
1128443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	swords -= dev->z_port_xmit_data;
1129443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	rwords -= dev->z_port_rcv_data;
1130443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	spkts -= dev->z_port_xmit_packets;
1131443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan	rpkts -= dev->z_port_rcv_packets;
1132e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1133e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	memset(pmp->data, 0, sizeof(pmp->data));
1134e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1135e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_select = port_select;
11366aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	if (pmp->mad_hdr.attr_mod != 0 ||
1137e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	    (port_select != port && port_select != 0xFF))
11386aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz		pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
1139e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1140e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_xmit_data = cpu_to_be64(swords);
1141e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_rcv_data = cpu_to_be64(rwords);
1142e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_xmit_packets = cpu_to_be64(spkts);
1143e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_rcv_packets = cpu_to_be64(rpkts);
1144e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_unicast_xmit_packets = cpu_to_be64(dev->n_unicast_xmit);
1145e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_unicast_rcv_packets = cpu_to_be64(dev->n_unicast_rcv);
1146e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_multicast_xmit_packets = cpu_to_be64(dev->n_multicast_xmit);
1147e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	p->port_multicast_rcv_packets = cpu_to_be64(dev->n_multicast_rcv);
1148e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1149e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return reply((struct ib_smp *) pmp);
1150e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
1151e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
11526aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitzstatic int recv_pma_set_portcounters(struct ib_pma_mad *pmp,
1153e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				     struct ib_device *ibdev, u8 port)
1154e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
1155e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
1156e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		pmp->data;
1157e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev = to_idev(ibdev);
115834b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	struct ipath_verbs_counters cntrs;
1159e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1160e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/*
1161e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * Since the HW doesn't support clearing counters, we save the
1162e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * current count and subtract it from future responses.
1163e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 */
116434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	ipath_get_counters(dev->dd, &cntrs);
1165e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1166e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_SYMBOL_ERROR)
1167443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_symbol_error_counter = cntrs.symbol_error_counter;
1168e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1169e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_LINK_ERROR_RECOVERY)
1170443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_link_error_recovery_counter =
1171e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			cntrs.link_error_recovery_counter;
1172e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1173e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_LINK_DOWNED)
1174443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_link_downed_counter = cntrs.link_downed_counter;
1175e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1176e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_PORT_RCV_ERRORS)
1177443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_rcv_errors =
1178e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			cntrs.port_rcv_errors + dev->rcv_errors;
1179e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1180e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS)
1181443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_rcv_remphys_errors =
1182e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			cntrs.port_rcv_remphys_errors;
1183e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1184e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DISCARDS)
1185443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_xmit_discards = cntrs.port_xmit_discards;
1186e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1187fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_LOCAL_LINK_INTEGRITY_ERRORS)
1188fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan		dev->z_local_link_integrity_errors =
1189fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan			cntrs.local_link_integrity_errors;
1190fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan
1191fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_EXCESSIVE_BUFFER_OVERRUNS)
1192fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan		dev->z_excessive_buffer_overrun_errors =
1193fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan			cntrs.excessive_buffer_overrun_errors;
1194fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan
11956c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) {
1196fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan		dev->n_vl15_dropped = 0;
11976c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell		dev->z_vl15_dropped = cntrs.vl15_dropped;
11986c719cae0b91f577738dfb4007baee28f03e48a5Ralph Campbell	}
1199fba75200ad92892bf32d8d6f1443c6f1e4f48676Bryan O'Sullivan
1200e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA)
1201443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_xmit_data = cntrs.port_xmit_data;
1202e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1203e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_PORT_RCV_DATA)
1204443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_rcv_data = cntrs.port_rcv_data;
1205e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1206e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_PORT_XMIT_PACKETS)
1207443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_xmit_packets = cntrs.port_xmit_packets;
1208e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1209e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SEL_PORT_RCV_PACKETS)
1210443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_rcv_packets = cntrs.port_rcv_packets;
1211e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1212e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return recv_pma_get_portcounters(pmp, ibdev, port);
1213e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
1214e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
12156aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitzstatic int recv_pma_set_portcounters_ext(struct ib_pma_mad *pmp,
1216e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan					 struct ib_device *ibdev, u8 port)
1217e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
1218e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
1219e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		pmp->data;
1220e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev = to_idev(ibdev);
1221e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	u64 swords, rwords, spkts, rpkts, xwait;
1222e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
122334b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan	ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
122434b2aafea38efdf02cd8107a6e1057e2a297c447Bryan O'Sullivan				&rpkts, &xwait);
1225e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1226e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SELX_PORT_XMIT_DATA)
1227443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_xmit_data = swords;
1228e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1229e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SELX_PORT_RCV_DATA)
1230443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_rcv_data = rwords;
1231e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1232e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SELX_PORT_XMIT_PACKETS)
1233443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_xmit_packets = spkts;
1234e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1235e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SELX_PORT_RCV_PACKETS)
1236443a64abbcb130caa315eb1110d7146365846235Bryan O'Sullivan		dev->z_port_rcv_packets = rpkts;
1237e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1238e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SELX_PORT_UNI_XMIT_PACKETS)
1239e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		dev->n_unicast_xmit = 0;
1240e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1241e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SELX_PORT_UNI_RCV_PACKETS)
1242e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		dev->n_unicast_rcv = 0;
1243e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1244e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS)
1245e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		dev->n_multicast_xmit = 0;
1246e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1247e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (p->counter_select & IB_PMA_SELX_PORT_MULTI_RCV_PACKETS)
1248e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		dev->n_multicast_rcv = 0;
1249e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1250e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return recv_pma_get_portcounters_ext(pmp, ibdev, port);
1251e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
1252e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1253e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int process_subn(struct ib_device *ibdev, int mad_flags,
1254e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			u8 port_num, struct ib_mad *in_mad,
1255e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			struct ib_mad *out_mad)
1256e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
1257e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ib_smp *smp = (struct ib_smp *)out_mad;
1258e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	struct ipath_ibdev *dev = to_idev(ibdev);
1259e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	int ret;
1260e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1261e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	*out_mad = *in_mad;
1262e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if (smp->class_version != 1) {
1263e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		smp->status |= IB_SMP_UNSUP_VERSION;
1264e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = reply(smp);
1265e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto bail;
1266e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
1267e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1268e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/* Is the mkey in the process of expiring? */
1269b3b8128fd3b0966830ee90f1162173d07cb496a0Robert P. J. Day	if (dev->mkey_lease_timeout &&
1270b3b8128fd3b0966830ee90f1162173d07cb496a0Robert P. J. Day	    time_after_eq(jiffies, dev->mkey_lease_timeout)) {
1271e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		/* Clear timeout and mkey protection field. */
1272e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		dev->mkey_lease_timeout = 0;
1273542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell		dev->mkeyprot = 0;
1274e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
1275e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1276e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	/*
1277e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * M_Key checking depends on
1278e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 * Portinfo:M_Key_protect_bits
1279e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	 */
1280e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	if ((mad_flags & IB_MAD_IGNORE_MKEY) == 0 && dev->mkey != 0 &&
1281e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	    dev->mkey != smp->mkey &&
1282e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	    (smp->method == IB_MGMT_METHOD_SET ||
1283e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	     (smp->method == IB_MGMT_METHOD_GET &&
1284542869a17eee2edf389273f40f757aa4e662b3daRalph Campbell	      dev->mkeyprot >= 2))) {
1285e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		if (dev->mkey_violations != 0xFFFF)
1286e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			++dev->mkey_violations;
1287e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		if (dev->mkey_lease_timeout ||
1288e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		    dev->mkey_lease_period == 0) {
1289e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = IB_MAD_RESULT_SUCCESS |
1290e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				IB_MAD_RESULT_CONSUMED;
1291e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1292e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		}
1293e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		dev->mkey_lease_timeout = jiffies +
1294e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			dev->mkey_lease_period * HZ;
1295e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		/* Future: Generate a trap notice. */
1296e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
1297e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto bail;
1298e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	} else if (dev->mkey_lease_timeout)
1299e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		dev->mkey_lease_timeout = 0;
1300e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1301e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	switch (smp->method) {
1302e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MGMT_METHOD_GET:
1303e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		switch (smp->attr_id) {
1304e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_SMP_ATTR_NODE_DESC:
1305e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_subn_get_nodedescription(smp, ibdev);
1306e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1307e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_SMP_ATTR_NODE_INFO:
1308e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_subn_get_nodeinfo(smp, ibdev, port_num);
1309e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1310e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_SMP_ATTR_GUID_INFO:
1311e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_subn_get_guidinfo(smp, ibdev);
1312e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1313e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_SMP_ATTR_PORT_INFO:
1314e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_subn_get_portinfo(smp, ibdev, port_num);
1315e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1316e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_SMP_ATTR_PKEY_TABLE:
1317e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_subn_get_pkeytable(smp, ibdev);
1318e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1319e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_SMP_ATTR_SM_INFO:
1320e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			if (dev->port_cap_flags & IB_PORT_SM_DISABLED) {
1321e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				ret = IB_MAD_RESULT_SUCCESS |
1322e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan					IB_MAD_RESULT_CONSUMED;
1323e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				goto bail;
1324e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			}
1325e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			if (dev->port_cap_flags & IB_PORT_SM) {
1326e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				ret = IB_MAD_RESULT_SUCCESS;
1327e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				goto bail;
1328e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			}
1329e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			/* FALLTHROUGH */
1330e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		default:
1331e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			smp->status |= IB_SMP_UNSUP_METH_ATTR;
1332e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = reply(smp);
1333e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1334e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		}
1335e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1336e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MGMT_METHOD_SET:
1337e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		switch (smp->attr_id) {
1338e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_SMP_ATTR_GUID_INFO:
1339e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_subn_set_guidinfo(smp, ibdev);
1340e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1341e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_SMP_ATTR_PORT_INFO:
1342e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_subn_set_portinfo(smp, ibdev, port_num);
1343e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1344e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_SMP_ATTR_PKEY_TABLE:
1345e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_subn_set_pkeytable(smp, ibdev);
1346e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1347e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_SMP_ATTR_SM_INFO:
1348e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			if (dev->port_cap_flags & IB_PORT_SM_DISABLED) {
1349e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				ret = IB_MAD_RESULT_SUCCESS |
1350e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan					IB_MAD_RESULT_CONSUMED;
1351e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				goto bail;
1352e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			}
1353e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			if (dev->port_cap_flags & IB_PORT_SM) {
1354e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				ret = IB_MAD_RESULT_SUCCESS;
1355e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				goto bail;
1356e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			}
1357e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			/* FALLTHROUGH */
1358e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		default:
1359e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			smp->status |= IB_SMP_UNSUP_METH_ATTR;
1360e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = reply(smp);
1361e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1362e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		}
1363e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
136427676a3e166b352928a8ef7b1c0e322f3c471a3eRalph Campbell	case IB_MGMT_METHOD_TRAP:
136527676a3e166b352928a8ef7b1c0e322f3c471a3eRalph Campbell	case IB_MGMT_METHOD_REPORT:
136627676a3e166b352928a8ef7b1c0e322f3c471a3eRalph Campbell	case IB_MGMT_METHOD_REPORT_RESP:
136727676a3e166b352928a8ef7b1c0e322f3c471a3eRalph Campbell	case IB_MGMT_METHOD_TRAP_REPRESS:
1368e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MGMT_METHOD_GET_RESP:
1369e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		/*
1370e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		 * The ib_mad module will call us to process responses
1371e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		 * before checking for other consumers.
1372e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		 * Just tell the caller to process it normally.
1373e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		 */
1374f9b403532235520ec248c024f621efcaf6ba7b93Ralph Campbell		ret = IB_MAD_RESULT_SUCCESS;
1375e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto bail;
1376e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	default:
1377e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		smp->status |= IB_SMP_UNSUP_METHOD;
1378e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = reply(smp);
1379e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
1380e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1381e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanbail:
1382e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return ret;
1383e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
1384e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1385e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanstatic int process_perf(struct ib_device *ibdev, u8 port_num,
1386e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			struct ib_mad *in_mad,
1387e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			struct ib_mad *out_mad)
1388e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
13896aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	struct ib_pma_mad *pmp = (struct ib_pma_mad *)out_mad;
1390e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	int ret;
1391e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1392e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	*out_mad = *in_mad;
13936aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	if (pmp->mad_hdr.class_version != 1) {
13946aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz		pmp->mad_hdr.status |= IB_SMP_UNSUP_VERSION;
1395e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = reply((struct ib_smp *) pmp);
1396e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto bail;
1397e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
1398e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
13996aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz	switch (pmp->mad_hdr.method) {
1400e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MGMT_METHOD_GET:
14016aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz		switch (pmp->mad_hdr.attr_id) {
1402e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_PMA_CLASS_PORT_INFO:
1403e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_pma_get_classportinfo(pmp);
1404e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1405e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_PMA_PORT_SAMPLES_CONTROL:
1406e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_pma_get_portsamplescontrol(pmp, ibdev,
1407e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan							      port_num);
1408e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1409e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_PMA_PORT_SAMPLES_RESULT:
1410e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_pma_get_portsamplesresult(pmp, ibdev);
1411e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1412e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_PMA_PORT_SAMPLES_RESULT_EXT:
1413e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_pma_get_portsamplesresult_ext(pmp,
1414e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan								 ibdev);
1415e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1416e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_PMA_PORT_COUNTERS:
1417e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_pma_get_portcounters(pmp, ibdev,
1418e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan							port_num);
1419e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1420e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_PMA_PORT_COUNTERS_EXT:
1421e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_pma_get_portcounters_ext(pmp, ibdev,
1422e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan							    port_num);
1423e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1424e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		default:
14256aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz			pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR;
1426e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = reply((struct ib_smp *) pmp);
1427e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1428e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		}
1429e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1430e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MGMT_METHOD_SET:
14316aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz		switch (pmp->mad_hdr.attr_id) {
1432e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_PMA_PORT_SAMPLES_CONTROL:
1433e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_pma_set_portsamplescontrol(pmp, ibdev,
1434e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan							      port_num);
1435e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1436e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_PMA_PORT_COUNTERS:
1437e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_pma_set_portcounters(pmp, ibdev,
1438e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan							port_num);
1439e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1440e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		case IB_PMA_PORT_COUNTERS_EXT:
1441e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = recv_pma_set_portcounters_ext(pmp, ibdev,
1442e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan							    port_num);
1443e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1444e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		default:
14456aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz			pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR;
1446e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			ret = reply((struct ib_smp *) pmp);
1447e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan			goto bail;
1448e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		}
1449e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1450e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MGMT_METHOD_GET_RESP:
1451e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		/*
1452e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		 * The ib_mad module will call us to process responses
1453e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		 * before checking for other consumers.
1454e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		 * Just tell the caller to process it normally.
1455e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		 */
1456f9b403532235520ec248c024f621efcaf6ba7b93Ralph Campbell		ret = IB_MAD_RESULT_SUCCESS;
1457e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto bail;
1458e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	default:
14596aea213a62122701891fe55cc3405d31b927cfdeOr Gerlitz		pmp->mad_hdr.status |= IB_SMP_UNSUP_METHOD;
1460e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = reply((struct ib_smp *) pmp);
1461e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
1462e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1463e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanbail:
1464e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return ret;
1465e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
1466e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1467e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan/**
1468e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * ipath_process_mad - process an incoming MAD packet
1469e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * @ibdev: the infiniband device this packet came in on
1470e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * @mad_flags: MAD flags
1471e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * @port_num: the port number this packet came in on
1472e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * @in_wc: the work completion entry for this packet
1473e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * @in_grh: the global route header for this packet
1474e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * @in_mad: the incoming MAD
1475e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * @out_mad: any outgoing MAD reply
1476e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *
1477e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * Returns IB_MAD_RESULT_SUCCESS if this is a MAD that we are not
1478e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * interested in processing.
1479e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *
1480e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * Note that the verbs framework has already done the MAD sanity checks,
1481e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * and hop count/pointer updating for IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE
1482e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * MADs.
1483e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan *
1484e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan * This is called by the ib_mad module.
1485e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan */
1486e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanint ipath_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
1487e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		      struct ib_wc *in_wc, struct ib_grh *in_grh,
1488e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		      struct ib_mad *in_mad, struct ib_mad *out_mad)
1489e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan{
1490e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	int ret;
1491e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1492e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	switch (in_mad->mad_hdr.mgmt_class) {
1493e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
1494e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MGMT_CLASS_SUBN_LID_ROUTED:
1495e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = process_subn(ibdev, mad_flags, port_num,
1496e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan				   in_mad, out_mad);
1497e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto bail;
1498e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	case IB_MGMT_CLASS_PERF_MGMT:
1499e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = process_perf(ibdev, port_num, in_mad, out_mad);
1500e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		goto bail;
1501e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	default:
1502e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan		ret = IB_MAD_RESULT_SUCCESS;
1503e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	}
1504e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan
1505e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivanbail:
1506e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan	return ret;
1507e28c00ad67164dba688c1d19c208c5fb554465f2Bryan O'Sullivan}
1508