549 lines · c
1/*2 * Copyright (c) 2012 Intel Corporation. All rights reserved.3 * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.4 * Copyright (c) 2006 PathScale, Inc. All rights reserved.5 *6 * This software is available to you under a choice of one of two7 * licenses. You may choose to be licensed under the terms of the GNU8 * General Public License (GPL) Version 2, available from the file9 * COPYING in the main directory of this source tree, or the10 * OpenIB.org BSD license below:11 *12 * Redistribution and use in source and binary forms, with or13 * without modification, are permitted provided that the following14 * conditions are met:15 *16 * - Redistributions of source code must retain the above17 * copyright notice, this list of conditions and the following18 * disclaimer.19 *20 * - Redistributions in binary form must reproduce the above21 * copyright notice, this list of conditions and the following22 * disclaimer in the documentation and/or other materials23 * provided with the distribution.24 *25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE32 * SOFTWARE.33 */34 35#include <linux/fs.h>36#include <linux/fs_context.h>37#include <linux/mount.h>38#include <linux/pagemap.h>39#include <linux/init.h>40#include <linux/namei.h>41 42#include "qib.h"43 44#define QIBFS_MAGIC 0x726a7745 46static struct super_block *qib_super;47 48#define private2dd(file) (file_inode(file)->i_private)49 50static int qibfs_mknod(struct inode *dir, struct dentry *dentry,51 umode_t mode, const struct file_operations *fops,52 void *data)53{54 int error;55 struct inode *inode = new_inode(dir->i_sb);56 57 if (!inode) {58 error = -EPERM;59 goto bail;60 }61 62 inode->i_ino = get_next_ino();63 inode->i_mode = mode;64 inode->i_uid = GLOBAL_ROOT_UID;65 inode->i_gid = GLOBAL_ROOT_GID;66 inode->i_blocks = 0;67 simple_inode_init_ts(inode);68 69 inode->i_private = data;70 if (S_ISDIR(mode)) {71 inode->i_op = &simple_dir_inode_operations;72 inc_nlink(inode);73 inc_nlink(dir);74 }75 76 inode->i_fop = fops;77 78 d_instantiate(dentry, inode);79 error = 0;80 81bail:82 return error;83}84 85static int create_file(const char *name, umode_t mode,86 struct dentry *parent, struct dentry **dentry,87 const struct file_operations *fops, void *data)88{89 int error;90 91 inode_lock(d_inode(parent));92 *dentry = lookup_one_len(name, parent, strlen(name));93 if (!IS_ERR(*dentry))94 error = qibfs_mknod(d_inode(parent), *dentry,95 mode, fops, data);96 else97 error = PTR_ERR(*dentry);98 inode_unlock(d_inode(parent));99 100 return error;101}102 103static ssize_t driver_stats_read(struct file *file, char __user *buf,104 size_t count, loff_t *ppos)105{106 qib_stats.sps_ints = qib_sps_ints();107 return simple_read_from_buffer(buf, count, ppos, &qib_stats,108 sizeof(qib_stats));109}110 111/*112 * driver stats field names, one line per stat, single string. Used by113 * programs like ipathstats to print the stats in a way which works for114 * different versions of drivers, without changing program source.115 * if qlogic_ib_stats changes, this needs to change. Names need to be116 * 12 chars or less (w/o newline), for proper display by ipathstats utility.117 */118static const char qib_statnames[] =119 "KernIntr\n"120 "ErrorIntr\n"121 "Tx_Errs\n"122 "Rcv_Errs\n"123 "H/W_Errs\n"124 "NoPIOBufs\n"125 "CtxtsOpen\n"126 "RcvLen_Errs\n"127 "EgrBufFull\n"128 "EgrHdrFull\n"129 ;130 131static ssize_t driver_names_read(struct file *file, char __user *buf,132 size_t count, loff_t *ppos)133{134 return simple_read_from_buffer(buf, count, ppos, qib_statnames,135 sizeof(qib_statnames) - 1); /* no null */136}137 138static const struct file_operations driver_ops[] = {139 { .read = driver_stats_read, .llseek = generic_file_llseek, },140 { .read = driver_names_read, .llseek = generic_file_llseek, },141};142 143/* read the per-device counters */144static ssize_t dev_counters_read(struct file *file, char __user *buf,145 size_t count, loff_t *ppos)146{147 u64 *counters;148 size_t avail;149 struct qib_devdata *dd = private2dd(file);150 151 avail = dd->f_read_cntrs(dd, *ppos, NULL, &counters);152 return simple_read_from_buffer(buf, count, ppos, counters, avail);153}154 155/* read the per-device counters */156static ssize_t dev_names_read(struct file *file, char __user *buf,157 size_t count, loff_t *ppos)158{159 char *names;160 size_t avail;161 struct qib_devdata *dd = private2dd(file);162 163 avail = dd->f_read_cntrs(dd, *ppos, &names, NULL);164 return simple_read_from_buffer(buf, count, ppos, names, avail);165}166 167static const struct file_operations cntr_ops[] = {168 { .read = dev_counters_read, .llseek = generic_file_llseek, },169 { .read = dev_names_read, .llseek = generic_file_llseek, },170};171 172/*173 * Could use file_inode(file)->i_ino to figure out which file,174 * instead of separate routine for each, but for now, this works...175 */176 177/* read the per-port names (same for each port) */178static ssize_t portnames_read(struct file *file, char __user *buf,179 size_t count, loff_t *ppos)180{181 char *names;182 size_t avail;183 struct qib_devdata *dd = private2dd(file);184 185 avail = dd->f_read_portcntrs(dd, *ppos, 0, &names, NULL);186 return simple_read_from_buffer(buf, count, ppos, names, avail);187}188 189/* read the per-port counters for port 1 (pidx 0) */190static ssize_t portcntrs_1_read(struct file *file, char __user *buf,191 size_t count, loff_t *ppos)192{193 u64 *counters;194 size_t avail;195 struct qib_devdata *dd = private2dd(file);196 197 avail = dd->f_read_portcntrs(dd, *ppos, 0, NULL, &counters);198 return simple_read_from_buffer(buf, count, ppos, counters, avail);199}200 201/* read the per-port counters for port 2 (pidx 1) */202static ssize_t portcntrs_2_read(struct file *file, char __user *buf,203 size_t count, loff_t *ppos)204{205 u64 *counters;206 size_t avail;207 struct qib_devdata *dd = private2dd(file);208 209 avail = dd->f_read_portcntrs(dd, *ppos, 1, NULL, &counters);210 return simple_read_from_buffer(buf, count, ppos, counters, avail);211}212 213static const struct file_operations portcntr_ops[] = {214 { .read = portnames_read, .llseek = generic_file_llseek, },215 { .read = portcntrs_1_read, .llseek = generic_file_llseek, },216 { .read = portcntrs_2_read, .llseek = generic_file_llseek, },217};218 219/*220 * read the per-port QSFP data for port 1 (pidx 0)221 */222static ssize_t qsfp_1_read(struct file *file, char __user *buf,223 size_t count, loff_t *ppos)224{225 struct qib_devdata *dd = private2dd(file);226 char *tmp;227 int ret;228 229 tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);230 if (!tmp)231 return -ENOMEM;232 233 ret = qib_qsfp_dump(dd->pport, tmp, PAGE_SIZE);234 if (ret > 0)235 ret = simple_read_from_buffer(buf, count, ppos, tmp, ret);236 kfree(tmp);237 return ret;238}239 240/*241 * read the per-port QSFP data for port 2 (pidx 1)242 */243static ssize_t qsfp_2_read(struct file *file, char __user *buf,244 size_t count, loff_t *ppos)245{246 struct qib_devdata *dd = private2dd(file);247 char *tmp;248 int ret;249 250 if (dd->num_pports < 2)251 return -ENODEV;252 253 tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);254 if (!tmp)255 return -ENOMEM;256 257 ret = qib_qsfp_dump(dd->pport + 1, tmp, PAGE_SIZE);258 if (ret > 0)259 ret = simple_read_from_buffer(buf, count, ppos, tmp, ret);260 kfree(tmp);261 return ret;262}263 264static const struct file_operations qsfp_ops[] = {265 { .read = qsfp_1_read, .llseek = generic_file_llseek, },266 { .read = qsfp_2_read, .llseek = generic_file_llseek, },267};268 269static ssize_t flash_read(struct file *file, char __user *buf,270 size_t count, loff_t *ppos)271{272 struct qib_devdata *dd;273 ssize_t ret;274 loff_t pos;275 char *tmp;276 277 pos = *ppos;278 279 if (pos < 0) {280 ret = -EINVAL;281 goto bail;282 }283 284 if (pos >= sizeof(struct qib_flash)) {285 ret = 0;286 goto bail;287 }288 289 if (count > sizeof(struct qib_flash) - pos)290 count = sizeof(struct qib_flash) - pos;291 292 tmp = kmalloc(count, GFP_KERNEL);293 if (!tmp) {294 ret = -ENOMEM;295 goto bail;296 }297 298 dd = private2dd(file);299 if (qib_eeprom_read(dd, pos, tmp, count)) {300 qib_dev_err(dd, "failed to read from flash\n");301 ret = -ENXIO;302 goto bail_tmp;303 }304 305 if (copy_to_user(buf, tmp, count)) {306 ret = -EFAULT;307 goto bail_tmp;308 }309 310 *ppos = pos + count;311 ret = count;312 313bail_tmp:314 kfree(tmp);315 316bail:317 return ret;318}319 320static ssize_t flash_write(struct file *file, const char __user *buf,321 size_t count, loff_t *ppos)322{323 struct qib_devdata *dd;324 ssize_t ret;325 loff_t pos;326 char *tmp;327 328 pos = *ppos;329 330 if (pos != 0 || count != sizeof(struct qib_flash))331 return -EINVAL;332 333 tmp = memdup_user(buf, count);334 if (IS_ERR(tmp))335 return PTR_ERR(tmp);336 337 dd = private2dd(file);338 if (qib_eeprom_write(dd, pos, tmp, count)) {339 ret = -ENXIO;340 qib_dev_err(dd, "failed to write to flash\n");341 goto bail_tmp;342 }343 344 *ppos = pos + count;345 ret = count;346 347bail_tmp:348 kfree(tmp);349 return ret;350}351 352static const struct file_operations flash_ops = {353 .read = flash_read,354 .write = flash_write,355 .llseek = default_llseek,356};357 358static int add_cntr_files(struct super_block *sb, struct qib_devdata *dd)359{360 struct dentry *dir, *tmp;361 char unit[10];362 int ret, i;363 364 /* create the per-unit directory */365 snprintf(unit, sizeof(unit), "%u", dd->unit);366 ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,367 &simple_dir_operations, dd);368 if (ret) {369 pr_err("create_file(%s) failed: %d\n", unit, ret);370 goto bail;371 }372 373 /* create the files in the new directory */374 ret = create_file("counters", S_IFREG|S_IRUGO, dir, &tmp,375 &cntr_ops[0], dd);376 if (ret) {377 pr_err("create_file(%s/counters) failed: %d\n",378 unit, ret);379 goto bail;380 }381 ret = create_file("counter_names", S_IFREG|S_IRUGO, dir, &tmp,382 &cntr_ops[1], dd);383 if (ret) {384 pr_err("create_file(%s/counter_names) failed: %d\n",385 unit, ret);386 goto bail;387 }388 ret = create_file("portcounter_names", S_IFREG|S_IRUGO, dir, &tmp,389 &portcntr_ops[0], dd);390 if (ret) {391 pr_err("create_file(%s/%s) failed: %d\n",392 unit, "portcounter_names", ret);393 goto bail;394 }395 for (i = 1; i <= dd->num_pports; i++) {396 char fname[24];397 398 sprintf(fname, "port%dcounters", i);399 /* create the files in the new directory */400 ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp,401 &portcntr_ops[i], dd);402 if (ret) {403 pr_err("create_file(%s/%s) failed: %d\n",404 unit, fname, ret);405 goto bail;406 }407 if (!(dd->flags & QIB_HAS_QSFP))408 continue;409 sprintf(fname, "qsfp%d", i);410 ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp,411 &qsfp_ops[i - 1], dd);412 if (ret) {413 pr_err("create_file(%s/%s) failed: %d\n",414 unit, fname, ret);415 goto bail;416 }417 }418 419 ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp,420 &flash_ops, dd);421 if (ret)422 pr_err("create_file(%s/flash) failed: %d\n",423 unit, ret);424bail:425 return ret;426}427 428static int remove_device_files(struct super_block *sb,429 struct qib_devdata *dd)430{431 struct dentry *dir;432 char unit[10];433 434 snprintf(unit, sizeof(unit), "%u", dd->unit);435 dir = lookup_one_len_unlocked(unit, sb->s_root, strlen(unit));436 437 if (IS_ERR(dir)) {438 pr_err("Lookup of %s failed\n", unit);439 return PTR_ERR(dir);440 }441 simple_recursive_removal(dir, NULL);442 dput(dir);443 return 0;444}445 446/*447 * This fills everything in when the fs is mounted, to handle umount/mount448 * after device init. The direct add_cntr_files() call handles adding449 * them from the init code, when the fs is already mounted.450 */451static int qibfs_fill_super(struct super_block *sb, struct fs_context *fc)452{453 struct qib_devdata *dd;454 unsigned long index;455 int ret;456 457 static const struct tree_descr files[] = {458 [2] = {"driver_stats", &driver_ops[0], S_IRUGO},459 [3] = {"driver_stats_names", &driver_ops[1], S_IRUGO},460 {""},461 };462 463 ret = simple_fill_super(sb, QIBFS_MAGIC, files);464 if (ret) {465 pr_err("simple_fill_super failed: %d\n", ret);466 goto bail;467 }468 469 xa_for_each(&qib_dev_table, index, dd) {470 ret = add_cntr_files(sb, dd);471 if (ret)472 goto bail;473 }474 475bail:476 return ret;477}478 479static int qibfs_get_tree(struct fs_context *fc)480{481 int ret = get_tree_single(fc, qibfs_fill_super);482 if (ret == 0)483 qib_super = fc->root->d_sb;484 return ret;485}486 487static const struct fs_context_operations qibfs_context_ops = {488 .get_tree = qibfs_get_tree,489};490 491static int qibfs_init_fs_context(struct fs_context *fc)492{493 fc->ops = &qibfs_context_ops;494 return 0;495}496 497static void qibfs_kill_super(struct super_block *s)498{499 kill_litter_super(s);500 qib_super = NULL;501}502 503int qibfs_add(struct qib_devdata *dd)504{505 int ret;506 507 /*508 * On first unit initialized, qib_super will not yet exist509 * because nobody has yet tried to mount the filesystem, so510 * we can't consider that to be an error; if an error occurs511 * during the mount, that will get a complaint, so this is OK.512 * add_cntr_files() for all units is done at mount from513 * qibfs_fill_super(), so one way or another, everything works.514 */515 if (qib_super == NULL)516 ret = 0;517 else518 ret = add_cntr_files(qib_super, dd);519 return ret;520}521 522int qibfs_remove(struct qib_devdata *dd)523{524 int ret = 0;525 526 if (qib_super)527 ret = remove_device_files(qib_super, dd);528 529 return ret;530}531 532static struct file_system_type qibfs_fs_type = {533 .owner = THIS_MODULE,534 .name = "ipathfs",535 .init_fs_context = qibfs_init_fs_context,536 .kill_sb = qibfs_kill_super,537};538MODULE_ALIAS_FS("ipathfs");539 540int __init qib_init_qibfs(void)541{542 return register_filesystem(&qibfs_fs_type);543}544 545int __exit qib_exit_qibfs(void)546{547 return unregister_filesystem(&qibfs_fs_type);548}549