brintos

brintos / linux-shallow public Read only

0
0
Text · 13.2 KiB · b277910 Raw
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