1f931551bSRalph Campbell /* 27fac3301SMike Marciniszyn * Copyright (c) 2012 Intel Corporation. All rights reserved. 37fac3301SMike Marciniszyn * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. 4f931551bSRalph Campbell * Copyright (c) 2006 PathScale, Inc. All rights reserved. 5f931551bSRalph Campbell * 6f931551bSRalph Campbell * This software is available to you under a choice of one of two 7f931551bSRalph Campbell * licenses. You may choose to be licensed under the terms of the GNU 8f931551bSRalph Campbell * General Public License (GPL) Version 2, available from the file 9f931551bSRalph Campbell * COPYING in the main directory of this source tree, or the 10f931551bSRalph Campbell * OpenIB.org BSD license below: 11f931551bSRalph Campbell * 12f931551bSRalph Campbell * Redistribution and use in source and binary forms, with or 13f931551bSRalph Campbell * without modification, are permitted provided that the following 14f931551bSRalph Campbell * conditions are met: 15f931551bSRalph Campbell * 16f931551bSRalph Campbell * - Redistributions of source code must retain the above 17f931551bSRalph Campbell * copyright notice, this list of conditions and the following 18f931551bSRalph Campbell * disclaimer. 19f931551bSRalph Campbell * 20f931551bSRalph Campbell * - Redistributions in binary form must reproduce the above 21f931551bSRalph Campbell * copyright notice, this list of conditions and the following 22f931551bSRalph Campbell * disclaimer in the documentation and/or other materials 23f931551bSRalph Campbell * provided with the distribution. 24f931551bSRalph Campbell * 25f931551bSRalph Campbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26f931551bSRalph Campbell * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27f931551bSRalph Campbell * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28f931551bSRalph Campbell * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29f931551bSRalph Campbell * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30f931551bSRalph Campbell * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31f931551bSRalph Campbell * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32f931551bSRalph Campbell * SOFTWARE. 33f931551bSRalph Campbell */ 34f931551bSRalph Campbell 35f931551bSRalph Campbell #include <linux/module.h> 36f931551bSRalph Campbell #include <linux/fs.h> 37f931551bSRalph Campbell #include <linux/mount.h> 38f931551bSRalph Campbell #include <linux/pagemap.h> 39f931551bSRalph Campbell #include <linux/init.h> 40f931551bSRalph Campbell #include <linux/namei.h> 41f931551bSRalph Campbell 42f931551bSRalph Campbell #include "qib.h" 43f931551bSRalph Campbell 44f931551bSRalph Campbell #define QIBFS_MAGIC 0x726a77 45f931551bSRalph Campbell 46f931551bSRalph Campbell static struct super_block *qib_super; 47f931551bSRalph Campbell 48496ad9aaSAl Viro #define private2dd(file) (file_inode(file)->i_private) 49f931551bSRalph Campbell 50f931551bSRalph Campbell static int qibfs_mknod(struct inode *dir, struct dentry *dentry, 51f9ec8006SAl Viro umode_t mode, const struct file_operations *fops, 52f931551bSRalph Campbell void *data) 53f931551bSRalph Campbell { 54f931551bSRalph Campbell int error; 55f931551bSRalph Campbell struct inode *inode = new_inode(dir->i_sb); 56f931551bSRalph Campbell 57f931551bSRalph Campbell if (!inode) { 58f931551bSRalph Campbell error = -EPERM; 59f931551bSRalph Campbell goto bail; 60f931551bSRalph Campbell } 61f931551bSRalph Campbell 6285fe4025SChristoph Hellwig inode->i_ino = get_next_ino(); 63f931551bSRalph Campbell inode->i_mode = mode; 64d03ca582SEric W. Biederman inode->i_uid = GLOBAL_ROOT_UID; 65d03ca582SEric W. Biederman inode->i_gid = GLOBAL_ROOT_GID; 66f931551bSRalph Campbell inode->i_blocks = 0; 67f931551bSRalph Campbell inode->i_atime = CURRENT_TIME; 68f931551bSRalph Campbell inode->i_mtime = inode->i_atime; 69f931551bSRalph Campbell inode->i_ctime = inode->i_atime; 70f931551bSRalph Campbell inode->i_private = data; 71f9ec8006SAl Viro if (S_ISDIR(mode)) { 72f931551bSRalph Campbell inode->i_op = &simple_dir_inode_operations; 73f931551bSRalph Campbell inc_nlink(inode); 74f931551bSRalph Campbell inc_nlink(dir); 75f931551bSRalph Campbell } 76f931551bSRalph Campbell 77f931551bSRalph Campbell inode->i_fop = fops; 78f931551bSRalph Campbell 79f931551bSRalph Campbell d_instantiate(dentry, inode); 80f931551bSRalph Campbell error = 0; 81f931551bSRalph Campbell 82f931551bSRalph Campbell bail: 83f931551bSRalph Campbell return error; 84f931551bSRalph Campbell } 85f931551bSRalph Campbell 86f9ec8006SAl Viro static int create_file(const char *name, umode_t mode, 87f931551bSRalph Campbell struct dentry *parent, struct dentry **dentry, 88f931551bSRalph Campbell const struct file_operations *fops, void *data) 89f931551bSRalph Campbell { 90f931551bSRalph Campbell int error; 91f931551bSRalph Campbell 92f931551bSRalph Campbell *dentry = NULL; 93f931551bSRalph Campbell mutex_lock(&parent->d_inode->i_mutex); 94f931551bSRalph Campbell *dentry = lookup_one_len(name, parent, strlen(name)); 95f931551bSRalph Campbell if (!IS_ERR(*dentry)) 96f931551bSRalph Campbell error = qibfs_mknod(parent->d_inode, *dentry, 97f931551bSRalph Campbell mode, fops, data); 98f931551bSRalph Campbell else 99f931551bSRalph Campbell error = PTR_ERR(*dentry); 100f931551bSRalph Campbell mutex_unlock(&parent->d_inode->i_mutex); 101f931551bSRalph Campbell 102f931551bSRalph Campbell return error; 103f931551bSRalph Campbell } 104f931551bSRalph Campbell 105f931551bSRalph Campbell static ssize_t driver_stats_read(struct file *file, char __user *buf, 106f931551bSRalph Campbell size_t count, loff_t *ppos) 107f931551bSRalph Campbell { 1081ed88dd7SMike Marciniszyn qib_stats.sps_ints = qib_sps_ints(); 109f931551bSRalph Campbell return simple_read_from_buffer(buf, count, ppos, &qib_stats, 110f931551bSRalph Campbell sizeof qib_stats); 111f931551bSRalph Campbell } 112f931551bSRalph Campbell 113f931551bSRalph Campbell /* 114f931551bSRalph Campbell * driver stats field names, one line per stat, single string. Used by 115f931551bSRalph Campbell * programs like ipathstats to print the stats in a way which works for 116f931551bSRalph Campbell * different versions of drivers, without changing program source. 117f931551bSRalph Campbell * if qlogic_ib_stats changes, this needs to change. Names need to be 118f931551bSRalph Campbell * 12 chars or less (w/o newline), for proper display by ipathstats utility. 119f931551bSRalph Campbell */ 120f931551bSRalph Campbell static const char qib_statnames[] = 121f931551bSRalph Campbell "KernIntr\n" 122f931551bSRalph Campbell "ErrorIntr\n" 123f931551bSRalph Campbell "Tx_Errs\n" 124f931551bSRalph Campbell "Rcv_Errs\n" 125f931551bSRalph Campbell "H/W_Errs\n" 126f931551bSRalph Campbell "NoPIOBufs\n" 127f931551bSRalph Campbell "CtxtsOpen\n" 128f931551bSRalph Campbell "RcvLen_Errs\n" 129f931551bSRalph Campbell "EgrBufFull\n" 130f931551bSRalph Campbell "EgrHdrFull\n" 131f931551bSRalph Campbell ; 132f931551bSRalph Campbell 133f931551bSRalph Campbell static ssize_t driver_names_read(struct file *file, char __user *buf, 134f931551bSRalph Campbell size_t count, loff_t *ppos) 135f931551bSRalph Campbell { 136f931551bSRalph Campbell return simple_read_from_buffer(buf, count, ppos, qib_statnames, 137f931551bSRalph Campbell sizeof qib_statnames - 1); /* no null */ 138f931551bSRalph Campbell } 139f931551bSRalph Campbell 140f931551bSRalph Campbell static const struct file_operations driver_ops[] = { 141dd378c21SArnd Bergmann { .read = driver_stats_read, .llseek = generic_file_llseek, }, 142dd378c21SArnd Bergmann { .read = driver_names_read, .llseek = generic_file_llseek, }, 143f931551bSRalph Campbell }; 144f931551bSRalph Campbell 145f931551bSRalph Campbell /* read the per-device counters */ 146f931551bSRalph Campbell static ssize_t dev_counters_read(struct file *file, char __user *buf, 147f931551bSRalph Campbell size_t count, loff_t *ppos) 148f931551bSRalph Campbell { 149f931551bSRalph Campbell u64 *counters; 150f27ec1d6SRoland Dreier size_t avail; 151f931551bSRalph Campbell struct qib_devdata *dd = private2dd(file); 152f931551bSRalph Campbell 153f27ec1d6SRoland Dreier avail = dd->f_read_cntrs(dd, *ppos, NULL, &counters); 154f27ec1d6SRoland Dreier return simple_read_from_buffer(buf, count, ppos, counters, avail); 155f931551bSRalph Campbell } 156f931551bSRalph Campbell 157f931551bSRalph Campbell /* read the per-device counters */ 158f931551bSRalph Campbell static ssize_t dev_names_read(struct file *file, char __user *buf, 159f931551bSRalph Campbell size_t count, loff_t *ppos) 160f931551bSRalph Campbell { 161f931551bSRalph Campbell char *names; 162f27ec1d6SRoland Dreier size_t avail; 163f931551bSRalph Campbell struct qib_devdata *dd = private2dd(file); 164f931551bSRalph Campbell 165f27ec1d6SRoland Dreier avail = dd->f_read_cntrs(dd, *ppos, &names, NULL); 166f27ec1d6SRoland Dreier return simple_read_from_buffer(buf, count, ppos, names, avail); 167f931551bSRalph Campbell } 168f931551bSRalph Campbell 169f931551bSRalph Campbell static const struct file_operations cntr_ops[] = { 170dd378c21SArnd Bergmann { .read = dev_counters_read, .llseek = generic_file_llseek, }, 171dd378c21SArnd Bergmann { .read = dev_names_read, .llseek = generic_file_llseek, }, 172f931551bSRalph Campbell }; 173f931551bSRalph Campbell 174f931551bSRalph Campbell /* 175496ad9aaSAl Viro * Could use file_inode(file)->i_ino to figure out which file, 176f931551bSRalph Campbell * instead of separate routine for each, but for now, this works... 177f931551bSRalph Campbell */ 178f931551bSRalph Campbell 179f931551bSRalph Campbell /* read the per-port names (same for each port) */ 180f931551bSRalph Campbell static ssize_t portnames_read(struct file *file, char __user *buf, 181f931551bSRalph Campbell size_t count, loff_t *ppos) 182f931551bSRalph Campbell { 183f931551bSRalph Campbell char *names; 184f27ec1d6SRoland Dreier size_t avail; 185f931551bSRalph Campbell struct qib_devdata *dd = private2dd(file); 186f931551bSRalph Campbell 187f27ec1d6SRoland Dreier avail = dd->f_read_portcntrs(dd, *ppos, 0, &names, NULL); 188f27ec1d6SRoland Dreier return simple_read_from_buffer(buf, count, ppos, names, avail); 189f931551bSRalph Campbell } 190f931551bSRalph Campbell 191f931551bSRalph Campbell /* read the per-port counters for port 1 (pidx 0) */ 192f931551bSRalph Campbell static ssize_t portcntrs_1_read(struct file *file, char __user *buf, 193f931551bSRalph Campbell size_t count, loff_t *ppos) 194f931551bSRalph Campbell { 195f931551bSRalph Campbell u64 *counters; 196f27ec1d6SRoland Dreier size_t avail; 197f931551bSRalph Campbell struct qib_devdata *dd = private2dd(file); 198f931551bSRalph Campbell 199f27ec1d6SRoland Dreier avail = dd->f_read_portcntrs(dd, *ppos, 0, NULL, &counters); 200f27ec1d6SRoland Dreier return simple_read_from_buffer(buf, count, ppos, counters, avail); 201f931551bSRalph Campbell } 202f931551bSRalph Campbell 203f931551bSRalph Campbell /* read the per-port counters for port 2 (pidx 1) */ 204f931551bSRalph Campbell static ssize_t portcntrs_2_read(struct file *file, char __user *buf, 205f931551bSRalph Campbell size_t count, loff_t *ppos) 206f931551bSRalph Campbell { 207f931551bSRalph Campbell u64 *counters; 208f27ec1d6SRoland Dreier size_t avail; 209f931551bSRalph Campbell struct qib_devdata *dd = private2dd(file); 210f931551bSRalph Campbell 211f27ec1d6SRoland Dreier avail = dd->f_read_portcntrs(dd, *ppos, 1, NULL, &counters); 212f27ec1d6SRoland Dreier return simple_read_from_buffer(buf, count, ppos, counters, avail); 213f931551bSRalph Campbell } 214f931551bSRalph Campbell 215f931551bSRalph Campbell static const struct file_operations portcntr_ops[] = { 216dd378c21SArnd Bergmann { .read = portnames_read, .llseek = generic_file_llseek, }, 217dd378c21SArnd Bergmann { .read = portcntrs_1_read, .llseek = generic_file_llseek, }, 218dd378c21SArnd Bergmann { .read = portcntrs_2_read, .llseek = generic_file_llseek, }, 219f931551bSRalph Campbell }; 220f931551bSRalph Campbell 221f931551bSRalph Campbell /* 222f931551bSRalph Campbell * read the per-port QSFP data for port 1 (pidx 0) 223f931551bSRalph Campbell */ 224f931551bSRalph Campbell static ssize_t qsfp_1_read(struct file *file, char __user *buf, 225f931551bSRalph Campbell size_t count, loff_t *ppos) 226f931551bSRalph Campbell { 227f931551bSRalph Campbell struct qib_devdata *dd = private2dd(file); 228f931551bSRalph Campbell char *tmp; 229f931551bSRalph Campbell int ret; 230f931551bSRalph Campbell 231f931551bSRalph Campbell tmp = kmalloc(PAGE_SIZE, GFP_KERNEL); 232f931551bSRalph Campbell if (!tmp) 233f931551bSRalph Campbell return -ENOMEM; 234f931551bSRalph Campbell 235f931551bSRalph Campbell ret = qib_qsfp_dump(dd->pport, tmp, PAGE_SIZE); 236f931551bSRalph Campbell if (ret > 0) 237f931551bSRalph Campbell ret = simple_read_from_buffer(buf, count, ppos, tmp, ret); 238f931551bSRalph Campbell kfree(tmp); 239f931551bSRalph Campbell return ret; 240f931551bSRalph Campbell } 241f931551bSRalph Campbell 242f931551bSRalph Campbell /* 243f931551bSRalph Campbell * read the per-port QSFP data for port 2 (pidx 1) 244f931551bSRalph Campbell */ 245f931551bSRalph Campbell static ssize_t qsfp_2_read(struct file *file, char __user *buf, 246f931551bSRalph Campbell size_t count, loff_t *ppos) 247f931551bSRalph Campbell { 248f931551bSRalph Campbell struct qib_devdata *dd = private2dd(file); 249f931551bSRalph Campbell char *tmp; 250f931551bSRalph Campbell int ret; 251f931551bSRalph Campbell 252f931551bSRalph Campbell if (dd->num_pports < 2) 253f931551bSRalph Campbell return -ENODEV; 254f931551bSRalph Campbell 255f931551bSRalph Campbell tmp = kmalloc(PAGE_SIZE, GFP_KERNEL); 256f931551bSRalph Campbell if (!tmp) 257f931551bSRalph Campbell return -ENOMEM; 258f931551bSRalph Campbell 259f931551bSRalph Campbell ret = qib_qsfp_dump(dd->pport + 1, tmp, PAGE_SIZE); 260f931551bSRalph Campbell if (ret > 0) 261f931551bSRalph Campbell ret = simple_read_from_buffer(buf, count, ppos, tmp, ret); 262f931551bSRalph Campbell kfree(tmp); 263f931551bSRalph Campbell return ret; 264f931551bSRalph Campbell } 265f931551bSRalph Campbell 266f931551bSRalph Campbell static const struct file_operations qsfp_ops[] = { 267dd378c21SArnd Bergmann { .read = qsfp_1_read, .llseek = generic_file_llseek, }, 268dd378c21SArnd Bergmann { .read = qsfp_2_read, .llseek = generic_file_llseek, }, 269f931551bSRalph Campbell }; 270f931551bSRalph Campbell 271f931551bSRalph Campbell static ssize_t flash_read(struct file *file, char __user *buf, 272f931551bSRalph Campbell size_t count, loff_t *ppos) 273f931551bSRalph Campbell { 274f931551bSRalph Campbell struct qib_devdata *dd; 275f931551bSRalph Campbell ssize_t ret; 276f931551bSRalph Campbell loff_t pos; 277f931551bSRalph Campbell char *tmp; 278f931551bSRalph Campbell 279f931551bSRalph Campbell pos = *ppos; 280f931551bSRalph Campbell 281f931551bSRalph Campbell if (pos < 0) { 282f931551bSRalph Campbell ret = -EINVAL; 283f931551bSRalph Campbell goto bail; 284f931551bSRalph Campbell } 285f931551bSRalph Campbell 286f931551bSRalph Campbell if (pos >= sizeof(struct qib_flash)) { 287f931551bSRalph Campbell ret = 0; 288f931551bSRalph Campbell goto bail; 289f931551bSRalph Campbell } 290f931551bSRalph Campbell 291f931551bSRalph Campbell if (count > sizeof(struct qib_flash) - pos) 292f931551bSRalph Campbell count = sizeof(struct qib_flash) - pos; 293f931551bSRalph Campbell 294f931551bSRalph Campbell tmp = kmalloc(count, GFP_KERNEL); 295f931551bSRalph Campbell if (!tmp) { 296f931551bSRalph Campbell ret = -ENOMEM; 297f931551bSRalph Campbell goto bail; 298f931551bSRalph Campbell } 299f931551bSRalph Campbell 300f931551bSRalph Campbell dd = private2dd(file); 301f931551bSRalph Campbell if (qib_eeprom_read(dd, pos, tmp, count)) { 302f931551bSRalph Campbell qib_dev_err(dd, "failed to read from flash\n"); 303f931551bSRalph Campbell ret = -ENXIO; 304f931551bSRalph Campbell goto bail_tmp; 305f931551bSRalph Campbell } 306f931551bSRalph Campbell 307f931551bSRalph Campbell if (copy_to_user(buf, tmp, count)) { 308f931551bSRalph Campbell ret = -EFAULT; 309f931551bSRalph Campbell goto bail_tmp; 310f931551bSRalph Campbell } 311f931551bSRalph Campbell 312f931551bSRalph Campbell *ppos = pos + count; 313f931551bSRalph Campbell ret = count; 314f931551bSRalph Campbell 315f931551bSRalph Campbell bail_tmp: 316f931551bSRalph Campbell kfree(tmp); 317f931551bSRalph Campbell 318f931551bSRalph Campbell bail: 319f931551bSRalph Campbell return ret; 320f931551bSRalph Campbell } 321f931551bSRalph Campbell 322f931551bSRalph Campbell static ssize_t flash_write(struct file *file, const char __user *buf, 323f931551bSRalph Campbell size_t count, loff_t *ppos) 324f931551bSRalph Campbell { 325f931551bSRalph Campbell struct qib_devdata *dd; 326f931551bSRalph Campbell ssize_t ret; 327f931551bSRalph Campbell loff_t pos; 328f931551bSRalph Campbell char *tmp; 329f931551bSRalph Campbell 330f931551bSRalph Campbell pos = *ppos; 331f931551bSRalph Campbell 332f931551bSRalph Campbell if (pos != 0) { 333f931551bSRalph Campbell ret = -EINVAL; 334f931551bSRalph Campbell goto bail; 335f931551bSRalph Campbell } 336f931551bSRalph Campbell 337f931551bSRalph Campbell if (count != sizeof(struct qib_flash)) { 338f931551bSRalph Campbell ret = -EINVAL; 339f931551bSRalph Campbell goto bail; 340f931551bSRalph Campbell } 341f931551bSRalph Campbell 342f931551bSRalph Campbell tmp = kmalloc(count, GFP_KERNEL); 343f931551bSRalph Campbell if (!tmp) { 344f931551bSRalph Campbell ret = -ENOMEM; 345f931551bSRalph Campbell goto bail; 346f931551bSRalph Campbell } 347f931551bSRalph Campbell 348f931551bSRalph Campbell if (copy_from_user(tmp, buf, count)) { 349f931551bSRalph Campbell ret = -EFAULT; 350f931551bSRalph Campbell goto bail_tmp; 351f931551bSRalph Campbell } 352f931551bSRalph Campbell 353f931551bSRalph Campbell dd = private2dd(file); 354f931551bSRalph Campbell if (qib_eeprom_write(dd, pos, tmp, count)) { 355f931551bSRalph Campbell ret = -ENXIO; 356f931551bSRalph Campbell qib_dev_err(dd, "failed to write to flash\n"); 357f931551bSRalph Campbell goto bail_tmp; 358f931551bSRalph Campbell } 359f931551bSRalph Campbell 360f931551bSRalph Campbell *ppos = pos + count; 361f931551bSRalph Campbell ret = count; 362f931551bSRalph Campbell 363f931551bSRalph Campbell bail_tmp: 364f931551bSRalph Campbell kfree(tmp); 365f931551bSRalph Campbell 366f931551bSRalph Campbell bail: 367f931551bSRalph Campbell return ret; 368f931551bSRalph Campbell } 369f931551bSRalph Campbell 370f931551bSRalph Campbell static const struct file_operations flash_ops = { 371f931551bSRalph Campbell .read = flash_read, 372f931551bSRalph Campbell .write = flash_write, 3736038f373SArnd Bergmann .llseek = default_llseek, 374f931551bSRalph Campbell }; 375f931551bSRalph Campbell 376f931551bSRalph Campbell static int add_cntr_files(struct super_block *sb, struct qib_devdata *dd) 377f931551bSRalph Campbell { 378f931551bSRalph Campbell struct dentry *dir, *tmp; 379f931551bSRalph Campbell char unit[10]; 380f931551bSRalph Campbell int ret, i; 381f931551bSRalph Campbell 382f931551bSRalph Campbell /* create the per-unit directory */ 383f931551bSRalph Campbell snprintf(unit, sizeof unit, "%u", dd->unit); 384f931551bSRalph Campbell ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir, 385f931551bSRalph Campbell &simple_dir_operations, dd); 386f931551bSRalph Campbell if (ret) { 3877fac3301SMike Marciniszyn pr_err("create_file(%s) failed: %d\n", unit, ret); 388f931551bSRalph Campbell goto bail; 389f931551bSRalph Campbell } 390f931551bSRalph Campbell 391f931551bSRalph Campbell /* create the files in the new directory */ 392f931551bSRalph Campbell ret = create_file("counters", S_IFREG|S_IRUGO, dir, &tmp, 393f931551bSRalph Campbell &cntr_ops[0], dd); 394f931551bSRalph Campbell if (ret) { 3957fac3301SMike Marciniszyn pr_err("create_file(%s/counters) failed: %d\n", 396f931551bSRalph Campbell unit, ret); 397f931551bSRalph Campbell goto bail; 398f931551bSRalph Campbell } 399f931551bSRalph Campbell ret = create_file("counter_names", S_IFREG|S_IRUGO, dir, &tmp, 400f931551bSRalph Campbell &cntr_ops[1], dd); 401f931551bSRalph Campbell if (ret) { 4027fac3301SMike Marciniszyn pr_err("create_file(%s/counter_names) failed: %d\n", 403f931551bSRalph Campbell unit, ret); 404f931551bSRalph Campbell goto bail; 405f931551bSRalph Campbell } 406f931551bSRalph Campbell ret = create_file("portcounter_names", S_IFREG|S_IRUGO, dir, &tmp, 407f931551bSRalph Campbell &portcntr_ops[0], dd); 408f931551bSRalph Campbell if (ret) { 4097fac3301SMike Marciniszyn pr_err("create_file(%s/%s) failed: %d\n", 410f931551bSRalph Campbell unit, "portcounter_names", ret); 411f931551bSRalph Campbell goto bail; 412f931551bSRalph Campbell } 413f931551bSRalph Campbell for (i = 1; i <= dd->num_pports; i++) { 414f931551bSRalph Campbell char fname[24]; 415f931551bSRalph Campbell 416f931551bSRalph Campbell sprintf(fname, "port%dcounters", i); 417f931551bSRalph Campbell /* create the files in the new directory */ 418f931551bSRalph Campbell ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp, 419f931551bSRalph Campbell &portcntr_ops[i], dd); 420f931551bSRalph Campbell if (ret) { 4217fac3301SMike Marciniszyn pr_err("create_file(%s/%s) failed: %d\n", 422f931551bSRalph Campbell unit, fname, ret); 423f931551bSRalph Campbell goto bail; 424f931551bSRalph Campbell } 425f931551bSRalph Campbell if (!(dd->flags & QIB_HAS_QSFP)) 426f931551bSRalph Campbell continue; 427f931551bSRalph Campbell sprintf(fname, "qsfp%d", i); 428f931551bSRalph Campbell ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp, 429f931551bSRalph Campbell &qsfp_ops[i - 1], dd); 430f931551bSRalph Campbell if (ret) { 4317fac3301SMike Marciniszyn pr_err("create_file(%s/%s) failed: %d\n", 432f931551bSRalph Campbell unit, fname, ret); 433f931551bSRalph Campbell goto bail; 434f931551bSRalph Campbell } 435f931551bSRalph Campbell } 436f931551bSRalph Campbell 437f931551bSRalph Campbell ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp, 438f931551bSRalph Campbell &flash_ops, dd); 439f931551bSRalph Campbell if (ret) 4407fac3301SMike Marciniszyn pr_err("create_file(%s/flash) failed: %d\n", 441f931551bSRalph Campbell unit, ret); 442f931551bSRalph Campbell bail: 443f931551bSRalph Campbell return ret; 444f931551bSRalph Campbell } 445f931551bSRalph Campbell 446f931551bSRalph Campbell static int remove_file(struct dentry *parent, char *name) 447f931551bSRalph Campbell { 448f931551bSRalph Campbell struct dentry *tmp; 449f931551bSRalph Campbell int ret; 450f931551bSRalph Campbell 451f931551bSRalph Campbell tmp = lookup_one_len(name, parent, strlen(name)); 452f931551bSRalph Campbell 453f931551bSRalph Campbell if (IS_ERR(tmp)) { 454f931551bSRalph Campbell ret = PTR_ERR(tmp); 455f931551bSRalph Campbell goto bail; 456f931551bSRalph Campbell } 457f931551bSRalph Campbell 458f931551bSRalph Campbell spin_lock(&tmp->d_lock); 459f931551bSRalph Campbell if (!(d_unhashed(tmp) && tmp->d_inode)) { 460f931551bSRalph Campbell __d_drop(tmp); 461f931551bSRalph Campbell spin_unlock(&tmp->d_lock); 462f931551bSRalph Campbell simple_unlink(parent->d_inode, tmp); 463f931551bSRalph Campbell } else { 464f931551bSRalph Campbell spin_unlock(&tmp->d_lock); 465f931551bSRalph Campbell } 466441a9d0eSAl Viro dput(tmp); 467f931551bSRalph Campbell 468f931551bSRalph Campbell ret = 0; 469f931551bSRalph Campbell bail: 470f931551bSRalph Campbell /* 471f931551bSRalph Campbell * We don't expect clients to care about the return value, but 472f931551bSRalph Campbell * it's there if they need it. 473f931551bSRalph Campbell */ 474f931551bSRalph Campbell return ret; 475f931551bSRalph Campbell } 476f931551bSRalph Campbell 477f931551bSRalph Campbell static int remove_device_files(struct super_block *sb, 478f931551bSRalph Campbell struct qib_devdata *dd) 479f931551bSRalph Campbell { 480f931551bSRalph Campbell struct dentry *dir, *root; 481f931551bSRalph Campbell char unit[10]; 482f931551bSRalph Campbell int ret, i; 483f931551bSRalph Campbell 484f931551bSRalph Campbell root = dget(sb->s_root); 485f931551bSRalph Campbell mutex_lock(&root->d_inode->i_mutex); 486f931551bSRalph Campbell snprintf(unit, sizeof unit, "%u", dd->unit); 487f931551bSRalph Campbell dir = lookup_one_len(unit, root, strlen(unit)); 488f931551bSRalph Campbell 489f931551bSRalph Campbell if (IS_ERR(dir)) { 490f931551bSRalph Campbell ret = PTR_ERR(dir); 4917fac3301SMike Marciniszyn pr_err("Lookup of %s failed\n", unit); 492f931551bSRalph Campbell goto bail; 493f931551bSRalph Campbell } 494f931551bSRalph Campbell 495441a9d0eSAl Viro mutex_lock(&dir->d_inode->i_mutex); 496f931551bSRalph Campbell remove_file(dir, "counters"); 497f931551bSRalph Campbell remove_file(dir, "counter_names"); 498f931551bSRalph Campbell remove_file(dir, "portcounter_names"); 499f931551bSRalph Campbell for (i = 0; i < dd->num_pports; i++) { 500f931551bSRalph Campbell char fname[24]; 501f931551bSRalph Campbell 502f931551bSRalph Campbell sprintf(fname, "port%dcounters", i + 1); 503f931551bSRalph Campbell remove_file(dir, fname); 504f931551bSRalph Campbell if (dd->flags & QIB_HAS_QSFP) { 505f931551bSRalph Campbell sprintf(fname, "qsfp%d", i + 1); 506f931551bSRalph Campbell remove_file(dir, fname); 507f931551bSRalph Campbell } 508f931551bSRalph Campbell } 509f931551bSRalph Campbell remove_file(dir, "flash"); 510441a9d0eSAl Viro mutex_unlock(&dir->d_inode->i_mutex); 511f931551bSRalph Campbell ret = simple_rmdir(root->d_inode, dir); 512441a9d0eSAl Viro d_delete(dir); 513441a9d0eSAl Viro dput(dir); 514f931551bSRalph Campbell 515f931551bSRalph Campbell bail: 516f931551bSRalph Campbell mutex_unlock(&root->d_inode->i_mutex); 517f931551bSRalph Campbell dput(root); 518f931551bSRalph Campbell return ret; 519f931551bSRalph Campbell } 520f931551bSRalph Campbell 521f931551bSRalph Campbell /* 522f931551bSRalph Campbell * This fills everything in when the fs is mounted, to handle umount/mount 523f931551bSRalph Campbell * after device init. The direct add_cntr_files() call handles adding 524f931551bSRalph Campbell * them from the init code, when the fs is already mounted. 525f931551bSRalph Campbell */ 526f931551bSRalph Campbell static int qibfs_fill_super(struct super_block *sb, void *data, int silent) 527f931551bSRalph Campbell { 528f931551bSRalph Campbell struct qib_devdata *dd, *tmp; 529f931551bSRalph Campbell unsigned long flags; 530f931551bSRalph Campbell int ret; 531f931551bSRalph Campbell 532f931551bSRalph Campbell static struct tree_descr files[] = { 533f931551bSRalph Campbell [2] = {"driver_stats", &driver_ops[0], S_IRUGO}, 534f931551bSRalph Campbell [3] = {"driver_stats_names", &driver_ops[1], S_IRUGO}, 535f931551bSRalph Campbell {""}, 536f931551bSRalph Campbell }; 537f931551bSRalph Campbell 538f931551bSRalph Campbell ret = simple_fill_super(sb, QIBFS_MAGIC, files); 539f931551bSRalph Campbell if (ret) { 5407fac3301SMike Marciniszyn pr_err("simple_fill_super failed: %d\n", ret); 541f931551bSRalph Campbell goto bail; 542f931551bSRalph Campbell } 543f931551bSRalph Campbell 544f931551bSRalph Campbell spin_lock_irqsave(&qib_devs_lock, flags); 545f931551bSRalph Campbell 546f931551bSRalph Campbell list_for_each_entry_safe(dd, tmp, &qib_dev_list, list) { 547f931551bSRalph Campbell spin_unlock_irqrestore(&qib_devs_lock, flags); 548f931551bSRalph Campbell ret = add_cntr_files(sb, dd); 549971b2e8aSAl Viro if (ret) 550f931551bSRalph Campbell goto bail; 551f931551bSRalph Campbell spin_lock_irqsave(&qib_devs_lock, flags); 552f931551bSRalph Campbell } 553f931551bSRalph Campbell 554f931551bSRalph Campbell spin_unlock_irqrestore(&qib_devs_lock, flags); 555f931551bSRalph Campbell 556f931551bSRalph Campbell bail: 557f931551bSRalph Campbell return ret; 558f931551bSRalph Campbell } 559f931551bSRalph Campbell 560fc14f2feSAl Viro static struct dentry *qibfs_mount(struct file_system_type *fs_type, int flags, 561fc14f2feSAl Viro const char *dev_name, void *data) 562f931551bSRalph Campbell { 563fc14f2feSAl Viro struct dentry *ret; 564fc14f2feSAl Viro ret = mount_single(fs_type, flags, data, qibfs_fill_super); 565fc14f2feSAl Viro if (!IS_ERR(ret)) 566fc14f2feSAl Viro qib_super = ret->d_sb; 567f931551bSRalph Campbell return ret; 568f931551bSRalph Campbell } 569f931551bSRalph Campbell 570f931551bSRalph Campbell static void qibfs_kill_super(struct super_block *s) 571f931551bSRalph Campbell { 572f931551bSRalph Campbell kill_litter_super(s); 573f931551bSRalph Campbell qib_super = NULL; 574f931551bSRalph Campbell } 575f931551bSRalph Campbell 576f931551bSRalph Campbell int qibfs_add(struct qib_devdata *dd) 577f931551bSRalph Campbell { 578f931551bSRalph Campbell int ret; 579f931551bSRalph Campbell 580f931551bSRalph Campbell /* 581f931551bSRalph Campbell * On first unit initialized, qib_super will not yet exist 582f931551bSRalph Campbell * because nobody has yet tried to mount the filesystem, so 583f931551bSRalph Campbell * we can't consider that to be an error; if an error occurs 584f931551bSRalph Campbell * during the mount, that will get a complaint, so this is OK. 585f931551bSRalph Campbell * add_cntr_files() for all units is done at mount from 586f931551bSRalph Campbell * qibfs_fill_super(), so one way or another, everything works. 587f931551bSRalph Campbell */ 588f931551bSRalph Campbell if (qib_super == NULL) 589f931551bSRalph Campbell ret = 0; 590f931551bSRalph Campbell else 591f931551bSRalph Campbell ret = add_cntr_files(qib_super, dd); 592f931551bSRalph Campbell return ret; 593f931551bSRalph Campbell } 594f931551bSRalph Campbell 595f931551bSRalph Campbell int qibfs_remove(struct qib_devdata *dd) 596f931551bSRalph Campbell { 597f931551bSRalph Campbell int ret = 0; 598f931551bSRalph Campbell 599f931551bSRalph Campbell if (qib_super) 600f931551bSRalph Campbell ret = remove_device_files(qib_super, dd); 601f931551bSRalph Campbell 602f931551bSRalph Campbell return ret; 603f931551bSRalph Campbell } 604f931551bSRalph Campbell 605f931551bSRalph Campbell static struct file_system_type qibfs_fs_type = { 606f931551bSRalph Campbell .owner = THIS_MODULE, 607f931551bSRalph Campbell .name = "ipathfs", 608fc14f2feSAl Viro .mount = qibfs_mount, 609f931551bSRalph Campbell .kill_sb = qibfs_kill_super, 610f931551bSRalph Campbell }; 6117f78e035SEric W. Biederman MODULE_ALIAS_FS("ipathfs"); 612f931551bSRalph Campbell 613f931551bSRalph Campbell int __init qib_init_qibfs(void) 614f931551bSRalph Campbell { 615f931551bSRalph Campbell return register_filesystem(&qibfs_fs_type); 616f931551bSRalph Campbell } 617f931551bSRalph Campbell 618f931551bSRalph Campbell int __exit qib_exit_qibfs(void) 619f931551bSRalph Campbell { 620f931551bSRalph Campbell return unregister_filesystem(&qibfs_fs_type); 621f931551bSRalph Campbell } 622