211 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright IBM Corp. 2007, 20074 * Authors: Peter Tiedemann (ptiedem@de.ibm.com)5 *6 */7 8#undef DEBUG9#undef DEBUGDATA10#undef DEBUGCCW11 12#define KMSG_COMPONENT "ctcm"13#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt14 15#include <linux/device.h>16#include <linux/sysfs.h>17#include <linux/slab.h>18#include "ctcm_main.h"19 20/*21 * sysfs attributes22 */23 24static ssize_t ctcm_buffer_show(struct device *dev,25 struct device_attribute *attr, char *buf)26{27 struct ctcm_priv *priv = dev_get_drvdata(dev);28 29 if (!priv)30 return -ENODEV;31 return sysfs_emit(buf, "%d\n", priv->buffer_size);32}33 34static ssize_t ctcm_buffer_write(struct device *dev,35 struct device_attribute *attr, const char *buf, size_t count)36{37 struct net_device *ndev;38 unsigned int bs1;39 struct ctcm_priv *priv = dev_get_drvdata(dev);40 int rc;41 42 if (!(priv && priv->channel[CTCM_READ] &&43 priv->channel[CTCM_READ]->netdev)) {44 CTCM_DBF_TEXT(SETUP, CTC_DBF_ERROR, "bfnondev");45 return -ENODEV;46 }47 ndev = priv->channel[CTCM_READ]->netdev;48 49 rc = kstrtouint(buf, 0, &bs1);50 if (rc)51 goto einval;52 if (bs1 > CTCM_BUFSIZE_LIMIT)53 goto einval;54 if (bs1 < (576 + LL_HEADER_LENGTH + 2))55 goto einval;56 priv->buffer_size = bs1; /* just to overwrite the default */57 58 if ((ndev->flags & IFF_RUNNING) &&59 (bs1 < (ndev->mtu + LL_HEADER_LENGTH + 2)))60 goto einval;61 62 priv->channel[CTCM_READ]->max_bufsize = bs1;63 priv->channel[CTCM_WRITE]->max_bufsize = bs1;64 if (!(ndev->flags & IFF_RUNNING))65 ndev->mtu = bs1 - LL_HEADER_LENGTH - 2;66 priv->channel[CTCM_READ]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;67 priv->channel[CTCM_WRITE]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;68 69 CTCM_DBF_DEV(SETUP, ndev, buf);70 return count;71 72einval:73 CTCM_DBF_DEV(SETUP, ndev, "buff_err");74 return -EINVAL;75}76 77static void ctcm_print_statistics(struct ctcm_priv *priv)78{79 char *sbuf;80 char *p;81 82 if (!priv)83 return;84 sbuf = kmalloc(2048, GFP_KERNEL);85 if (sbuf == NULL)86 return;87 p = sbuf;88 89 p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Device FSM state: %s\n",90 fsm_getstate_str(priv->fsm));91 p += scnprintf(p, CTCM_STATSIZE_LIMIT, " RX channel FSM state: %s\n",92 fsm_getstate_str(priv->channel[CTCM_READ]->fsm));93 p += scnprintf(p, CTCM_STATSIZE_LIMIT, " TX channel FSM state: %s\n",94 fsm_getstate_str(priv->channel[CTCM_WRITE]->fsm));95 p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Max. TX buffer used: %ld\n",96 priv->channel[WRITE]->prof.maxmulti);97 p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Max. chained SKBs: %ld\n",98 priv->channel[WRITE]->prof.maxcqueue);99 p += scnprintf(p, CTCM_STATSIZE_LIMIT, " TX single write ops: %ld\n",100 priv->channel[WRITE]->prof.doios_single);101 p += scnprintf(p, CTCM_STATSIZE_LIMIT, " TX multi write ops: %ld\n",102 priv->channel[WRITE]->prof.doios_multi);103 p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Netto bytes written: %ld\n",104 priv->channel[WRITE]->prof.txlen);105 p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Max. TX IO-time: %u\n",106 jiffies_to_usecs(priv->channel[WRITE]->prof.tx_time));107 108 printk(KERN_INFO "Statistics for %s:\n%s",109 priv->channel[CTCM_WRITE]->netdev->name, sbuf);110 kfree(sbuf);111 return;112}113 114static ssize_t stats_show(struct device *dev,115 struct device_attribute *attr, char *buf)116{117 struct ccwgroup_device *gdev = to_ccwgroupdev(dev);118 struct ctcm_priv *priv = dev_get_drvdata(dev);119 120 if (!priv || gdev->state != CCWGROUP_ONLINE)121 return -ENODEV;122 ctcm_print_statistics(priv);123 return sysfs_emit(buf, "0\n");124}125 126static ssize_t stats_write(struct device *dev, struct device_attribute *attr,127 const char *buf, size_t count)128{129 struct ctcm_priv *priv = dev_get_drvdata(dev);130 if (!priv)131 return -ENODEV;132 /* Reset statistics */133 memset(&priv->channel[WRITE]->prof, 0,134 sizeof(priv->channel[CTCM_WRITE]->prof));135 return count;136}137 138static ssize_t ctcm_proto_show(struct device *dev,139 struct device_attribute *attr, char *buf)140{141 struct ctcm_priv *priv = dev_get_drvdata(dev);142 if (!priv)143 return -ENODEV;144 145 return sysfs_emit(buf, "%d\n", priv->protocol);146}147 148static ssize_t ctcm_proto_store(struct device *dev,149 struct device_attribute *attr, const char *buf, size_t count)150{151 int value, rc;152 struct ctcm_priv *priv = dev_get_drvdata(dev);153 154 if (!priv)155 return -ENODEV;156 rc = kstrtoint(buf, 0, &value);157 if (rc ||158 !((value == CTCM_PROTO_S390) ||159 (value == CTCM_PROTO_LINUX) ||160 (value == CTCM_PROTO_MPC) ||161 (value == CTCM_PROTO_OS390)))162 return -EINVAL;163 priv->protocol = value;164 CTCM_DBF_DEV(SETUP, dev, buf);165 166 return count;167}168 169static const char *ctcm_type[] = {170 "not a channel",171 "CTC/A",172 "FICON channel",173 "ESCON channel",174 "unknown channel type",175 "unsupported channel type",176};177 178static ssize_t ctcm_type_show(struct device *dev,179 struct device_attribute *attr, char *buf)180{181 struct ccwgroup_device *cgdev;182 183 cgdev = to_ccwgroupdev(dev);184 if (!cgdev)185 return -ENODEV;186 187 return sysfs_emit(buf, "%s\n",188 ctcm_type[cgdev->cdev[0]->id.driver_info]);189}190 191static DEVICE_ATTR(buffer, 0644, ctcm_buffer_show, ctcm_buffer_write);192static DEVICE_ATTR(protocol, 0644, ctcm_proto_show, ctcm_proto_store);193static DEVICE_ATTR(type, 0444, ctcm_type_show, NULL);194static DEVICE_ATTR(stats, 0644, stats_show, stats_write);195 196static struct attribute *ctcm_attr[] = {197 &dev_attr_protocol.attr,198 &dev_attr_type.attr,199 &dev_attr_buffer.attr,200 &dev_attr_stats.attr,201 NULL,202};203 204static struct attribute_group ctcm_attr_group = {205 .attrs = ctcm_attr,206};207const struct attribute_group *ctcm_attr_groups[] = {208 &ctcm_attr_group,209 NULL,210};211