162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2012 Intel Corporation. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2006 PathScale, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/fs.h> 3662306a36Sopenharmony_ci#include <linux/fs_context.h> 3762306a36Sopenharmony_ci#include <linux/mount.h> 3862306a36Sopenharmony_ci#include <linux/pagemap.h> 3962306a36Sopenharmony_ci#include <linux/init.h> 4062306a36Sopenharmony_ci#include <linux/namei.h> 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include "qib.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define QIBFS_MAGIC 0x726a77 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic struct super_block *qib_super; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define private2dd(file) (file_inode(file)->i_private) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int qibfs_mknod(struct inode *dir, struct dentry *dentry, 5162306a36Sopenharmony_ci umode_t mode, const struct file_operations *fops, 5262306a36Sopenharmony_ci void *data) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci int error; 5562306a36Sopenharmony_ci struct inode *inode = new_inode(dir->i_sb); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (!inode) { 5862306a36Sopenharmony_ci error = -EPERM; 5962306a36Sopenharmony_ci goto bail; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci inode->i_ino = get_next_ino(); 6362306a36Sopenharmony_ci inode->i_mode = mode; 6462306a36Sopenharmony_ci inode->i_uid = GLOBAL_ROOT_UID; 6562306a36Sopenharmony_ci inode->i_gid = GLOBAL_ROOT_GID; 6662306a36Sopenharmony_ci inode->i_blocks = 0; 6762306a36Sopenharmony_ci inode->i_atime = inode_set_ctime_current(inode); 6862306a36Sopenharmony_ci inode->i_mtime = inode->i_atime; 6962306a36Sopenharmony_ci inode->i_private = data; 7062306a36Sopenharmony_ci if (S_ISDIR(mode)) { 7162306a36Sopenharmony_ci inode->i_op = &simple_dir_inode_operations; 7262306a36Sopenharmony_ci inc_nlink(inode); 7362306a36Sopenharmony_ci inc_nlink(dir); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci inode->i_fop = fops; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci d_instantiate(dentry, inode); 7962306a36Sopenharmony_ci error = 0; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cibail: 8262306a36Sopenharmony_ci return error; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int create_file(const char *name, umode_t mode, 8662306a36Sopenharmony_ci struct dentry *parent, struct dentry **dentry, 8762306a36Sopenharmony_ci const struct file_operations *fops, void *data) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci int error; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci inode_lock(d_inode(parent)); 9262306a36Sopenharmony_ci *dentry = lookup_one_len(name, parent, strlen(name)); 9362306a36Sopenharmony_ci if (!IS_ERR(*dentry)) 9462306a36Sopenharmony_ci error = qibfs_mknod(d_inode(parent), *dentry, 9562306a36Sopenharmony_ci mode, fops, data); 9662306a36Sopenharmony_ci else 9762306a36Sopenharmony_ci error = PTR_ERR(*dentry); 9862306a36Sopenharmony_ci inode_unlock(d_inode(parent)); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return error; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic ssize_t driver_stats_read(struct file *file, char __user *buf, 10462306a36Sopenharmony_ci size_t count, loff_t *ppos) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci qib_stats.sps_ints = qib_sps_ints(); 10762306a36Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, &qib_stats, 10862306a36Sopenharmony_ci sizeof(qib_stats)); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci * driver stats field names, one line per stat, single string. Used by 11362306a36Sopenharmony_ci * programs like ipathstats to print the stats in a way which works for 11462306a36Sopenharmony_ci * different versions of drivers, without changing program source. 11562306a36Sopenharmony_ci * if qlogic_ib_stats changes, this needs to change. Names need to be 11662306a36Sopenharmony_ci * 12 chars or less (w/o newline), for proper display by ipathstats utility. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_cistatic const char qib_statnames[] = 11962306a36Sopenharmony_ci "KernIntr\n" 12062306a36Sopenharmony_ci "ErrorIntr\n" 12162306a36Sopenharmony_ci "Tx_Errs\n" 12262306a36Sopenharmony_ci "Rcv_Errs\n" 12362306a36Sopenharmony_ci "H/W_Errs\n" 12462306a36Sopenharmony_ci "NoPIOBufs\n" 12562306a36Sopenharmony_ci "CtxtsOpen\n" 12662306a36Sopenharmony_ci "RcvLen_Errs\n" 12762306a36Sopenharmony_ci "EgrBufFull\n" 12862306a36Sopenharmony_ci "EgrHdrFull\n" 12962306a36Sopenharmony_ci ; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic ssize_t driver_names_read(struct file *file, char __user *buf, 13262306a36Sopenharmony_ci size_t count, loff_t *ppos) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, qib_statnames, 13562306a36Sopenharmony_ci sizeof(qib_statnames) - 1); /* no null */ 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic const struct file_operations driver_ops[] = { 13962306a36Sopenharmony_ci { .read = driver_stats_read, .llseek = generic_file_llseek, }, 14062306a36Sopenharmony_ci { .read = driver_names_read, .llseek = generic_file_llseek, }, 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* read the per-device counters */ 14462306a36Sopenharmony_cistatic ssize_t dev_counters_read(struct file *file, char __user *buf, 14562306a36Sopenharmony_ci size_t count, loff_t *ppos) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci u64 *counters; 14862306a36Sopenharmony_ci size_t avail; 14962306a36Sopenharmony_ci struct qib_devdata *dd = private2dd(file); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci avail = dd->f_read_cntrs(dd, *ppos, NULL, &counters); 15262306a36Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, counters, avail); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* read the per-device counters */ 15662306a36Sopenharmony_cistatic ssize_t dev_names_read(struct file *file, char __user *buf, 15762306a36Sopenharmony_ci size_t count, loff_t *ppos) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci char *names; 16062306a36Sopenharmony_ci size_t avail; 16162306a36Sopenharmony_ci struct qib_devdata *dd = private2dd(file); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci avail = dd->f_read_cntrs(dd, *ppos, &names, NULL); 16462306a36Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, names, avail); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic const struct file_operations cntr_ops[] = { 16862306a36Sopenharmony_ci { .read = dev_counters_read, .llseek = generic_file_llseek, }, 16962306a36Sopenharmony_ci { .read = dev_names_read, .llseek = generic_file_llseek, }, 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci * Could use file_inode(file)->i_ino to figure out which file, 17462306a36Sopenharmony_ci * instead of separate routine for each, but for now, this works... 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/* read the per-port names (same for each port) */ 17862306a36Sopenharmony_cistatic ssize_t portnames_read(struct file *file, char __user *buf, 17962306a36Sopenharmony_ci size_t count, loff_t *ppos) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci char *names; 18262306a36Sopenharmony_ci size_t avail; 18362306a36Sopenharmony_ci struct qib_devdata *dd = private2dd(file); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci avail = dd->f_read_portcntrs(dd, *ppos, 0, &names, NULL); 18662306a36Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, names, avail); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/* read the per-port counters for port 1 (pidx 0) */ 19062306a36Sopenharmony_cistatic ssize_t portcntrs_1_read(struct file *file, char __user *buf, 19162306a36Sopenharmony_ci size_t count, loff_t *ppos) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci u64 *counters; 19462306a36Sopenharmony_ci size_t avail; 19562306a36Sopenharmony_ci struct qib_devdata *dd = private2dd(file); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci avail = dd->f_read_portcntrs(dd, *ppos, 0, NULL, &counters); 19862306a36Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, counters, avail); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/* read the per-port counters for port 2 (pidx 1) */ 20262306a36Sopenharmony_cistatic ssize_t portcntrs_2_read(struct file *file, char __user *buf, 20362306a36Sopenharmony_ci size_t count, loff_t *ppos) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci u64 *counters; 20662306a36Sopenharmony_ci size_t avail; 20762306a36Sopenharmony_ci struct qib_devdata *dd = private2dd(file); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci avail = dd->f_read_portcntrs(dd, *ppos, 1, NULL, &counters); 21062306a36Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, counters, avail); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic const struct file_operations portcntr_ops[] = { 21462306a36Sopenharmony_ci { .read = portnames_read, .llseek = generic_file_llseek, }, 21562306a36Sopenharmony_ci { .read = portcntrs_1_read, .llseek = generic_file_llseek, }, 21662306a36Sopenharmony_ci { .read = portcntrs_2_read, .llseek = generic_file_llseek, }, 21762306a36Sopenharmony_ci}; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/* 22062306a36Sopenharmony_ci * read the per-port QSFP data for port 1 (pidx 0) 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_cistatic ssize_t qsfp_1_read(struct file *file, char __user *buf, 22362306a36Sopenharmony_ci size_t count, loff_t *ppos) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct qib_devdata *dd = private2dd(file); 22662306a36Sopenharmony_ci char *tmp; 22762306a36Sopenharmony_ci int ret; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci tmp = kmalloc(PAGE_SIZE, GFP_KERNEL); 23062306a36Sopenharmony_ci if (!tmp) 23162306a36Sopenharmony_ci return -ENOMEM; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci ret = qib_qsfp_dump(dd->pport, tmp, PAGE_SIZE); 23462306a36Sopenharmony_ci if (ret > 0) 23562306a36Sopenharmony_ci ret = simple_read_from_buffer(buf, count, ppos, tmp, ret); 23662306a36Sopenharmony_ci kfree(tmp); 23762306a36Sopenharmony_ci return ret; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* 24162306a36Sopenharmony_ci * read the per-port QSFP data for port 2 (pidx 1) 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_cistatic ssize_t qsfp_2_read(struct file *file, char __user *buf, 24462306a36Sopenharmony_ci size_t count, loff_t *ppos) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct qib_devdata *dd = private2dd(file); 24762306a36Sopenharmony_ci char *tmp; 24862306a36Sopenharmony_ci int ret; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (dd->num_pports < 2) 25162306a36Sopenharmony_ci return -ENODEV; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci tmp = kmalloc(PAGE_SIZE, GFP_KERNEL); 25462306a36Sopenharmony_ci if (!tmp) 25562306a36Sopenharmony_ci return -ENOMEM; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci ret = qib_qsfp_dump(dd->pport + 1, tmp, PAGE_SIZE); 25862306a36Sopenharmony_ci if (ret > 0) 25962306a36Sopenharmony_ci ret = simple_read_from_buffer(buf, count, ppos, tmp, ret); 26062306a36Sopenharmony_ci kfree(tmp); 26162306a36Sopenharmony_ci return ret; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic const struct file_operations qsfp_ops[] = { 26562306a36Sopenharmony_ci { .read = qsfp_1_read, .llseek = generic_file_llseek, }, 26662306a36Sopenharmony_ci { .read = qsfp_2_read, .llseek = generic_file_llseek, }, 26762306a36Sopenharmony_ci}; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic ssize_t flash_read(struct file *file, char __user *buf, 27062306a36Sopenharmony_ci size_t count, loff_t *ppos) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct qib_devdata *dd; 27362306a36Sopenharmony_ci ssize_t ret; 27462306a36Sopenharmony_ci loff_t pos; 27562306a36Sopenharmony_ci char *tmp; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci pos = *ppos; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (pos < 0) { 28062306a36Sopenharmony_ci ret = -EINVAL; 28162306a36Sopenharmony_ci goto bail; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (pos >= sizeof(struct qib_flash)) { 28562306a36Sopenharmony_ci ret = 0; 28662306a36Sopenharmony_ci goto bail; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (count > sizeof(struct qib_flash) - pos) 29062306a36Sopenharmony_ci count = sizeof(struct qib_flash) - pos; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci tmp = kmalloc(count, GFP_KERNEL); 29362306a36Sopenharmony_ci if (!tmp) { 29462306a36Sopenharmony_ci ret = -ENOMEM; 29562306a36Sopenharmony_ci goto bail; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci dd = private2dd(file); 29962306a36Sopenharmony_ci if (qib_eeprom_read(dd, pos, tmp, count)) { 30062306a36Sopenharmony_ci qib_dev_err(dd, "failed to read from flash\n"); 30162306a36Sopenharmony_ci ret = -ENXIO; 30262306a36Sopenharmony_ci goto bail_tmp; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (copy_to_user(buf, tmp, count)) { 30662306a36Sopenharmony_ci ret = -EFAULT; 30762306a36Sopenharmony_ci goto bail_tmp; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci *ppos = pos + count; 31162306a36Sopenharmony_ci ret = count; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cibail_tmp: 31462306a36Sopenharmony_ci kfree(tmp); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cibail: 31762306a36Sopenharmony_ci return ret; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic ssize_t flash_write(struct file *file, const char __user *buf, 32162306a36Sopenharmony_ci size_t count, loff_t *ppos) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct qib_devdata *dd; 32462306a36Sopenharmony_ci ssize_t ret; 32562306a36Sopenharmony_ci loff_t pos; 32662306a36Sopenharmony_ci char *tmp; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci pos = *ppos; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (pos != 0 || count != sizeof(struct qib_flash)) 33162306a36Sopenharmony_ci return -EINVAL; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci tmp = memdup_user(buf, count); 33462306a36Sopenharmony_ci if (IS_ERR(tmp)) 33562306a36Sopenharmony_ci return PTR_ERR(tmp); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci dd = private2dd(file); 33862306a36Sopenharmony_ci if (qib_eeprom_write(dd, pos, tmp, count)) { 33962306a36Sopenharmony_ci ret = -ENXIO; 34062306a36Sopenharmony_ci qib_dev_err(dd, "failed to write to flash\n"); 34162306a36Sopenharmony_ci goto bail_tmp; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci *ppos = pos + count; 34562306a36Sopenharmony_ci ret = count; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cibail_tmp: 34862306a36Sopenharmony_ci kfree(tmp); 34962306a36Sopenharmony_ci return ret; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic const struct file_operations flash_ops = { 35362306a36Sopenharmony_ci .read = flash_read, 35462306a36Sopenharmony_ci .write = flash_write, 35562306a36Sopenharmony_ci .llseek = default_llseek, 35662306a36Sopenharmony_ci}; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int add_cntr_files(struct super_block *sb, struct qib_devdata *dd) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct dentry *dir, *tmp; 36162306a36Sopenharmony_ci char unit[10]; 36262306a36Sopenharmony_ci int ret, i; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* create the per-unit directory */ 36562306a36Sopenharmony_ci snprintf(unit, sizeof(unit), "%u", dd->unit); 36662306a36Sopenharmony_ci ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir, 36762306a36Sopenharmony_ci &simple_dir_operations, dd); 36862306a36Sopenharmony_ci if (ret) { 36962306a36Sopenharmony_ci pr_err("create_file(%s) failed: %d\n", unit, ret); 37062306a36Sopenharmony_ci goto bail; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* create the files in the new directory */ 37462306a36Sopenharmony_ci ret = create_file("counters", S_IFREG|S_IRUGO, dir, &tmp, 37562306a36Sopenharmony_ci &cntr_ops[0], dd); 37662306a36Sopenharmony_ci if (ret) { 37762306a36Sopenharmony_ci pr_err("create_file(%s/counters) failed: %d\n", 37862306a36Sopenharmony_ci unit, ret); 37962306a36Sopenharmony_ci goto bail; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci ret = create_file("counter_names", S_IFREG|S_IRUGO, dir, &tmp, 38262306a36Sopenharmony_ci &cntr_ops[1], dd); 38362306a36Sopenharmony_ci if (ret) { 38462306a36Sopenharmony_ci pr_err("create_file(%s/counter_names) failed: %d\n", 38562306a36Sopenharmony_ci unit, ret); 38662306a36Sopenharmony_ci goto bail; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci ret = create_file("portcounter_names", S_IFREG|S_IRUGO, dir, &tmp, 38962306a36Sopenharmony_ci &portcntr_ops[0], dd); 39062306a36Sopenharmony_ci if (ret) { 39162306a36Sopenharmony_ci pr_err("create_file(%s/%s) failed: %d\n", 39262306a36Sopenharmony_ci unit, "portcounter_names", ret); 39362306a36Sopenharmony_ci goto bail; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci for (i = 1; i <= dd->num_pports; i++) { 39662306a36Sopenharmony_ci char fname[24]; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci sprintf(fname, "port%dcounters", i); 39962306a36Sopenharmony_ci /* create the files in the new directory */ 40062306a36Sopenharmony_ci ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp, 40162306a36Sopenharmony_ci &portcntr_ops[i], dd); 40262306a36Sopenharmony_ci if (ret) { 40362306a36Sopenharmony_ci pr_err("create_file(%s/%s) failed: %d\n", 40462306a36Sopenharmony_ci unit, fname, ret); 40562306a36Sopenharmony_ci goto bail; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci if (!(dd->flags & QIB_HAS_QSFP)) 40862306a36Sopenharmony_ci continue; 40962306a36Sopenharmony_ci sprintf(fname, "qsfp%d", i); 41062306a36Sopenharmony_ci ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp, 41162306a36Sopenharmony_ci &qsfp_ops[i - 1], dd); 41262306a36Sopenharmony_ci if (ret) { 41362306a36Sopenharmony_ci pr_err("create_file(%s/%s) failed: %d\n", 41462306a36Sopenharmony_ci unit, fname, ret); 41562306a36Sopenharmony_ci goto bail; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp, 42062306a36Sopenharmony_ci &flash_ops, dd); 42162306a36Sopenharmony_ci if (ret) 42262306a36Sopenharmony_ci pr_err("create_file(%s/flash) failed: %d\n", 42362306a36Sopenharmony_ci unit, ret); 42462306a36Sopenharmony_cibail: 42562306a36Sopenharmony_ci return ret; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int remove_device_files(struct super_block *sb, 42962306a36Sopenharmony_ci struct qib_devdata *dd) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct dentry *dir; 43262306a36Sopenharmony_ci char unit[10]; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci snprintf(unit, sizeof(unit), "%u", dd->unit); 43562306a36Sopenharmony_ci dir = lookup_one_len_unlocked(unit, sb->s_root, strlen(unit)); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (IS_ERR(dir)) { 43862306a36Sopenharmony_ci pr_err("Lookup of %s failed\n", unit); 43962306a36Sopenharmony_ci return PTR_ERR(dir); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci simple_recursive_removal(dir, NULL); 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci/* 44662306a36Sopenharmony_ci * This fills everything in when the fs is mounted, to handle umount/mount 44762306a36Sopenharmony_ci * after device init. The direct add_cntr_files() call handles adding 44862306a36Sopenharmony_ci * them from the init code, when the fs is already mounted. 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_cistatic int qibfs_fill_super(struct super_block *sb, struct fs_context *fc) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct qib_devdata *dd; 45362306a36Sopenharmony_ci unsigned long index; 45462306a36Sopenharmony_ci int ret; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci static const struct tree_descr files[] = { 45762306a36Sopenharmony_ci [2] = {"driver_stats", &driver_ops[0], S_IRUGO}, 45862306a36Sopenharmony_ci [3] = {"driver_stats_names", &driver_ops[1], S_IRUGO}, 45962306a36Sopenharmony_ci {""}, 46062306a36Sopenharmony_ci }; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci ret = simple_fill_super(sb, QIBFS_MAGIC, files); 46362306a36Sopenharmony_ci if (ret) { 46462306a36Sopenharmony_ci pr_err("simple_fill_super failed: %d\n", ret); 46562306a36Sopenharmony_ci goto bail; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci xa_for_each(&qib_dev_table, index, dd) { 46962306a36Sopenharmony_ci ret = add_cntr_files(sb, dd); 47062306a36Sopenharmony_ci if (ret) 47162306a36Sopenharmony_ci goto bail; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cibail: 47562306a36Sopenharmony_ci return ret; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic int qibfs_get_tree(struct fs_context *fc) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci int ret = get_tree_single(fc, qibfs_fill_super); 48162306a36Sopenharmony_ci if (ret == 0) 48262306a36Sopenharmony_ci qib_super = fc->root->d_sb; 48362306a36Sopenharmony_ci return ret; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic const struct fs_context_operations qibfs_context_ops = { 48762306a36Sopenharmony_ci .get_tree = qibfs_get_tree, 48862306a36Sopenharmony_ci}; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic int qibfs_init_fs_context(struct fs_context *fc) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci fc->ops = &qibfs_context_ops; 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic void qibfs_kill_super(struct super_block *s) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci kill_litter_super(s); 49962306a36Sopenharmony_ci qib_super = NULL; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ciint qibfs_add(struct qib_devdata *dd) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci int ret; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* 50762306a36Sopenharmony_ci * On first unit initialized, qib_super will not yet exist 50862306a36Sopenharmony_ci * because nobody has yet tried to mount the filesystem, so 50962306a36Sopenharmony_ci * we can't consider that to be an error; if an error occurs 51062306a36Sopenharmony_ci * during the mount, that will get a complaint, so this is OK. 51162306a36Sopenharmony_ci * add_cntr_files() for all units is done at mount from 51262306a36Sopenharmony_ci * qibfs_fill_super(), so one way or another, everything works. 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_ci if (qib_super == NULL) 51562306a36Sopenharmony_ci ret = 0; 51662306a36Sopenharmony_ci else 51762306a36Sopenharmony_ci ret = add_cntr_files(qib_super, dd); 51862306a36Sopenharmony_ci return ret; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ciint qibfs_remove(struct qib_devdata *dd) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci int ret = 0; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (qib_super) 52662306a36Sopenharmony_ci ret = remove_device_files(qib_super, dd); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci return ret; 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic struct file_system_type qibfs_fs_type = { 53262306a36Sopenharmony_ci .owner = THIS_MODULE, 53362306a36Sopenharmony_ci .name = "ipathfs", 53462306a36Sopenharmony_ci .init_fs_context = qibfs_init_fs_context, 53562306a36Sopenharmony_ci .kill_sb = qibfs_kill_super, 53662306a36Sopenharmony_ci}; 53762306a36Sopenharmony_ciMODULE_ALIAS_FS("ipathfs"); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ciint __init qib_init_qibfs(void) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci return register_filesystem(&qibfs_fs_type); 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ciint __exit qib_exit_qibfs(void) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci return unregister_filesystem(&qibfs_fs_type); 54762306a36Sopenharmony_ci} 548