Path: blob/master/drivers/infiniband/hw/qib/qib_sysfs.c
15112 views
/*1* Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.2* Copyright (c) 2006 PathScale, Inc. All rights reserved.3*4* This software is available to you under a choice of one of two5* licenses. You may choose to be licensed under the terms of the GNU6* General Public License (GPL) Version 2, available from the file7* COPYING in the main directory of this source tree, or the8* OpenIB.org BSD license below:9*10* Redistribution and use in source and binary forms, with or11* without modification, are permitted provided that the following12* conditions are met:13*14* - Redistributions of source code must retain the above15* copyright notice, this list of conditions and the following16* disclaimer.17*18* - Redistributions in binary form must reproduce the above19* copyright notice, this list of conditions and the following20* disclaimer in the documentation and/or other materials21* provided with the distribution.22*23* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30* SOFTWARE.31*/32#include <linux/ctype.h>3334#include "qib.h"3536/**37* qib_parse_ushort - parse an unsigned short value in an arbitrary base38* @str: the string containing the number39* @valp: where to put the result40*41* Returns the number of bytes consumed, or negative value on error.42*/43static int qib_parse_ushort(const char *str, unsigned short *valp)44{45unsigned long val;46char *end;47int ret;4849if (!isdigit(str[0])) {50ret = -EINVAL;51goto bail;52}5354val = simple_strtoul(str, &end, 0);5556if (val > 0xffff) {57ret = -EINVAL;58goto bail;59}6061*valp = val;6263ret = end + 1 - str;64if (ret == 0)65ret = -EINVAL;6667bail:68return ret;69}7071/* start of per-port functions */72/*73* Get/Set heartbeat enable. OR of 1=enabled, 2=auto74*/75static ssize_t show_hrtbt_enb(struct qib_pportdata *ppd, char *buf)76{77struct qib_devdata *dd = ppd->dd;78int ret;7980ret = dd->f_get_ib_cfg(ppd, QIB_IB_CFG_HRTBT);81ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);82return ret;83}8485static ssize_t store_hrtbt_enb(struct qib_pportdata *ppd, const char *buf,86size_t count)87{88struct qib_devdata *dd = ppd->dd;89int ret;90u16 val;9192ret = qib_parse_ushort(buf, &val);9394/*95* Set the "intentional" heartbeat enable per either of96* "Enable" and "Auto", as these are normally set together.97* This bit is consulted when leaving loopback mode,98* because entering loopback mode overrides it and automatically99* disables heartbeat.100*/101if (ret >= 0)102ret = dd->f_set_ib_cfg(ppd, QIB_IB_CFG_HRTBT, val);103if (ret < 0)104qib_dev_err(dd, "attempt to set invalid Heartbeat enable\n");105return ret < 0 ? ret : count;106}107108static ssize_t store_loopback(struct qib_pportdata *ppd, const char *buf,109size_t count)110{111struct qib_devdata *dd = ppd->dd;112int ret = count, r;113114r = dd->f_set_ib_loopback(ppd, buf);115if (r < 0)116ret = r;117118return ret;119}120121static ssize_t store_led_override(struct qib_pportdata *ppd, const char *buf,122size_t count)123{124struct qib_devdata *dd = ppd->dd;125int ret;126u16 val;127128ret = qib_parse_ushort(buf, &val);129if (ret > 0)130qib_set_led_override(ppd, val);131else132qib_dev_err(dd, "attempt to set invalid LED override\n");133return ret < 0 ? ret : count;134}135136static ssize_t show_status(struct qib_pportdata *ppd, char *buf)137{138ssize_t ret;139140if (!ppd->statusp)141ret = -EINVAL;142else143ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",144(unsigned long long) *(ppd->statusp));145return ret;146}147148/*149* For userland compatibility, these offsets must remain fixed.150* They are strings for QIB_STATUS_*151*/152static const char *qib_status_str[] = {153"Initted",154"",155"",156"",157"",158"Present",159"IB_link_up",160"IB_configured",161"",162"Fatal_Hardware_Error",163NULL,164};165166static ssize_t show_status_str(struct qib_pportdata *ppd, char *buf)167{168int i, any;169u64 s;170ssize_t ret;171172if (!ppd->statusp) {173ret = -EINVAL;174goto bail;175}176177s = *(ppd->statusp);178*buf = '\0';179for (any = i = 0; s && qib_status_str[i]; i++) {180if (s & 1) {181/* if overflow */182if (any && strlcat(buf, " ", PAGE_SIZE) >= PAGE_SIZE)183break;184if (strlcat(buf, qib_status_str[i], PAGE_SIZE) >=185PAGE_SIZE)186break;187any = 1;188}189s >>= 1;190}191if (any)192strlcat(buf, "\n", PAGE_SIZE);193194ret = strlen(buf);195196bail:197return ret;198}199200/* end of per-port functions */201202/*203* Start of per-port file structures and support code204* Because we are fitting into other infrastructure, we have to supply the205* full set of kobject/sysfs_ops structures and routines.206*/207#define QIB_PORT_ATTR(name, mode, show, store) \208static struct qib_port_attr qib_port_attr_##name = \209__ATTR(name, mode, show, store)210211struct qib_port_attr {212struct attribute attr;213ssize_t (*show)(struct qib_pportdata *, char *);214ssize_t (*store)(struct qib_pportdata *, const char *, size_t);215};216217QIB_PORT_ATTR(loopback, S_IWUSR, NULL, store_loopback);218QIB_PORT_ATTR(led_override, S_IWUSR, NULL, store_led_override);219QIB_PORT_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb,220store_hrtbt_enb);221QIB_PORT_ATTR(status, S_IRUGO, show_status, NULL);222QIB_PORT_ATTR(status_str, S_IRUGO, show_status_str, NULL);223224static struct attribute *port_default_attributes[] = {225&qib_port_attr_loopback.attr,226&qib_port_attr_led_override.attr,227&qib_port_attr_hrtbt_enable.attr,228&qib_port_attr_status.attr,229&qib_port_attr_status_str.attr,230NULL231};232233static ssize_t qib_portattr_show(struct kobject *kobj,234struct attribute *attr, char *buf)235{236struct qib_port_attr *pattr =237container_of(attr, struct qib_port_attr, attr);238struct qib_pportdata *ppd =239container_of(kobj, struct qib_pportdata, pport_kobj);240241return pattr->show(ppd, buf);242}243244static ssize_t qib_portattr_store(struct kobject *kobj,245struct attribute *attr, const char *buf, size_t len)246{247struct qib_port_attr *pattr =248container_of(attr, struct qib_port_attr, attr);249struct qib_pportdata *ppd =250container_of(kobj, struct qib_pportdata, pport_kobj);251252return pattr->store(ppd, buf, len);253}254255static void qib_port_release(struct kobject *kobj)256{257/* nothing to do since memory is freed by qib_free_devdata() */258}259260static const struct sysfs_ops qib_port_ops = {261.show = qib_portattr_show,262.store = qib_portattr_store,263};264265static struct kobj_type qib_port_ktype = {266.release = qib_port_release,267.sysfs_ops = &qib_port_ops,268.default_attrs = port_default_attributes269};270271/* Start sl2vl */272273#define QIB_SL2VL_ATTR(N) \274static struct qib_sl2vl_attr qib_sl2vl_attr_##N = { \275.attr = { .name = __stringify(N), .mode = 0444 }, \276.sl = N \277}278279struct qib_sl2vl_attr {280struct attribute attr;281int sl;282};283284QIB_SL2VL_ATTR(0);285QIB_SL2VL_ATTR(1);286QIB_SL2VL_ATTR(2);287QIB_SL2VL_ATTR(3);288QIB_SL2VL_ATTR(4);289QIB_SL2VL_ATTR(5);290QIB_SL2VL_ATTR(6);291QIB_SL2VL_ATTR(7);292QIB_SL2VL_ATTR(8);293QIB_SL2VL_ATTR(9);294QIB_SL2VL_ATTR(10);295QIB_SL2VL_ATTR(11);296QIB_SL2VL_ATTR(12);297QIB_SL2VL_ATTR(13);298QIB_SL2VL_ATTR(14);299QIB_SL2VL_ATTR(15);300301static struct attribute *sl2vl_default_attributes[] = {302&qib_sl2vl_attr_0.attr,303&qib_sl2vl_attr_1.attr,304&qib_sl2vl_attr_2.attr,305&qib_sl2vl_attr_3.attr,306&qib_sl2vl_attr_4.attr,307&qib_sl2vl_attr_5.attr,308&qib_sl2vl_attr_6.attr,309&qib_sl2vl_attr_7.attr,310&qib_sl2vl_attr_8.attr,311&qib_sl2vl_attr_9.attr,312&qib_sl2vl_attr_10.attr,313&qib_sl2vl_attr_11.attr,314&qib_sl2vl_attr_12.attr,315&qib_sl2vl_attr_13.attr,316&qib_sl2vl_attr_14.attr,317&qib_sl2vl_attr_15.attr,318NULL319};320321static ssize_t sl2vl_attr_show(struct kobject *kobj, struct attribute *attr,322char *buf)323{324struct qib_sl2vl_attr *sattr =325container_of(attr, struct qib_sl2vl_attr, attr);326struct qib_pportdata *ppd =327container_of(kobj, struct qib_pportdata, sl2vl_kobj);328struct qib_ibport *qibp = &ppd->ibport_data;329330return sprintf(buf, "%u\n", qibp->sl_to_vl[sattr->sl]);331}332333static const struct sysfs_ops qib_sl2vl_ops = {334.show = sl2vl_attr_show,335};336337static struct kobj_type qib_sl2vl_ktype = {338.release = qib_port_release,339.sysfs_ops = &qib_sl2vl_ops,340.default_attrs = sl2vl_default_attributes341};342343/* End sl2vl */344345/* Start diag_counters */346347#define QIB_DIAGC_ATTR(N) \348static struct qib_diagc_attr qib_diagc_attr_##N = { \349.attr = { .name = __stringify(N), .mode = 0664 }, \350.counter = offsetof(struct qib_ibport, n_##N) \351}352353struct qib_diagc_attr {354struct attribute attr;355size_t counter;356};357358QIB_DIAGC_ATTR(rc_resends);359QIB_DIAGC_ATTR(rc_acks);360QIB_DIAGC_ATTR(rc_qacks);361QIB_DIAGC_ATTR(rc_delayed_comp);362QIB_DIAGC_ATTR(seq_naks);363QIB_DIAGC_ATTR(rdma_seq);364QIB_DIAGC_ATTR(rnr_naks);365QIB_DIAGC_ATTR(other_naks);366QIB_DIAGC_ATTR(rc_timeouts);367QIB_DIAGC_ATTR(loop_pkts);368QIB_DIAGC_ATTR(pkt_drops);369QIB_DIAGC_ATTR(dmawait);370QIB_DIAGC_ATTR(unaligned);371QIB_DIAGC_ATTR(rc_dupreq);372QIB_DIAGC_ATTR(rc_seqnak);373374static struct attribute *diagc_default_attributes[] = {375&qib_diagc_attr_rc_resends.attr,376&qib_diagc_attr_rc_acks.attr,377&qib_diagc_attr_rc_qacks.attr,378&qib_diagc_attr_rc_delayed_comp.attr,379&qib_diagc_attr_seq_naks.attr,380&qib_diagc_attr_rdma_seq.attr,381&qib_diagc_attr_rnr_naks.attr,382&qib_diagc_attr_other_naks.attr,383&qib_diagc_attr_rc_timeouts.attr,384&qib_diagc_attr_loop_pkts.attr,385&qib_diagc_attr_pkt_drops.attr,386&qib_diagc_attr_dmawait.attr,387&qib_diagc_attr_unaligned.attr,388&qib_diagc_attr_rc_dupreq.attr,389&qib_diagc_attr_rc_seqnak.attr,390NULL391};392393static ssize_t diagc_attr_show(struct kobject *kobj, struct attribute *attr,394char *buf)395{396struct qib_diagc_attr *dattr =397container_of(attr, struct qib_diagc_attr, attr);398struct qib_pportdata *ppd =399container_of(kobj, struct qib_pportdata, diagc_kobj);400struct qib_ibport *qibp = &ppd->ibport_data;401402return sprintf(buf, "%u\n", *(u32 *)((char *)qibp + dattr->counter));403}404405static ssize_t diagc_attr_store(struct kobject *kobj, struct attribute *attr,406const char *buf, size_t size)407{408struct qib_diagc_attr *dattr =409container_of(attr, struct qib_diagc_attr, attr);410struct qib_pportdata *ppd =411container_of(kobj, struct qib_pportdata, diagc_kobj);412struct qib_ibport *qibp = &ppd->ibport_data;413char *endp;414long val = simple_strtol(buf, &endp, 0);415416if (val < 0 || endp == buf)417return -EINVAL;418419*(u32 *)((char *) qibp + dattr->counter) = val;420return size;421}422423static const struct sysfs_ops qib_diagc_ops = {424.show = diagc_attr_show,425.store = diagc_attr_store,426};427428static struct kobj_type qib_diagc_ktype = {429.release = qib_port_release,430.sysfs_ops = &qib_diagc_ops,431.default_attrs = diagc_default_attributes432};433434/* End diag_counters */435436/* end of per-port file structures and support code */437438/*439* Start of per-unit (or driver, in some cases, but replicated440* per unit) functions (these get a device *)441*/442static ssize_t show_rev(struct device *device, struct device_attribute *attr,443char *buf)444{445struct qib_ibdev *dev =446container_of(device, struct qib_ibdev, ibdev.dev);447448return sprintf(buf, "%x\n", dd_from_dev(dev)->minrev);449}450451static ssize_t show_hca(struct device *device, struct device_attribute *attr,452char *buf)453{454struct qib_ibdev *dev =455container_of(device, struct qib_ibdev, ibdev.dev);456struct qib_devdata *dd = dd_from_dev(dev);457int ret;458459if (!dd->boardname)460ret = -EINVAL;461else462ret = scnprintf(buf, PAGE_SIZE, "%s\n", dd->boardname);463return ret;464}465466static ssize_t show_version(struct device *device,467struct device_attribute *attr, char *buf)468{469/* The string printed here is already newline-terminated. */470return scnprintf(buf, PAGE_SIZE, "%s", (char *)ib_qib_version);471}472473static ssize_t show_boardversion(struct device *device,474struct device_attribute *attr, char *buf)475{476struct qib_ibdev *dev =477container_of(device, struct qib_ibdev, ibdev.dev);478struct qib_devdata *dd = dd_from_dev(dev);479480/* The string printed here is already newline-terminated. */481return scnprintf(buf, PAGE_SIZE, "%s", dd->boardversion);482}483484485static ssize_t show_localbus_info(struct device *device,486struct device_attribute *attr, char *buf)487{488struct qib_ibdev *dev =489container_of(device, struct qib_ibdev, ibdev.dev);490struct qib_devdata *dd = dd_from_dev(dev);491492/* The string printed here is already newline-terminated. */493return scnprintf(buf, PAGE_SIZE, "%s", dd->lbus_info);494}495496497static ssize_t show_nctxts(struct device *device,498struct device_attribute *attr, char *buf)499{500struct qib_ibdev *dev =501container_of(device, struct qib_ibdev, ibdev.dev);502struct qib_devdata *dd = dd_from_dev(dev);503504/* Return the number of user ports (contexts) available. */505return scnprintf(buf, PAGE_SIZE, "%u\n", dd->cfgctxts -506dd->first_user_ctxt);507}508509static ssize_t show_serial(struct device *device,510struct device_attribute *attr, char *buf)511{512struct qib_ibdev *dev =513container_of(device, struct qib_ibdev, ibdev.dev);514struct qib_devdata *dd = dd_from_dev(dev);515516buf[sizeof dd->serial] = '\0';517memcpy(buf, dd->serial, sizeof dd->serial);518strcat(buf, "\n");519return strlen(buf);520}521522static ssize_t store_chip_reset(struct device *device,523struct device_attribute *attr, const char *buf,524size_t count)525{526struct qib_ibdev *dev =527container_of(device, struct qib_ibdev, ibdev.dev);528struct qib_devdata *dd = dd_from_dev(dev);529int ret;530531if (count < 5 || memcmp(buf, "reset", 5) || !dd->diag_client) {532ret = -EINVAL;533goto bail;534}535536ret = qib_reset_device(dd->unit);537bail:538return ret < 0 ? ret : count;539}540541static ssize_t show_logged_errs(struct device *device,542struct device_attribute *attr, char *buf)543{544struct qib_ibdev *dev =545container_of(device, struct qib_ibdev, ibdev.dev);546struct qib_devdata *dd = dd_from_dev(dev);547int idx, count;548549/* force consistency with actual EEPROM */550if (qib_update_eeprom_log(dd) != 0)551return -ENXIO;552553count = 0;554for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) {555count += scnprintf(buf + count, PAGE_SIZE - count, "%d%c",556dd->eep_st_errs[idx],557idx == (QIB_EEP_LOG_CNT - 1) ? '\n' : ' ');558}559560return count;561}562563/*564* Dump tempsense regs. in decimal, to ease shell-scripts.565*/566static ssize_t show_tempsense(struct device *device,567struct device_attribute *attr, char *buf)568{569struct qib_ibdev *dev =570container_of(device, struct qib_ibdev, ibdev.dev);571struct qib_devdata *dd = dd_from_dev(dev);572int ret;573int idx;574u8 regvals[8];575576ret = -ENXIO;577for (idx = 0; idx < 8; ++idx) {578if (idx == 6)579continue;580ret = dd->f_tempsense_rd(dd, idx);581if (ret < 0)582break;583regvals[idx] = ret;584}585if (idx == 8)586ret = scnprintf(buf, PAGE_SIZE, "%d %d %02X %02X %d %d\n",587*(signed char *)(regvals),588*(signed char *)(regvals + 1),589regvals[2], regvals[3],590*(signed char *)(regvals + 5),591*(signed char *)(regvals + 7));592return ret;593}594595/*596* end of per-unit (or driver, in some cases, but replicated597* per unit) functions598*/599600/* start of per-unit file structures and support code */601static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);602static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);603static DEVICE_ATTR(board_id, S_IRUGO, show_hca, NULL);604static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);605static DEVICE_ATTR(nctxts, S_IRUGO, show_nctxts, NULL);606static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);607static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);608static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);609static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL);610static DEVICE_ATTR(localbus_info, S_IRUGO, show_localbus_info, NULL);611static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset);612613static struct device_attribute *qib_attributes[] = {614&dev_attr_hw_rev,615&dev_attr_hca_type,616&dev_attr_board_id,617&dev_attr_version,618&dev_attr_nctxts,619&dev_attr_serial,620&dev_attr_boardversion,621&dev_attr_logged_errors,622&dev_attr_tempsense,623&dev_attr_localbus_info,624&dev_attr_chip_reset,625};626627int qib_create_port_files(struct ib_device *ibdev, u8 port_num,628struct kobject *kobj)629{630struct qib_pportdata *ppd;631struct qib_devdata *dd = dd_from_ibdev(ibdev);632int ret;633634if (!port_num || port_num > dd->num_pports) {635qib_dev_err(dd, "Skipping infiniband class with "636"invalid port %u\n", port_num);637ret = -ENODEV;638goto bail;639}640ppd = &dd->pport[port_num - 1];641642ret = kobject_init_and_add(&ppd->pport_kobj, &qib_port_ktype, kobj,643"linkcontrol");644if (ret) {645qib_dev_err(dd, "Skipping linkcontrol sysfs info, "646"(err %d) port %u\n", ret, port_num);647goto bail;648}649kobject_uevent(&ppd->pport_kobj, KOBJ_ADD);650651ret = kobject_init_and_add(&ppd->sl2vl_kobj, &qib_sl2vl_ktype, kobj,652"sl2vl");653if (ret) {654qib_dev_err(dd, "Skipping sl2vl sysfs info, "655"(err %d) port %u\n", ret, port_num);656goto bail_sl;657}658kobject_uevent(&ppd->sl2vl_kobj, KOBJ_ADD);659660ret = kobject_init_and_add(&ppd->diagc_kobj, &qib_diagc_ktype, kobj,661"diag_counters");662if (ret) {663qib_dev_err(dd, "Skipping diag_counters sysfs info, "664"(err %d) port %u\n", ret, port_num);665goto bail_diagc;666}667kobject_uevent(&ppd->diagc_kobj, KOBJ_ADD);668669return 0;670671bail_diagc:672kobject_put(&ppd->sl2vl_kobj);673bail_sl:674kobject_put(&ppd->pport_kobj);675bail:676return ret;677}678679/*680* Register and create our files in /sys/class/infiniband.681*/682int qib_verbs_register_sysfs(struct qib_devdata *dd)683{684struct ib_device *dev = &dd->verbs_dev.ibdev;685int i, ret;686687for (i = 0; i < ARRAY_SIZE(qib_attributes); ++i) {688ret = device_create_file(&dev->dev, qib_attributes[i]);689if (ret)690return ret;691}692693return 0;694}695696/*697* Unregister and remove our files in /sys/class/infiniband.698*/699void qib_verbs_unregister_sysfs(struct qib_devdata *dd)700{701struct qib_pportdata *ppd;702int i;703704for (i = 0; i < dd->num_pports; i++) {705ppd = &dd->pport[i];706kobject_put(&ppd->pport_kobj);707kobject_put(&ppd->sl2vl_kobj);708}709}710711712