11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
32a1d9b7f09aaaacf235656cb32a40ba2c79590b3Roland Dreier * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
42a1d9b7f09aaaacf235656cb32a40ba2c79590b3Roland Dreier * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software is available to you under a choice of one of two
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * licenses.  You may choose to be licensed under the terms of the GNU
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General Public License (GPL) Version 2, available from the file
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * COPYING in the main directory of this source tree, or the
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OpenIB.org BSD license below:
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Redistribution and use in source and binary forms, with or
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     without modification, are permitted provided that the following
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     conditions are met:
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      - Redistributions of source code must retain the above
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        copyright notice, this list of conditions and the following
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        disclaimer.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      - Redistributions in binary form must reproduce the above
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        copyright notice, this list of conditions and the following
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        disclaimer in the documentation and/or other materials
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        provided with the distribution.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SOFTWARE.
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "core_priv.h"
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
378c65b4a60450590e79a28e9717ceffa9e4debb3fTim Schmielau#include <linux/slab.h>
38fc87af74af7f856bb8e7585308fb1fdaaa69ec73Paul Gortmaker#include <linux/stat.h>
398c65b4a60450590e79a28e9717ceffa9e4debb3fTim Schmielau#include <linux/string.h>
408c65b4a60450590e79a28e9717ceffa9e4debb3fTim Schmielau
41a4d61e84804f3b14cc35c5e2af768a07c0f64ef6Roland Dreier#include <rdma/ib_mad.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ib_port {
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kobject         kobj;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_device      *ibdev;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct attribute_group gid_group;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct attribute_group pkey_group;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8                     port_num;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct port_attribute {
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct attribute attr;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t (*show)(struct ib_port *, struct port_attribute *, char *buf);
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t (*store)(struct ib_port *, struct port_attribute *,
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 const char *buf, size_t count);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_ATTR(_name, _mode, _show, _store) \
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct port_attribute port_attr_##_name = __ATTR(_name, _mode, _show, _store)
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_ATTR_RO(_name) \
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct port_attribute port_attr_##_name = __ATTR_RO(_name)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct port_table_attribute {
65d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	struct port_attribute	attr;
66d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	char			name[8];
67d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	int			index;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t port_attr_show(struct kobject *kobj,
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct attribute *attr, char *buf)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct port_attribute *port_attr =
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		container_of(attr, struct port_attribute, attr);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port *p = container_of(kobj, struct ib_port, kobj);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!port_attr->show)
7870f2817a43c89b784dc2ec3d06ba5bf3064f8235Dmitry Torokhov		return -EIO;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return port_attr->show(p, port_attr, buf);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8352cf25d0ab7f78eeecc59ac652ed5090f69b619eEmese Revfystatic const struct sysfs_ops port_sysfs_ops = {
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show = port_attr_show
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t state_show(struct ib_port *p, struct port_attribute *unused,
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  char *buf)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port_attr attr;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static const char *state_name[] = {
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		[IB_PORT_NOP]		= "NOP",
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		[IB_PORT_DOWN]		= "DOWN",
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		[IB_PORT_INIT]		= "INIT",
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		[IB_PORT_ARMED]		= "ARMED",
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		[IB_PORT_ACTIVE]	= "ACTIVE",
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		[IB_PORT_ACTIVE_DEFER]	= "ACTIVE_DEFER"
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_port(p->ibdev, p->port_num, &attr);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d: %s\n", attr.state,
107048975ac580a771fc5bb96c6b454cba897ab1a73Roland Dreier		       attr.state >= 0 && attr.state < ARRAY_SIZE(state_name) ?
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       state_name[attr.state] : "UNKNOWN");
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t lid_show(struct ib_port *p, struct port_attribute *unused,
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			char *buf)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port_attr attr;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_port(p->ibdev, p->port_num, &attr);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "0x%x\n", attr.lid);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t lid_mask_count_show(struct ib_port *p,
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   struct port_attribute *unused,
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   char *buf)
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port_attr attr;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_port(p->ibdev, p->port_num, &attr);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", attr.lmc);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t sm_lid_show(struct ib_port *p, struct port_attribute *unused,
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   char *buf)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port_attr attr;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_port(p->ibdev, p->port_num, &attr);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "0x%x\n", attr.sm_lid);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t sm_sl_show(struct ib_port *p, struct port_attribute *unused,
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  char *buf)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port_attr attr;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_port(p->ibdev, p->port_num, &attr);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", attr.sm_sl);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t cap_mask_show(struct ib_port *p, struct port_attribute *unused,
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     char *buf)
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port_attr attr;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_port(p->ibdev, p->port_num, &attr);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "0x%08x\n", attr.port_cap_flags);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t rate_show(struct ib_port *p, struct port_attribute *unused,
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 char *buf)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port_attr attr;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *speed = "";
1820559d8dc13a1cd68b5e64c0b61659f36c7b5c89fRoland Dreier	int rate;		/* in deci-Gb/sec */
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_port(p->ibdev, p->port_num, &attr);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (attr.active_speed) {
1902e96691c31ecf749f48aa94ea837b95dd656f5c2Or Gerlitz	case IB_SPEED_DDR:
19171eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum		speed = " DDR";
192e9319b0cb00d4d68792fdae37e81e316cb632cb9Roland Dreier		rate = 50;
19371eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum		break;
1942e96691c31ecf749f48aa94ea837b95dd656f5c2Or Gerlitz	case IB_SPEED_QDR:
19571eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum		speed = " QDR";
196e9319b0cb00d4d68792fdae37e81e316cb632cb9Roland Dreier		rate = 100;
19771eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum		break;
1982e96691c31ecf749f48aa94ea837b95dd656f5c2Or Gerlitz	case IB_SPEED_FDR10:
19971eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum		speed = " FDR10";
200e9319b0cb00d4d68792fdae37e81e316cb632cb9Roland Dreier		rate = 100;
20171eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum		break;
2022e96691c31ecf749f48aa94ea837b95dd656f5c2Or Gerlitz	case IB_SPEED_FDR:
20371eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum		speed = " FDR";
204e9319b0cb00d4d68792fdae37e81e316cb632cb9Roland Dreier		rate = 140;
20571eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum		break;
2062e96691c31ecf749f48aa94ea837b95dd656f5c2Or Gerlitz	case IB_SPEED_EDR:
20771eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum		speed = " EDR";
208e9319b0cb00d4d68792fdae37e81e316cb632cb9Roland Dreier		rate = 250;
20971eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum		break;
2100559d8dc13a1cd68b5e64c0b61659f36c7b5c89fRoland Dreier	case IB_SPEED_SDR:
2110559d8dc13a1cd68b5e64c0b61659f36c7b5c89fRoland Dreier	default:		/* default to SDR for invalid rates */
2120559d8dc13a1cd68b5e64c0b61659f36c7b5c89fRoland Dreier		rate = 25;
2130559d8dc13a1cd68b5e64c0b61659f36c7b5c89fRoland Dreier		break;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21671eeba161d7611238ecb6f525a82325aa35339f0Marcel Apfelbaum	rate *= ib_width_enum_to_int(attr.active_width);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rate < 0)
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d%s Gb/sec (%dX%s)\n",
221e9319b0cb00d4d68792fdae37e81e316cb632cb9Roland Dreier		       rate / 10, rate % 10 ? ".5" : "",
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ib_width_enum_to_int(attr.active_width), speed);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t phys_state_show(struct ib_port *p, struct port_attribute *unused,
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       char *buf)
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port_attr attr;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_port(p->ibdev, p->port_num, &attr);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (attr.phys_state) {
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:  return sprintf(buf, "1: Sleep\n");
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:  return sprintf(buf, "2: Polling\n");
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:  return sprintf(buf, "3: Disabled\n");
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4:  return sprintf(buf, "4: PortConfigurationTraining\n");
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 5:  return sprintf(buf, "5: LinkUp\n");
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 6:  return sprintf(buf, "6: LinkErrorRecovery\n");
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 7:  return sprintf(buf, "7: Phy Test\n");
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default: return sprintf(buf, "%d: <unknown>\n", attr.phys_state);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2488ad330a002ffbc422f32a77398666832f0df8a3dEli Cohenstatic ssize_t link_layer_show(struct ib_port *p, struct port_attribute *unused,
2498ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen			       char *buf)
2508ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen{
2518ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen	switch (rdma_port_get_link_layer(p->ibdev, p->port_num)) {
2528ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen	case IB_LINK_LAYER_INFINIBAND:
2538ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen		return sprintf(buf, "%s\n", "InfiniBand");
2548ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen	case IB_LINK_LAYER_ETHERNET:
2558ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen		return sprintf(buf, "%s\n", "Ethernet");
2568ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen	default:
2578ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen		return sprintf(buf, "%s\n", "Unknown");
2588ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen	}
2598ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen}
2608ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_ATTR_RO(state);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_ATTR_RO(lid);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_ATTR_RO(lid_mask_count);
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_ATTR_RO(sm_lid);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_ATTR_RO(sm_sl);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_ATTR_RO(cap_mask);
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_ATTR_RO(rate);
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_ATTR_RO(phys_state);
2698ad330a002ffbc422f32a77398666832f0df8a3dEli Cohenstatic PORT_ATTR_RO(link_layer);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct attribute *port_default_attrs[] = {
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_attr_state.attr,
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_attr_lid.attr,
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_attr_lid_mask_count.attr,
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_attr_sm_lid.attr,
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_attr_sm_sl.attr,
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_attr_cap_mask.attr,
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_attr_rate.attr,
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_attr_phys_state.attr,
2808ad330a002ffbc422f32a77398666832f0df8a3dEli Cohen	&port_attr_link_layer.attr,
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NULL
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr,
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     char *buf)
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct port_table_attribute *tab_attr =
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		container_of(attr, struct port_table_attribute, attr);
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union ib_gid gid;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_gid(p->ibdev, p->port_num, tab_attr->index, &gid);
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2965b095d98928fdb9e3b75be20a54b7a6cbf6ca9adHarvey Harrison	return sprintf(buf, "%pI6\n", gid.raw);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_port_pkey(struct ib_port *p, struct port_attribute *attr,
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      char *buf)
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct port_table_attribute *tab_attr =
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		container_of(attr, struct port_table_attribute, attr);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 pkey;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_pkey(p->ibdev, p->port_num, tab_attr->index, &pkey);
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "0x%04x\n", pkey);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_PMA_ATTR(_name, _counter, _width, _offset)			\
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct port_table_attribute port_pma_attr_##_name = {			\
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attr  = __ATTR(_name, S_IRUGO, show_pma_counter, NULL),	\
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.index = (_offset) | ((_width) << 16) | ((_counter) << 24)	\
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr,
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				char *buf)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct port_table_attribute *tab_attr =
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		container_of(attr, struct port_table_attribute, attr);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int offset = tab_attr->index & 0xffff;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int width  = (tab_attr->index >> 16) & 0xff;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_mad *in_mad  = NULL;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_mad *out_mad = NULL;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!p->ibdev->process_mad)
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sprintf(buf, "N/A (no PMA)\n");
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
334de6eb66b56d9df5ce6bd254994f05e065214e8cdRoland Dreier	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
335856c52a741950dc0be2c5c231efec626e9a0a3faDotan Barak	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!in_mad || !out_mad) {
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_mad->mad_hdr.base_version  = 1;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_mad->mad_hdr.mgmt_class    = IB_MGMT_CLASS_PERF_MGMT;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_mad->mad_hdr.class_version = 1;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_mad->mad_hdr.method        = IB_MGMT_METHOD_GET;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_mad->mad_hdr.attr_id       = cpu_to_be16(0x12); /* PortCounters */
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_mad->data[41] = p->port_num;	/* PortSelect field */
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((p->ibdev->process_mad(p->ibdev, IB_MAD_IGNORE_MKEY,
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 p->port_num, NULL, NULL, in_mad, out_mad) &
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) !=
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) {
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EINVAL;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (width) {
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4:
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = sprintf(buf, "%u\n", (out_mad->data[40 + offset / 8] >>
360d8b9f23b23e080d820e3c0aa5ccd7834c26ebf96Ralph Campbell					    (4 - (offset % 8))) & 0xf);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 8:
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = sprintf(buf, "%u\n", out_mad->data[40 + offset / 8]);
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 16:
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = sprintf(buf, "%u\n",
36797f52eb438be7caebe026421545619d8a0c1398aSean Hefty			      be16_to_cpup((__be16 *)(out_mad->data + 40 + offset / 8)));
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 32:
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = sprintf(buf, "%u\n",
37197f52eb438be7caebe026421545619d8a0c1398aSean Hefty			      be32_to_cpup((__be32 *)(out_mad->data + 40 + offset / 8)));
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(in_mad);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(out_mad);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(symbol_error		    ,  0, 16,  32);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(link_error_recovery	    ,  1,  8,  48);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(link_downed		    ,  2,  8,  56);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(port_rcv_errors		    ,  3, 16,  64);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(port_rcv_remote_physical_errors,  4, 16,  80);
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(port_rcv_switch_relay_errors   ,  5, 16,  96);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(port_xmit_discards		    ,  6, 16, 112);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(port_xmit_constraint_errors    ,  7,  8, 128);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(port_rcv_constraint_errors	    ,  8,  8, 136);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(local_link_integrity_errors    ,  9,  4, 152);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(excessive_buffer_overrun_errors, 10,  4, 156);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(VL15_dropped		    , 11, 16, 176);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(port_xmit_data		    , 12, 32, 192);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(port_rcv_data		    , 13, 32, 224);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(port_xmit_packets		    , 14, 32, 256);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic PORT_PMA_ATTR(port_rcv_packets		    , 15, 32, 288);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct attribute *pma_attrs[] = {
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_symbol_error.attr.attr,
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_link_error_recovery.attr.attr,
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_link_downed.attr.attr,
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_port_rcv_errors.attr.attr,
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_port_rcv_remote_physical_errors.attr.attr,
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_port_rcv_switch_relay_errors.attr.attr,
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_port_xmit_discards.attr.attr,
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_port_xmit_constraint_errors.attr.attr,
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_port_rcv_constraint_errors.attr.attr,
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_local_link_integrity_errors.attr.attr,
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_excessive_buffer_overrun_errors.attr.attr,
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_VL15_dropped.attr.attr,
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_port_xmit_data.attr.attr,
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_port_rcv_data.attr.attr,
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_port_xmit_packets.attr.attr,
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&port_pma_attr_port_rcv_packets.attr.attr,
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NULL
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct attribute_group pma_group = {
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name  = "counters",
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attrs  = pma_attrs
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ib_port_release(struct kobject *kobj)
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port *p = container_of(kobj, struct ib_port, kobj);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct attribute *a;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
432d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	for (i = 0; (a = p->gid_group.attrs[i]); ++i)
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(a);
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
435d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	kfree(p->gid_group.attrs);
436d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov
437d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	for (i = 0; (a = p->pkey_group.attrs[i]); ++i)
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(a);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
440d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	kfree(p->pkey_group.attrs);
441d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(p);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct kobj_type port_type = {
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release       = ib_port_release,
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sysfs_ops     = &port_sysfs_ops,
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.default_attrs = port_default_attrs
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic void ib_device_release(struct device *device)
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
453f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	struct ib_device *dev = container_of(device, struct ib_device, dev);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(dev);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
458f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic int ib_device_uevent(struct device *device,
4597eff2e7a8b65c25920207324e56611150eb1cd9aKay Sievers			    struct kobj_uevent_env *env)
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
461f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	struct ib_device *dev = container_of(device, struct ib_device, dev);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4637eff2e7a8b65c25920207324e56611150eb1cd9aKay Sievers	if (add_uevent_var(env, "NAME=%s", dev->name))
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
467cf311cd49a78f1e431787068cc31d29d06a415e6Sean Hefty	 * It would be nice to pass the node GUID with the event...
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
473d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhovstatic struct attribute **
474d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhovalloc_group_attrs(ssize_t (*show)(struct ib_port *,
475d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov				  struct port_attribute *, char *buf),
476d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		  int len)
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
478d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	struct attribute **tab_attr;
479d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	struct port_table_attribute *element;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
482d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	tab_attr = kcalloc(1 + len, sizeof(struct attribute *), GFP_KERNEL);
483d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	if (!tab_attr)
484d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		return NULL;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
486d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	for (i = 0; i < len; i++) {
48782ca76b6b160b6fce46f78c069f87fe1a4dc0778Pekka Enberg		element = kzalloc(sizeof(struct port_table_attribute),
488d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov				  GFP_KERNEL);
489d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		if (!element)
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
492d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		if (snprintf(element->name, sizeof(element->name),
493048975ac580a771fc5bb96c6b454cba897ab1a73Roland Dreier			     "%d", i) >= sizeof(element->name)) {
494048975ac580a771fc5bb96c6b454cba897ab1a73Roland Dreier			kfree(element);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err;
496048975ac580a771fc5bb96c6b454cba897ab1a73Roland Dreier		}
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
498d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		element->attr.attr.name  = element->name;
499d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		element->attr.attr.mode  = S_IRUGO;
500d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		element->attr.show       = show;
501d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		element->index		 = i;
50221e3bde964e873bb5d3b1dfef68294b1437fe678Greg Kroah-Hartman		sysfs_attr_init(&element->attr.attr);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
504d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		tab_attr[i] = &element->attr.attr;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
507d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	return tab_attr;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
509d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhoverr:
510d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	while (--i >= 0)
511d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		kfree(tab_attr[i]);
512d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	kfree(tab_attr);
513d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	return NULL;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5169a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbellstatic int add_port(struct ib_device *device, int port_num,
5179a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell		    int (*port_callback)(struct ib_device *,
5189a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell					 u8, struct kobject *))
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port *p;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port_attr attr;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_port(device, port_num, &attr);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
529de6eb66b56d9df5ce6bd254994f05e065214e8cdRoland Dreier	p = kzalloc(sizeof *p, GFP_KERNEL);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!p)
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->ibdev      = device;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->port_num   = port_num;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53635be0681983752116a8161ad3b30e830963108a4Greg Kroah-Hartman	ret = kobject_init_and_add(&p->kobj, &port_type,
53735be0681983752116a8161ad3b30e830963108a4Greg Kroah-Hartman				   kobject_get(device->ports_parent),
53835be0681983752116a8161ad3b30e830963108a4Greg Kroah-Hartman				   "%d", port_num);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_put;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = sysfs_create_group(&p->kobj, &pma_group);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_put;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->gid_group.name  = "gids";
547d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	p->gid_group.attrs = alloc_group_attrs(show_port_gid, attr.gid_tbl_len);
548d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	if (!p->gid_group.attrs)
549d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		goto err_remove_pma;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = sysfs_create_group(&p->kobj, &p->gid_group);
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_free_gid;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->pkey_group.name  = "pkeys";
556d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	p->pkey_group.attrs = alloc_group_attrs(show_port_pkey,
557d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov						attr.pkey_tbl_len);
558d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	if (!p->pkey_group.attrs)
559d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		goto err_remove_gid;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = sysfs_create_group(&p->kobj, &p->pkey_group);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_free_pkey;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5659a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell	if (port_callback) {
5669a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell		ret = port_callback(device, port_num, &p->kobj);
5679a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell		if (ret)
5689a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell			goto err_remove_pkey;
5699a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell	}
5709a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail(&p->kobj.entry, &device->port_list);
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
57335be0681983752116a8161ad3b30e830963108a4Greg Kroah-Hartman	kobject_uevent(&p->kobj, KOBJ_ADD);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5769a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbellerr_remove_pkey:
5779a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell	sysfs_remove_group(&p->kobj, &p->pkey_group);
5789a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_free_pkey:
580d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	for (i = 0; i < attr.pkey_tbl_len; ++i)
581d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		kfree(p->pkey_group.attrs[i]);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
583d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	kfree(p->pkey_group.attrs);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_remove_gid:
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sysfs_remove_group(&p->kobj, &p->gid_group);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_free_gid:
589d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	for (i = 0; i < attr.gid_tbl_len; ++i)
590d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov		kfree(p->gid_group.attrs[i]);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
592d48593bf208e0d046c35fb0707ae5b23fef8c4ffDmitry Torokhov	kfree(p->gid_group.attrs);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_remove_pma:
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sysfs_remove_group(&p->kobj, &pma_group);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_put:
59835be0681983752116a8161ad3b30e830963108a4Greg Kroah-Hartman	kobject_put(device->ports_parent);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(p);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
603f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic ssize_t show_node_type(struct device *device,
604f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones			      struct device_attribute *attr, char *buf)
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
606f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	struct ib_device *dev = container_of(device, struct ib_device, dev);
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dev->node_type) {
60907ebafbaaa72aa6a35472879008f5a1d1d469a0cTom Tucker	case RDMA_NODE_IB_CA:	  return sprintf(buf, "%d: CA\n", dev->node_type);
61007ebafbaaa72aa6a35472879008f5a1d1d469a0cTom Tucker	case RDMA_NODE_RNIC:	  return sprintf(buf, "%d: RNIC\n", dev->node_type);
61107ebafbaaa72aa6a35472879008f5a1d1d469a0cTom Tucker	case RDMA_NODE_IB_SWITCH: return sprintf(buf, "%d: switch\n", dev->node_type);
61207ebafbaaa72aa6a35472879008f5a1d1d469a0cTom Tucker	case RDMA_NODE_IB_ROUTER: return sprintf(buf, "%d: router\n", dev->node_type);
61307ebafbaaa72aa6a35472879008f5a1d1d469a0cTom Tucker	default:		  return sprintf(buf, "%d: <unknown>\n", dev->node_type);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
617f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic ssize_t show_sys_image_guid(struct device *device,
618f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones				   struct device_attribute *dev_attr, char *buf)
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
620f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	struct ib_device *dev = container_of(device, struct ib_device, dev);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_device_attr attr;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = ib_query_device(dev, &attr);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%04x:%04x:%04x:%04x\n",
62997f52eb438be7caebe026421545619d8a0c1398aSean Hefty		       be16_to_cpu(((__be16 *) &attr.sys_image_guid)[0]),
63097f52eb438be7caebe026421545619d8a0c1398aSean Hefty		       be16_to_cpu(((__be16 *) &attr.sys_image_guid)[1]),
63197f52eb438be7caebe026421545619d8a0c1398aSean Hefty		       be16_to_cpu(((__be16 *) &attr.sys_image_guid)[2]),
63297f52eb438be7caebe026421545619d8a0c1398aSean Hefty		       be16_to_cpu(((__be16 *) &attr.sys_image_guid)[3]));
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
635f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic ssize_t show_node_guid(struct device *device,
636f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones			      struct device_attribute *attr, char *buf)
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
638f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	struct ib_device *dev = container_of(device, struct ib_device, dev);
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%04x:%04x:%04x:%04x\n",
641cf311cd49a78f1e431787068cc31d29d06a415e6Sean Hefty		       be16_to_cpu(((__be16 *) &dev->node_guid)[0]),
642cf311cd49a78f1e431787068cc31d29d06a415e6Sean Hefty		       be16_to_cpu(((__be16 *) &dev->node_guid)[1]),
643cf311cd49a78f1e431787068cc31d29d06a415e6Sean Hefty		       be16_to_cpu(((__be16 *) &dev->node_guid)[2]),
644cf311cd49a78f1e431787068cc31d29d06a415e6Sean Hefty		       be16_to_cpu(((__be16 *) &dev->node_guid)[3]));
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
647f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic ssize_t show_node_desc(struct device *device,
648f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones			      struct device_attribute *attr, char *buf)
649c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier{
650f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	struct ib_device *dev = container_of(device, struct ib_device, dev);
651c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier
652c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier	return sprintf(buf, "%.64s\n", dev->node_desc);
653c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier}
654c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier
655f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic ssize_t set_node_desc(struct device *device,
656f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones			     struct device_attribute *attr,
657f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones			     const char *buf, size_t count)
658c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier{
659f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	struct ib_device *dev = container_of(device, struct ib_device, dev);
660c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier	struct ib_device_modify desc = {};
661c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier	int ret;
662c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier
663c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier	if (!dev->modify_device)
664c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier		return -EIO;
665c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier
666c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier	memcpy(desc.node_desc, buf, min_t(int, count, 64));
667c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier	ret = ib_modify_device(dev, IB_DEVICE_MODIFY_NODE_DESC, &desc);
668c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier	if (ret)
669c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier		return ret;
670c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier
671c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier	return count;
672c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier}
673c5bcbbb9fe00128d500c2f473d5ddc8d8c2c53a7Roland Dreier
674f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL);
675f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic DEVICE_ATTR(sys_image_guid, S_IRUGO, show_sys_image_guid, NULL);
676f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic DEVICE_ATTR(node_guid, S_IRUGO, show_node_guid, NULL);
677f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic DEVICE_ATTR(node_desc, S_IRUGO | S_IWUSR, show_node_desc, set_node_desc);
678f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones
679f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jonesstatic struct device_attribute *ib_class_attributes[] = {
680f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	&dev_attr_node_type,
681f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	&dev_attr_sys_image_guid,
682f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	&dev_attr_node_guid,
683f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	&dev_attr_node_desc
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct class ib_class = {
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name    = "infiniband",
688f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	.dev_release = ib_device_release,
689f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	.dev_uevent = ib_device_uevent,
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6927f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise/* Show a given an attribute in the statistics group */
6937f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wisestatic ssize_t show_protocol_stat(const struct device *device,
6947f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise			    struct device_attribute *attr, char *buf,
6957f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise			    unsigned offset)
6967f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise{
6977f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	struct ib_device *dev = container_of(device, struct ib_device, dev);
6987f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	union rdma_protocol_stats stats;
6997f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	ssize_t ret;
7007f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise
7017f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	ret = dev->get_protocol_stats(dev, &stats);
7027f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	if (ret)
7037f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise		return ret;
7047f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise
7057f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	return sprintf(buf, "%llu\n",
7067f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise		       (unsigned long long) ((u64 *) &stats)[offset]);
7077f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise}
7087f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise
7097f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise/* generate a read-only iwarp statistics attribute */
7107f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise#define IW_STATS_ENTRY(name)						\
7117f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wisestatic ssize_t show_##name(struct device *device,			\
7127f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise			   struct device_attribute *attr, char *buf)	\
7137f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise{									\
7147f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	return show_protocol_stat(device, attr, buf,			\
7157f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise				  offsetof(struct iw_protocol_stats, name) / \
7167f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise				  sizeof (u64));			\
7177f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise}									\
7187f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wisestatic DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
7197f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise
7207f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInReceives);
7217f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInHdrErrors);
7227f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInTooBigErrors);
7237f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInNoRoutes);
7247f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInAddrErrors);
7257f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInUnknownProtos);
7267f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInTruncatedPkts);
7277f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInDiscards);
7287f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInDelivers);
7297f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipOutForwDatagrams);
7307f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipOutRequests);
7317f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipOutDiscards);
7327f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipOutNoRoutes);
7337f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipReasmTimeout);
7347f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipReasmReqds);
7357f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipReasmOKs);
7367f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipReasmFails);
7377f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipFragOKs);
7387f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipFragFails);
7397f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipFragCreates);
7407f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInMcastPkts);
7417f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipOutMcastPkts);
7427f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipInBcastPkts);
7437f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(ipOutBcastPkts);
7447f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpRtoAlgorithm);
7457f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpRtoMin);
7467f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpRtoMax);
7477f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpMaxConn);
7487f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpActiveOpens);
7497f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpPassiveOpens);
7507f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpAttemptFails);
7517f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpEstabResets);
7527f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpCurrEstab);
7537f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpInSegs);
7547f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpOutSegs);
7557f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpRetransSegs);
7567f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpInErrs);
7577f624d023b5fb150831e02c1e4c0f2619ade72c2Steve WiseIW_STATS_ENTRY(tcpOutRsts);
7587f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise
7597f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wisestatic struct attribute *iw_proto_stats_attrs[] = {
7607f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInReceives.attr,
7617f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInHdrErrors.attr,
7627f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInTooBigErrors.attr,
7637f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInNoRoutes.attr,
7647f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInAddrErrors.attr,
7657f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInUnknownProtos.attr,
7667f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInTruncatedPkts.attr,
7677f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInDiscards.attr,
7687f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInDelivers.attr,
7697f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipOutForwDatagrams.attr,
7707f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipOutRequests.attr,
7717f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipOutDiscards.attr,
7727f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipOutNoRoutes.attr,
7737f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipReasmTimeout.attr,
7747f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipReasmReqds.attr,
7757f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipReasmOKs.attr,
7767f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipReasmFails.attr,
7777f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipFragOKs.attr,
7787f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipFragFails.attr,
7797f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipFragCreates.attr,
7807f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInMcastPkts.attr,
7817f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipOutMcastPkts.attr,
7827f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipInBcastPkts.attr,
7837f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_ipOutBcastPkts.attr,
7847f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpRtoAlgorithm.attr,
7857f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpRtoMin.attr,
7867f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpRtoMax.attr,
7877f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpMaxConn.attr,
7887f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpActiveOpens.attr,
7897f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpPassiveOpens.attr,
7907f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpAttemptFails.attr,
7917f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpEstabResets.attr,
7927f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpCurrEstab.attr,
7937f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpInSegs.attr,
7947f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpOutSegs.attr,
7957f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpRetransSegs.attr,
7967f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpInErrs.attr,
7977f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	&dev_attr_tcpOutRsts.attr,
7987f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	NULL
7997f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise};
8007f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise
8017f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wisestatic struct attribute_group iw_stats_group = {
8027f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	.name	= "proto_stats",
8037f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	.attrs	= iw_proto_stats_attrs,
8047f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise};
8057f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise
8069a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbellint ib_device_register_sysfs(struct ib_device *device,
8079a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell			     int (*port_callback)(struct ib_device *,
8089a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell						  u8, struct kobject *))
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
810f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	struct device *class_dev = &device->dev;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	class_dev->class      = &ib_class;
815f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	class_dev->parent     = device->dma_device;
816d927e38c6c1859494792547beee249c17b43a17eKay Sievers	dev_set_name(class_dev, device->name);
8173f7c58a05fe4aa71983ea27959b7ad840950537eGreg Kroah-Hartman	dev_set_drvdata(class_dev, device);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&device->port_list);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	ret = device_register(class_dev);
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < ARRAY_SIZE(ib_class_attributes); ++i) {
826f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones		ret = device_create_file(class_dev, ib_class_attributes[i]);
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret)
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_unregister;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
83135be0681983752116a8161ad3b30e830963108a4Greg Kroah-Hartman	device->ports_parent = kobject_create_and_add("ports",
83235be0681983752116a8161ad3b30e830963108a4Greg Kroah-Hartman					kobject_get(&class_dev->kobj));
833c7482b81c8b524193d736488c149adbe27a7eb7fLi Zefan	if (!device->ports_parent) {
834c7482b81c8b524193d736488c149adbe27a7eb7fLi Zefan		ret = -ENOMEM;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_put;
836c7482b81c8b524193d736488c149adbe27a7eb7fLi Zefan	}
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
83807ebafbaaa72aa6a35472879008f5a1d1d469a0cTom Tucker	if (device->node_type == RDMA_NODE_IB_SWITCH) {
8399a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell		ret = add_port(device, 0, port_callback);
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret)
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_put;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 1; i <= device->phys_port_cnt; ++i) {
8449a6edb60ec10d86b1025a0cdad68fd89f1ddaf02Ralph Campbell			ret = add_port(device, i, port_callback);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret)
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_put;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8507f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	if (device->node_type == RDMA_NODE_RNIC && device->get_protocol_stats) {
8517f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise		ret = sysfs_create_group(&class_dev->kobj, &iw_stats_group);
8527f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise		if (ret)
8537f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise			goto err_put;
8547f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise	}
8557f624d023b5fb150831e02c1e4c0f2619ade72c2Steve Wise
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_put:
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct kobject *p, *t;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ib_port *port;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry_safe(p, t, &device->port_list, entry) {
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del(&p->entry);
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			port = container_of(p, struct ib_port, kobj);
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sysfs_remove_group(p, &pma_group);
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sysfs_remove_group(p, &port->pkey_group);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sysfs_remove_group(p, &port->gid_group);
869c10997f6575f476ff38442fa18fd4a0d80345f9dGreg Kroah-Hartman			kobject_put(p);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kobject_put(&class_dev->kobj);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_unregister:
876f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	device_unregister(class_dev);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr:
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ib_device_unregister_sysfs(struct ib_device *device)
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kobject *p, *t;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_port *port;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8879206dff15705267c19f8fed391c4fb95975540a3Roland Dreier	/* Hold kobject until ib_dealloc_device() */
8889206dff15705267c19f8fed391c4fb95975540a3Roland Dreier	kobject_get(&device->dev.kobj);
8899206dff15705267c19f8fed391c4fb95975540a3Roland Dreier
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry_safe(p, t, &device->port_list, entry) {
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del(&p->entry);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port = container_of(p, struct ib_port, kobj);
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sysfs_remove_group(p, &pma_group);
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sysfs_remove_group(p, &port->pkey_group);
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sysfs_remove_group(p, &port->gid_group);
896c10997f6575f476ff38442fa18fd4a0d80345f9dGreg Kroah-Hartman		kobject_put(p);
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
899c10997f6575f476ff38442fa18fd4a0d80345f9dGreg Kroah-Hartman	kobject_put(device->ports_parent);
900f4e91eb4a81559da87a3843758a641b5cc590b65Tony Jones	device_unregister(&device->dev);
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ib_sysfs_setup(void)
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return class_register(&ib_class);
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ib_sysfs_cleanup(void)
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	class_unregister(&ib_class);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
912