ipath_fs.c revision 7dae5bff2e8e4699744e782a6e7605ad18d1240e
13e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan/*
2759d57686dab8169ca68bbf938ce8e965d1e107aBryan O'Sullivan * Copyright (c) 2006 QLogic, Inc. All rights reserved.
33e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * Copyright (c) 2006 PathScale, Inc. All rights reserved.
43e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *
53e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * This software is available to you under a choice of one of two
63e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * licenses.  You may choose to be licensed under the terms of the GNU
73e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * General Public License (GPL) Version 2, available from the file
83e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * COPYING in the main directory of this source tree, or the
93e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * OpenIB.org BSD license below:
103e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *
113e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *     Redistribution and use in source and binary forms, with or
123e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *     without modification, are permitted provided that the following
133e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *     conditions are met:
143e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *
153e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *      - Redistributions of source code must retain the above
163e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *        copyright notice, this list of conditions and the following
173e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *        disclaimer.
183e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *
193e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *      - Redistributions in binary form must reproduce the above
203e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *        copyright notice, this list of conditions and the following
213e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *        disclaimer in the documentation and/or other materials
223e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *        provided with the distribution.
233e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan *
243e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
253e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
263e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
273e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
283e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
293e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
303e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
313e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan * SOFTWARE.
323e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan */
333e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
343e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#include <linux/version.h>
353e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#include <linux/module.h>
363e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#include <linux/fs.h>
373e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#include <linux/mount.h>
383e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#include <linux/pagemap.h>
393e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#include <linux/init.h>
403e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#include <linux/namei.h>
413e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#include <linux/pci.h>
423e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
433e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#include "ipath_kernel.h"
443e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
453e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#define IPATHFS_MAGIC 0x726a77
463e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
473e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic struct super_block *ipath_super;
483e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
493e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic int ipathfs_mknod(struct inode *dir, struct dentry *dentry,
503e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			 int mode, struct file_operations *fops,
513e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			 void *data)
523e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
533e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	int error;
543e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	struct inode *inode = new_inode(dir->i_sb);
553e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
563e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (!inode) {
573e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		error = -EPERM;
583e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
593e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
603e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
613e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	inode->i_mode = mode;
623e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	inode->i_uid = 0;
633e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	inode->i_gid = 0;
643e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	inode->i_blocks = 0;
653e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
668e18e2941c53416aa219708e7dcad21fb4bd6794Theodore Ts'o	inode->i_private = data;
673e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if ((mode & S_IFMT) == S_IFDIR) {
683e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		inode->i_op = &simple_dir_inode_operations;
693e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		inode->i_nlink++;
703e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		dir->i_nlink++;
713e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
723e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
733e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	inode->i_fop = fops;
743e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
753e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	d_instantiate(dentry, inode);
763e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	error = 0;
773e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
783e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanbail:
793e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return error;
803e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
813e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
823e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic int create_file(const char *name, mode_t mode,
833e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		       struct dentry *parent, struct dentry **dentry,
843e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		       struct file_operations *fops, void *data)
853e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
863e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	int error;
873e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
883e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	*dentry = NULL;
893e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	mutex_lock(&parent->d_inode->i_mutex);
903e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	*dentry = lookup_one_len(name, parent, strlen(name));
913e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (!IS_ERR(dentry))
923e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		error = ipathfs_mknod(parent->d_inode, *dentry,
933e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan				      mode, fops, data);
943e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	else
953e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		error = PTR_ERR(dentry);
963e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	mutex_unlock(&parent->d_inode->i_mutex);
973e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
983e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return error;
993e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
1003e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1013e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic ssize_t atomic_stats_read(struct file *file, char __user *buf,
1023e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan				 size_t count, loff_t *ppos)
1033e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
1043e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return simple_read_from_buffer(buf, count, ppos, &ipath_stats,
1053e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan				       sizeof ipath_stats);
1063e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
1073e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1083e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic struct file_operations atomic_stats_ops = {
1093e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	.read = atomic_stats_read,
1103e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan};
1113e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1123e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan#define NUM_COUNTERS sizeof(struct infinipath_counters) / sizeof(u64)
1133e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1143e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic ssize_t atomic_counters_read(struct file *file, char __user *buf,
1153e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan				    size_t count, loff_t *ppos)
1163e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
1173e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	u64 counters[NUM_COUNTERS];
1183e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	u16 i;
1193e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	struct ipath_devdata *dd;
1203e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1218e18e2941c53416aa219708e7dcad21fb4bd6794Theodore Ts'o	dd = file->f_dentry->d_inode->i_private;
1223e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1233e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	for (i = 0; i < NUM_COUNTERS; i++)
1243e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		counters[i] = ipath_snap_cntr(dd, i);
1253e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1263e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return simple_read_from_buffer(buf, count, ppos, counters,
1273e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan				       sizeof counters);
1283e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
1293e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1303e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic struct file_operations atomic_counters_ops = {
1313e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	.read = atomic_counters_read,
1323e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan};
1333e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1343e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic ssize_t atomic_node_info_read(struct file *file, char __user *buf,
1353e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan				     size_t count, loff_t *ppos)
1363e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
1373e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	u32 nodeinfo[10];
1383e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	struct ipath_devdata *dd;
1393e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	u64 guid;
1403e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1418e18e2941c53416aa219708e7dcad21fb4bd6794Theodore Ts'o	dd = file->f_dentry->d_inode->i_private;
1423e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1433e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	guid = be64_to_cpu(dd->ipath_guid);
1443e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1453e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	nodeinfo[0] =			/* BaseVersion is SMA */
1463e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* ClassVersion is SMA */
1473e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		(1 << 8)		/* NodeType  */
1483e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (1 << 0);		/* NumPorts */
1493e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	nodeinfo[1] = (u32) (guid >> 32);
1503e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	nodeinfo[2] = (u32) (guid & 0xffffffff);
1513e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/* PortGUID == SystemImageGUID for us */
1523e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	nodeinfo[3] = nodeinfo[1];
1533e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/* PortGUID == SystemImageGUID for us */
1543e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	nodeinfo[4] = nodeinfo[2];
1553e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/* PortGUID == NodeGUID for us */
1563e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	nodeinfo[5] = nodeinfo[3];
1573e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/* PortGUID == NodeGUID for us */
1583e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	nodeinfo[6] = nodeinfo[4];
1593e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	nodeinfo[7] = (4 << 16) /* we support 4 pkeys */
1603e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (dd->ipath_deviceid << 0);
1613e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/* our chip version as 16 bits major, 16 bits minor */
1623e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	nodeinfo[8] = dd->ipath_minrev | (dd->ipath_majrev << 16);
1633e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	nodeinfo[9] = (dd->ipath_unit << 24) | (dd->ipath_vendorid << 0);
1643e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1653e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return simple_read_from_buffer(buf, count, ppos, nodeinfo,
1663e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan				       sizeof nodeinfo);
1673e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
1683e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1693e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic struct file_operations atomic_node_info_ops = {
1703e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	.read = atomic_node_info_read,
1713e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan};
1723e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1733e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic ssize_t atomic_port_info_read(struct file *file, char __user *buf,
1743e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan				     size_t count, loff_t *ppos)
1753e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
1763e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	u32 portinfo[13];
1773e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	u32 tmp, tmp2;
1783e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	struct ipath_devdata *dd;
1793e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1808e18e2941c53416aa219708e7dcad21fb4bd6794Theodore Ts'o	dd = file->f_dentry->d_inode->i_private;
1813e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1823e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/* so we only initialize non-zero fields. */
1833e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	memset(portinfo, 0, sizeof portinfo);
1843e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1853e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/*
1863e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	 * Notimpl yet M_Key (64)
1873e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	 * Notimpl yet GID (64)
1883e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	 */
1893e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1903e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	portinfo[4] = (dd->ipath_lid << 16);
1913e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1923e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/*
1930fd41363e0785247b7c19127318abc8b5eacc86bBryan O'Sullivan	 * Notimpl yet SMLID.
1940fd41363e0785247b7c19127318abc8b5eacc86bBryan O'Sullivan	 * CapabilityMask is 0, we don't support any of these
1953e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	 * DiagCode is 0; we don't store any diag info for now Notimpl yet
1963e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	 * M_KeyLeasePeriod (we don't support M_Key)
1973e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	 */
1983e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
1993e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/* LocalPortNum is whichever port number they ask for */
2003e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	portinfo[7] = (dd->ipath_unit << 24)
2013e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* LinkWidthEnabled */
2023e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (2 << 16)
2033e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* LinkWidthSupported (really 2, but not IB valid) */
2043e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (3 << 8)
2053e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* LinkWidthActive */
2063e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (2 << 0);
2073e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	tmp = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK;
2083e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	tmp2 = 5;
2093e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (tmp == IPATH_IBSTATE_INIT)
2103e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp = 2;
2113e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	else if (tmp == IPATH_IBSTATE_ARM)
2123e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp = 3;
2133e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	else if (tmp == IPATH_IBSTATE_ACTIVE)
2143e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp = 4;
2153e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	else {
2163e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp = 0;	/* down */
2173e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp2 = tmp & 0xf;
2183e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
2193e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
2203e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	portinfo[8] = (1 << 28)	/* LinkSpeedSupported */
2213e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (tmp << 24)	/* PortState */
2223e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (tmp2 << 20)	/* PortPhysicalState */
2233e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (2 << 16)
2243e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
2253e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* LinkDownDefaultState */
2263e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* M_KeyProtectBits == 0 */
2273e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* NotImpl yet LMC == 0 (we can support all values) */
2283e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (1 << 4)	/* LinkSpeedActive */
2293e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (1 << 0);	/* LinkSpeedEnabled */
2303e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	switch (dd->ipath_ibmtu) {
2313e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	case 4096:
2323e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp = 5;
2333e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		break;
2343e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	case 2048:
2353e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp = 4;
2363e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		break;
2373e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	case 1024:
2383e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp = 3;
2393e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		break;
2403e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	case 512:
2413e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp = 2;
2423e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		break;
2433e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	case 256:
2443e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp = 1;
2453e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		break;
2463e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	default:		/* oops, something is wrong */
2473e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ipath_dbg("Problem, ipath_ibmtu 0x%x not a valid IB MTU, "
2483e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			  "treat as 2048\n", dd->ipath_ibmtu);
2493e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		tmp = 4;
2503e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		break;
2513e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
2523e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	portinfo[9] = (tmp << 28)
2533e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* NeighborMTU */
2543e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* Notimpl MasterSMSL */
2553e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (1 << 20)
2563e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
2573e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* VLCap */
2583e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* Notimpl InitType (actually, an SMA decision) */
2593e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* VLHighLimit is 0 (only one VL) */
2603e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		; /* VLArbitrationHighCap is 0 (only one VL) */
2613e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	portinfo[10] = 	/* VLArbitrationLowCap is 0 (only one VL) */
2623e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* InitTypeReply is SMA decision */
2633e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		(5 << 16)	/* MTUCap 4096 */
2643e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (7 << 13)	/* VLStallCount */
2653e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (0x1f << 8)	/* HOQLife */
2663e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (1 << 4)
2673e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
2683e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* OperationalVLs 0 */
2693e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* PartitionEnforcementInbound */
2703e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* PartitionEnforcementOutbound not enforced */
2713e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* FilterRawinbound not enforced */
2723e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		;		/* FilterRawOutbound not enforced */
2733e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/* M_KeyViolations are not counted by hardware, SMA can count */
2743e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	tmp = ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey);
2753e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/* P_KeyViolations are counted by hardware. */
2763e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	portinfo[11] = ((tmp & 0xffff) << 0);
2773e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	portinfo[12] =
2783e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* Q_KeyViolations are not counted by hardware */
2793e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		(1 << 8)
2803e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
2813e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* GUIDCap */
2823e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* SubnetTimeOut handled by SMA */
2833e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		/* RespTimeValue handled by SMA */
2843e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		;
2853e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	/* LocalPhyErrors are programmed to max */
2863e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	portinfo[12] |= (0xf << 20)
2873e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		| (0xf << 16)   /* OverRunErrors are programmed to max */
2883e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		;
2893e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
2903e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return simple_read_from_buffer(buf, count, ppos, portinfo,
2913e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan				       sizeof portinfo);
2923e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
2933e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
2943e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic struct file_operations atomic_port_info_ops = {
2953e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	.read = atomic_port_info_read,
2963e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan};
2973e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
2983e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic ssize_t flash_read(struct file *file, char __user *buf,
2993e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			  size_t count, loff_t *ppos)
3003e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
3013e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	struct ipath_devdata *dd;
3023e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ssize_t ret;
3033e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	loff_t pos;
3043e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	char *tmp;
3053e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3063e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	pos = *ppos;
3073e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3083e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if ( pos < 0) {
3093e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = -EINVAL;
3103e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
3113e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
3123e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3133e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (pos >= sizeof(struct ipath_flash)) {
3143e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = 0;
3153e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
3163e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
3173e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3183e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (count > sizeof(struct ipath_flash) - pos)
3193e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		count = sizeof(struct ipath_flash) - pos;
3203e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3213e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	tmp = kmalloc(count, GFP_KERNEL);
3223e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (!tmp) {
3233e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = -ENOMEM;
3243e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
3253e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
3263e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3278e18e2941c53416aa219708e7dcad21fb4bd6794Theodore Ts'o	dd = file->f_dentry->d_inode->i_private;
3283e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (ipath_eeprom_read(dd, pos, tmp, count)) {
3293e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ipath_dev_err(dd, "failed to read from flash\n");
3303e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = -ENXIO;
3313e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail_tmp;
3323e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
3333e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3343e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (copy_to_user(buf, tmp, count)) {
3353e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = -EFAULT;
3363e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail_tmp;
3373e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
3383e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3393e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	*ppos = pos + count;
3403e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = count;
3413e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3423e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanbail_tmp:
3433e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	kfree(tmp);
3443e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3453e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanbail:
3463e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return ret;
3473e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
3483e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3493e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic ssize_t flash_write(struct file *file, const char __user *buf,
3503e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			   size_t count, loff_t *ppos)
3513e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
3523e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	struct ipath_devdata *dd;
3533e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ssize_t ret;
3543e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	loff_t pos;
3553e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	char *tmp;
3563e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3573e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	pos = *ppos;
3583e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3597dae5bff2e8e4699744e782a6e7605ad18d1240eBryan O'Sullivan	if (pos != 0) {
3603e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = -EINVAL;
3613e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
3623e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
3633e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3647dae5bff2e8e4699744e782a6e7605ad18d1240eBryan O'Sullivan	if (count != sizeof(struct ipath_flash)) {
3657dae5bff2e8e4699744e782a6e7605ad18d1240eBryan O'Sullivan		ret = -EINVAL;
3663e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
3673e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
3683e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3693e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	tmp = kmalloc(count, GFP_KERNEL);
3703e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (!tmp) {
3713e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = -ENOMEM;
3723e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
3733e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
3743e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3753e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (copy_from_user(tmp, buf, count)) {
3763e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = -EFAULT;
3773e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail_tmp;
3783e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
3793e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3808e18e2941c53416aa219708e7dcad21fb4bd6794Theodore Ts'o	dd = file->f_dentry->d_inode->i_private;
3813e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (ipath_eeprom_write(dd, pos, tmp, count)) {
3823e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = -ENXIO;
3833e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ipath_dev_err(dd, "failed to write to flash\n");
3843e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail_tmp;
3853e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
3863e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3873e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	*ppos = pos + count;
3883e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = count;
3893e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3903e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanbail_tmp:
3913e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	kfree(tmp);
3923e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3933e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanbail:
3943e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return ret;
3953e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
3963e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
3973e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic struct file_operations flash_ops = {
3983e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	.read = flash_read,
3993e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	.write = flash_write,
4003e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan};
4013e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4023e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic int create_device_files(struct super_block *sb,
4033e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			       struct ipath_devdata *dd)
4043e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
4053e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	struct dentry *dir, *tmp;
4063e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	char unit[10];
4073e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	int ret;
4083e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4093e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
4103e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
4113e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			  (struct file_operations *) &simple_dir_operations,
4123e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			  dd);
4133e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (ret) {
4143e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret);
4153e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
4163e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
4173e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4183e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = create_file("atomic_counters", S_IFREG|S_IRUGO, dir, &tmp,
4193e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			  &atomic_counters_ops, dd);
4203e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (ret) {
4213e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		printk(KERN_ERR "create_file(%s/atomic_counters) "
4223e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		       "failed: %d\n", unit, ret);
4233e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
4243e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
4253e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4263e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = create_file("node_info", S_IFREG|S_IRUGO, dir, &tmp,
4273e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			  &atomic_node_info_ops, dd);
4283e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (ret) {
4293e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		printk(KERN_ERR "create_file(%s/node_info) "
4303e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		       "failed: %d\n", unit, ret);
4313e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
4323e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
4333e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4343e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = create_file("port_info", S_IFREG|S_IRUGO, dir, &tmp,
4353e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			  &atomic_port_info_ops, dd);
4363e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (ret) {
4373e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		printk(KERN_ERR "create_file(%s/port_info) "
4383e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		       "failed: %d\n", unit, ret);
4393e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
4403e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
4413e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4423e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp,
4433e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			  &flash_ops, dd);
4443e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (ret) {
4453e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		printk(KERN_ERR "create_file(%s/flash) "
4463e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		       "failed: %d\n", unit, ret);
4473e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
4483e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
4493e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4503e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanbail:
4513e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return ret;
4523e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
4533e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4543e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic void remove_file(struct dentry *parent, char *name)
4553e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
4563e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	struct dentry *tmp;
4573e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4583e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	tmp = lookup_one_len(name, parent, strlen(name));
4593e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4603e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	spin_lock(&dcache_lock);
4613e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	spin_lock(&tmp->d_lock);
4623e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (!(d_unhashed(tmp) && tmp->d_inode)) {
4633e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		dget_locked(tmp);
4643e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		__d_drop(tmp);
4653e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		spin_unlock(&tmp->d_lock);
4663e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		spin_unlock(&dcache_lock);
4673e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		simple_unlink(parent->d_inode, tmp);
4683e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	} else {
4693e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		spin_unlock(&tmp->d_lock);
4703e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		spin_unlock(&dcache_lock);
4713e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
4723e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
4733e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4743e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic int remove_device_files(struct super_block *sb,
4753e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			       struct ipath_devdata *dd)
4763e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
4773e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	struct dentry *dir, *root;
4783e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	char unit[10];
4793e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	int ret;
4803e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4813e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	root = dget(sb->s_root);
4823e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	mutex_lock(&root->d_inode->i_mutex);
4833e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
4843e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	dir = lookup_one_len(unit, root, strlen(unit));
4853e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4863e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (IS_ERR(dir)) {
4873e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = PTR_ERR(dir);
4883e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		printk(KERN_ERR "Lookup of %s failed\n", unit);
4893e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
4903e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
4913e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4923e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	remove_file(dir, "flash");
4933e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	remove_file(dir, "port_info");
4943e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	remove_file(dir, "node_info");
4953e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	remove_file(dir, "atomic_counters");
4963e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	d_delete(dir);
4973e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = simple_rmdir(root->d_inode, dir);
4983e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
4993e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanbail:
5003e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	mutex_unlock(&root->d_inode->i_mutex);
5013e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	dput(root);
5023e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return ret;
5033e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
5043e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5053e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic int ipathfs_fill_super(struct super_block *sb, void *data,
5063e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			      int silent)
5073e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
5083e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	struct ipath_devdata *dd, *tmp;
5093e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	unsigned long flags;
5103e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	int ret;
5113e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5123e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	static struct tree_descr files[] = {
5133e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		[1] = {"atomic_stats", &atomic_stats_ops, S_IRUGO},
5143e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		{""},
5153e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	};
5163e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5173e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = simple_fill_super(sb, IPATHFS_MAGIC, files);
5183e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (ret) {
5193e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		printk(KERN_ERR "simple_fill_super failed: %d\n", ret);
5203e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
5213e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
5223e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5233e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	spin_lock_irqsave(&ipath_devs_lock, flags);
5243e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5253e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
5263e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		spin_unlock_irqrestore(&ipath_devs_lock, flags);
5273e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = create_device_files(sb, dd);
5283e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		if (ret) {
5293e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			deactivate_super(sb);
5303e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan			goto bail;
5313e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		}
5323e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		spin_lock_irqsave(&ipath_devs_lock, flags);
5333e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
5343e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5353e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	spin_unlock_irqrestore(&ipath_devs_lock, flags);
5363e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5373e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanbail:
5383e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return ret;
5393e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
5403e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
541454e2398be9b9fa30433fccc548db34d19aa9958David Howellsstatic int ipathfs_get_sb(struct file_system_type *fs_type, int flags,
542454e2398be9b9fa30433fccc548db34d19aa9958David Howells			const char *dev_name, void *data, struct vfsmount *mnt)
5433e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
544454e2398be9b9fa30433fccc548db34d19aa9958David Howells	int ret = get_sb_single(fs_type, flags, data,
545454e2398be9b9fa30433fccc548db34d19aa9958David Howells				    ipathfs_fill_super, mnt);
546454e2398be9b9fa30433fccc548db34d19aa9958David Howells	if (ret >= 0)
547454e2398be9b9fa30433fccc548db34d19aa9958David Howells		ipath_super = mnt->mnt_sb;
548454e2398be9b9fa30433fccc548db34d19aa9958David Howells	return ret;
5493e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
5503e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5513e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic void ipathfs_kill_super(struct super_block *s)
5523e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
5533e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	kill_litter_super(s);
5543e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ipath_super = NULL;
5553e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
5563e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5573e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanint ipathfs_add_device(struct ipath_devdata *dd)
5583e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
5593e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	int ret;
5603e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5613e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (ipath_super == NULL) {
5623e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = 0;
5633e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
5643e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
5653e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5663e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = create_device_files(ipath_super, dd);
5673e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5683e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanbail:
5693e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return ret;
5703e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
5713e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5723e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanint ipathfs_remove_device(struct ipath_devdata *dd)
5733e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
5743e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	int ret;
5753e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5763e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	if (ipath_super == NULL) {
5773e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		ret = 0;
5783e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan		goto bail;
5793e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	}
5803e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5813e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	ret = remove_device_files(ipath_super, dd);
5823e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5833e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanbail:
5843e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return ret;
5853e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
5863e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5873e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanstatic struct file_system_type ipathfs_fs_type = {
5883e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	.owner =	THIS_MODULE,
5893e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	.name =		"ipathfs",
5903e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	.get_sb =	ipathfs_get_sb,
5913e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	.kill_sb =	ipathfs_kill_super,
5923e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan};
5933e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5943e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanint __init ipath_init_ipathfs(void)
5953e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
5963e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	return register_filesystem(&ipathfs_fs_type);
5973e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
5983e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan
5993e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivanvoid __exit ipath_exit_ipathfs(void)
6003e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan{
6013e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan	unregister_filesystem(&ipathfs_fs_type);
6023e9b4a5eb4ae4936feeea256c0105e078c7702cdBryan O'Sullivan}
603