Path: blob/master/drivers/infiniband/hw/qib/qib_fs.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*/3233#include <linux/module.h>34#include <linux/fs.h>35#include <linux/mount.h>36#include <linux/pagemap.h>37#include <linux/init.h>38#include <linux/namei.h>3940#include "qib.h"4142#define QIBFS_MAGIC 0x726a774344static struct super_block *qib_super;4546#define private2dd(file) ((file)->f_dentry->d_inode->i_private)4748static int qibfs_mknod(struct inode *dir, struct dentry *dentry,49int mode, const struct file_operations *fops,50void *data)51{52int error;53struct inode *inode = new_inode(dir->i_sb);5455if (!inode) {56error = -EPERM;57goto bail;58}5960inode->i_ino = get_next_ino();61inode->i_mode = mode;62inode->i_uid = 0;63inode->i_gid = 0;64inode->i_blocks = 0;65inode->i_atime = CURRENT_TIME;66inode->i_mtime = inode->i_atime;67inode->i_ctime = inode->i_atime;68inode->i_private = data;69if ((mode & S_IFMT) == S_IFDIR) {70inode->i_op = &simple_dir_inode_operations;71inc_nlink(inode);72inc_nlink(dir);73}7475inode->i_fop = fops;7677d_instantiate(dentry, inode);78error = 0;7980bail:81return error;82}8384static int create_file(const char *name, mode_t mode,85struct dentry *parent, struct dentry **dentry,86const struct file_operations *fops, void *data)87{88int error;8990*dentry = NULL;91mutex_lock(&parent->d_inode->i_mutex);92*dentry = lookup_one_len(name, parent, strlen(name));93if (!IS_ERR(*dentry))94error = qibfs_mknod(parent->d_inode, *dentry,95mode, fops, data);96else97error = PTR_ERR(*dentry);98mutex_unlock(&parent->d_inode->i_mutex);99100return error;101}102103static ssize_t driver_stats_read(struct file *file, char __user *buf,104size_t count, loff_t *ppos)105{106return simple_read_from_buffer(buf, count, ppos, &qib_stats,107sizeof qib_stats);108}109110/*111* driver stats field names, one line per stat, single string. Used by112* programs like ipathstats to print the stats in a way which works for113* different versions of drivers, without changing program source.114* if qlogic_ib_stats changes, this needs to change. Names need to be115* 12 chars or less (w/o newline), for proper display by ipathstats utility.116*/117static const char qib_statnames[] =118"KernIntr\n"119"ErrorIntr\n"120"Tx_Errs\n"121"Rcv_Errs\n"122"H/W_Errs\n"123"NoPIOBufs\n"124"CtxtsOpen\n"125"RcvLen_Errs\n"126"EgrBufFull\n"127"EgrHdrFull\n"128;129130static ssize_t driver_names_read(struct file *file, char __user *buf,131size_t count, loff_t *ppos)132{133return simple_read_from_buffer(buf, count, ppos, qib_statnames,134sizeof qib_statnames - 1); /* no null */135}136137static const struct file_operations driver_ops[] = {138{ .read = driver_stats_read, .llseek = generic_file_llseek, },139{ .read = driver_names_read, .llseek = generic_file_llseek, },140};141142/* read the per-device counters */143static ssize_t dev_counters_read(struct file *file, char __user *buf,144size_t count, loff_t *ppos)145{146u64 *counters;147size_t avail;148struct qib_devdata *dd = private2dd(file);149150avail = dd->f_read_cntrs(dd, *ppos, NULL, &counters);151return simple_read_from_buffer(buf, count, ppos, counters, avail);152}153154/* read the per-device counters */155static ssize_t dev_names_read(struct file *file, char __user *buf,156size_t count, loff_t *ppos)157{158char *names;159size_t avail;160struct qib_devdata *dd = private2dd(file);161162avail = dd->f_read_cntrs(dd, *ppos, &names, NULL);163return simple_read_from_buffer(buf, count, ppos, names, avail);164}165166static const struct file_operations cntr_ops[] = {167{ .read = dev_counters_read, .llseek = generic_file_llseek, },168{ .read = dev_names_read, .llseek = generic_file_llseek, },169};170171/*172* Could use file->f_dentry->d_inode->i_ino to figure out which file,173* instead of separate routine for each, but for now, this works...174*/175176/* read the per-port names (same for each port) */177static ssize_t portnames_read(struct file *file, char __user *buf,178size_t count, loff_t *ppos)179{180char *names;181size_t avail;182struct qib_devdata *dd = private2dd(file);183184avail = dd->f_read_portcntrs(dd, *ppos, 0, &names, NULL);185return simple_read_from_buffer(buf, count, ppos, names, avail);186}187188/* read the per-port counters for port 1 (pidx 0) */189static ssize_t portcntrs_1_read(struct file *file, char __user *buf,190size_t count, loff_t *ppos)191{192u64 *counters;193size_t avail;194struct qib_devdata *dd = private2dd(file);195196avail = dd->f_read_portcntrs(dd, *ppos, 0, NULL, &counters);197return simple_read_from_buffer(buf, count, ppos, counters, avail);198}199200/* read the per-port counters for port 2 (pidx 1) */201static ssize_t portcntrs_2_read(struct file *file, char __user *buf,202size_t count, loff_t *ppos)203{204u64 *counters;205size_t avail;206struct qib_devdata *dd = private2dd(file);207208avail = dd->f_read_portcntrs(dd, *ppos, 1, NULL, &counters);209return simple_read_from_buffer(buf, count, ppos, counters, avail);210}211212static const struct file_operations portcntr_ops[] = {213{ .read = portnames_read, .llseek = generic_file_llseek, },214{ .read = portcntrs_1_read, .llseek = generic_file_llseek, },215{ .read = portcntrs_2_read, .llseek = generic_file_llseek, },216};217218/*219* read the per-port QSFP data for port 1 (pidx 0)220*/221static ssize_t qsfp_1_read(struct file *file, char __user *buf,222size_t count, loff_t *ppos)223{224struct qib_devdata *dd = private2dd(file);225char *tmp;226int ret;227228tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);229if (!tmp)230return -ENOMEM;231232ret = qib_qsfp_dump(dd->pport, tmp, PAGE_SIZE);233if (ret > 0)234ret = simple_read_from_buffer(buf, count, ppos, tmp, ret);235kfree(tmp);236return ret;237}238239/*240* read the per-port QSFP data for port 2 (pidx 1)241*/242static ssize_t qsfp_2_read(struct file *file, char __user *buf,243size_t count, loff_t *ppos)244{245struct qib_devdata *dd = private2dd(file);246char *tmp;247int ret;248249if (dd->num_pports < 2)250return -ENODEV;251252tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);253if (!tmp)254return -ENOMEM;255256ret = qib_qsfp_dump(dd->pport + 1, tmp, PAGE_SIZE);257if (ret > 0)258ret = simple_read_from_buffer(buf, count, ppos, tmp, ret);259kfree(tmp);260return ret;261}262263static const struct file_operations qsfp_ops[] = {264{ .read = qsfp_1_read, .llseek = generic_file_llseek, },265{ .read = qsfp_2_read, .llseek = generic_file_llseek, },266};267268static ssize_t flash_read(struct file *file, char __user *buf,269size_t count, loff_t *ppos)270{271struct qib_devdata *dd;272ssize_t ret;273loff_t pos;274char *tmp;275276pos = *ppos;277278if (pos < 0) {279ret = -EINVAL;280goto bail;281}282283if (pos >= sizeof(struct qib_flash)) {284ret = 0;285goto bail;286}287288if (count > sizeof(struct qib_flash) - pos)289count = sizeof(struct qib_flash) - pos;290291tmp = kmalloc(count, GFP_KERNEL);292if (!tmp) {293ret = -ENOMEM;294goto bail;295}296297dd = private2dd(file);298if (qib_eeprom_read(dd, pos, tmp, count)) {299qib_dev_err(dd, "failed to read from flash\n");300ret = -ENXIO;301goto bail_tmp;302}303304if (copy_to_user(buf, tmp, count)) {305ret = -EFAULT;306goto bail_tmp;307}308309*ppos = pos + count;310ret = count;311312bail_tmp:313kfree(tmp);314315bail:316return ret;317}318319static ssize_t flash_write(struct file *file, const char __user *buf,320size_t count, loff_t *ppos)321{322struct qib_devdata *dd;323ssize_t ret;324loff_t pos;325char *tmp;326327pos = *ppos;328329if (pos != 0) {330ret = -EINVAL;331goto bail;332}333334if (count != sizeof(struct qib_flash)) {335ret = -EINVAL;336goto bail;337}338339tmp = kmalloc(count, GFP_KERNEL);340if (!tmp) {341ret = -ENOMEM;342goto bail;343}344345if (copy_from_user(tmp, buf, count)) {346ret = -EFAULT;347goto bail_tmp;348}349350dd = private2dd(file);351if (qib_eeprom_write(dd, pos, tmp, count)) {352ret = -ENXIO;353qib_dev_err(dd, "failed to write to flash\n");354goto bail_tmp;355}356357*ppos = pos + count;358ret = count;359360bail_tmp:361kfree(tmp);362363bail:364return ret;365}366367static const struct file_operations flash_ops = {368.read = flash_read,369.write = flash_write,370.llseek = default_llseek,371};372373static int add_cntr_files(struct super_block *sb, struct qib_devdata *dd)374{375struct dentry *dir, *tmp;376char unit[10];377int ret, i;378379/* create the per-unit directory */380snprintf(unit, sizeof unit, "%u", dd->unit);381ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,382&simple_dir_operations, dd);383if (ret) {384printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret);385goto bail;386}387388/* create the files in the new directory */389ret = create_file("counters", S_IFREG|S_IRUGO, dir, &tmp,390&cntr_ops[0], dd);391if (ret) {392printk(KERN_ERR "create_file(%s/counters) failed: %d\n",393unit, ret);394goto bail;395}396ret = create_file("counter_names", S_IFREG|S_IRUGO, dir, &tmp,397&cntr_ops[1], dd);398if (ret) {399printk(KERN_ERR "create_file(%s/counter_names) failed: %d\n",400unit, ret);401goto bail;402}403ret = create_file("portcounter_names", S_IFREG|S_IRUGO, dir, &tmp,404&portcntr_ops[0], dd);405if (ret) {406printk(KERN_ERR "create_file(%s/%s) failed: %d\n",407unit, "portcounter_names", ret);408goto bail;409}410for (i = 1; i <= dd->num_pports; i++) {411char fname[24];412413sprintf(fname, "port%dcounters", i);414/* create the files in the new directory */415ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp,416&portcntr_ops[i], dd);417if (ret) {418printk(KERN_ERR "create_file(%s/%s) failed: %d\n",419unit, fname, ret);420goto bail;421}422if (!(dd->flags & QIB_HAS_QSFP))423continue;424sprintf(fname, "qsfp%d", i);425ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp,426&qsfp_ops[i - 1], dd);427if (ret) {428printk(KERN_ERR "create_file(%s/%s) failed: %d\n",429unit, fname, ret);430goto bail;431}432}433434ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp,435&flash_ops, dd);436if (ret)437printk(KERN_ERR "create_file(%s/flash) failed: %d\n",438unit, ret);439bail:440return ret;441}442443static int remove_file(struct dentry *parent, char *name)444{445struct dentry *tmp;446int ret;447448tmp = lookup_one_len(name, parent, strlen(name));449450if (IS_ERR(tmp)) {451ret = PTR_ERR(tmp);452goto bail;453}454455spin_lock(&tmp->d_lock);456if (!(d_unhashed(tmp) && tmp->d_inode)) {457dget_dlock(tmp);458__d_drop(tmp);459spin_unlock(&tmp->d_lock);460simple_unlink(parent->d_inode, tmp);461} else {462spin_unlock(&tmp->d_lock);463}464465ret = 0;466bail:467/*468* We don't expect clients to care about the return value, but469* it's there if they need it.470*/471return ret;472}473474static int remove_device_files(struct super_block *sb,475struct qib_devdata *dd)476{477struct dentry *dir, *root;478char unit[10];479int ret, i;480481root = dget(sb->s_root);482mutex_lock(&root->d_inode->i_mutex);483snprintf(unit, sizeof unit, "%u", dd->unit);484dir = lookup_one_len(unit, root, strlen(unit));485486if (IS_ERR(dir)) {487ret = PTR_ERR(dir);488printk(KERN_ERR "Lookup of %s failed\n", unit);489goto bail;490}491492remove_file(dir, "counters");493remove_file(dir, "counter_names");494remove_file(dir, "portcounter_names");495for (i = 0; i < dd->num_pports; i++) {496char fname[24];497498sprintf(fname, "port%dcounters", i + 1);499remove_file(dir, fname);500if (dd->flags & QIB_HAS_QSFP) {501sprintf(fname, "qsfp%d", i + 1);502remove_file(dir, fname);503}504}505remove_file(dir, "flash");506d_delete(dir);507ret = simple_rmdir(root->d_inode, dir);508509bail:510mutex_unlock(&root->d_inode->i_mutex);511dput(root);512return ret;513}514515/*516* This fills everything in when the fs is mounted, to handle umount/mount517* after device init. The direct add_cntr_files() call handles adding518* them from the init code, when the fs is already mounted.519*/520static int qibfs_fill_super(struct super_block *sb, void *data, int silent)521{522struct qib_devdata *dd, *tmp;523unsigned long flags;524int ret;525526static struct tree_descr files[] = {527[2] = {"driver_stats", &driver_ops[0], S_IRUGO},528[3] = {"driver_stats_names", &driver_ops[1], S_IRUGO},529{""},530};531532ret = simple_fill_super(sb, QIBFS_MAGIC, files);533if (ret) {534printk(KERN_ERR "simple_fill_super failed: %d\n", ret);535goto bail;536}537538spin_lock_irqsave(&qib_devs_lock, flags);539540list_for_each_entry_safe(dd, tmp, &qib_dev_list, list) {541spin_unlock_irqrestore(&qib_devs_lock, flags);542ret = add_cntr_files(sb, dd);543if (ret)544goto bail;545spin_lock_irqsave(&qib_devs_lock, flags);546}547548spin_unlock_irqrestore(&qib_devs_lock, flags);549550bail:551return ret;552}553554static struct dentry *qibfs_mount(struct file_system_type *fs_type, int flags,555const char *dev_name, void *data)556{557struct dentry *ret;558ret = mount_single(fs_type, flags, data, qibfs_fill_super);559if (!IS_ERR(ret))560qib_super = ret->d_sb;561return ret;562}563564static void qibfs_kill_super(struct super_block *s)565{566kill_litter_super(s);567qib_super = NULL;568}569570int qibfs_add(struct qib_devdata *dd)571{572int ret;573574/*575* On first unit initialized, qib_super will not yet exist576* because nobody has yet tried to mount the filesystem, so577* we can't consider that to be an error; if an error occurs578* during the mount, that will get a complaint, so this is OK.579* add_cntr_files() for all units is done at mount from580* qibfs_fill_super(), so one way or another, everything works.581*/582if (qib_super == NULL)583ret = 0;584else585ret = add_cntr_files(qib_super, dd);586return ret;587}588589int qibfs_remove(struct qib_devdata *dd)590{591int ret = 0;592593if (qib_super)594ret = remove_device_files(qib_super, dd);595596return ret;597}598599static struct file_system_type qibfs_fs_type = {600.owner = THIS_MODULE,601.name = "ipathfs",602.mount = qibfs_mount,603.kill_sb = qibfs_kill_super,604};605606int __init qib_init_qibfs(void)607{608return register_filesystem(&qibfs_fs_type);609}610611int __exit qib_exit_qibfs(void)612{613return unregister_filesystem(&qibfs_fs_type);614}615616617