root/drivers/scsi/mpt3sas/mpt3sas_debugfs.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Debugfs interface Support for MPT (Message Passing Technology) based
 * controllers.
 *
 * Copyright (C) 2020  Broadcom Inc.
 *
 * Authors: Broadcom Inc.
 * Sreekanth Reddy  <sreekanth.reddy@broadcom.com>
 * Suganath Prabu <suganath-prabu.subramani@broadcom.com>
 *
 * Send feedback to : MPT-FusionLinux.pdl@broadcom.com)
 *
 **/

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/compat.h>
#include <linux/uio.h>

#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include "mpt3sas_base.h"
#include <linux/debugfs.h>

static struct dentry *mpt3sas_debugfs_root;

/*
 * _debugfs_iocdump_read - copy ioc dump from debugfs buffer
 * @filep:      File Pointer
 * @ubuf:       Buffer to fill data
 * @cnt:        Length of the buffer
 * @ppos:       Offset in the file
 */

static ssize_t
_debugfs_iocdump_read(struct file *filp, char __user *ubuf, size_t cnt,
        loff_t *ppos)

{
        struct mpt3sas_debugfs_buffer *debug = filp->private_data;

        if (!debug || !debug->buf)
                return 0;

        return simple_read_from_buffer(ubuf, cnt, ppos, debug->buf, debug->len);
}

/*
 * _debugfs_iocdump_open :      open the ioc_dump debugfs attribute file
 */
static int
_debugfs_iocdump_open(struct inode *inode, struct file *file)
{
        struct MPT3SAS_ADAPTER *ioc = inode->i_private;
        struct mpt3sas_debugfs_buffer *debug;

        debug = kzalloc_obj(struct mpt3sas_debugfs_buffer);
        if (!debug)
                return -ENOMEM;

        debug->buf = (void *)ioc;
        debug->len = sizeof(struct MPT3SAS_ADAPTER);
        file->private_data = debug;
        return 0;
}

/*
 * _debugfs_iocdump_release :   release the ioc_dump debugfs attribute
 * @inode: inode structure to the corresponds device
 * @file: File pointer
 */
static int
_debugfs_iocdump_release(struct inode *inode, struct file *file)
{
        struct mpt3sas_debugfs_buffer *debug = file->private_data;

        if (!debug)
                return 0;

        file->private_data = NULL;
        kfree(debug);
        return 0;
}

static const struct file_operations mpt3sas_debugfs_iocdump_fops = {
        .owner          = THIS_MODULE,
        .open           = _debugfs_iocdump_open,
        .read           = _debugfs_iocdump_read,
        .release        = _debugfs_iocdump_release,
};

/*
 * mpt3sas_init_debugfs :       Create debugfs root for mpt3sas driver
 */
void mpt3sas_init_debugfs(void)
{
        mpt3sas_debugfs_root = debugfs_create_dir("mpt3sas", NULL);
        if (!mpt3sas_debugfs_root)
                pr_info("mpt3sas: Cannot create debugfs root\n");
}

/*
 * mpt3sas_exit_debugfs :       Remove debugfs root for mpt3sas driver
 */
void mpt3sas_exit_debugfs(void)
{
        debugfs_remove_recursive(mpt3sas_debugfs_root);
}

/*
 * mpt3sas_setup_debugfs :      Setup debugfs per HBA adapter
 * ioc:                         MPT3SAS_ADAPTER object
 */
void
mpt3sas_setup_debugfs(struct MPT3SAS_ADAPTER *ioc)
{
        char name[64];

        snprintf(name, sizeof(name), "scsi_host%d", ioc->shost->host_no);
        if (!ioc->debugfs_root) {
                ioc->debugfs_root =
                    debugfs_create_dir(name, mpt3sas_debugfs_root);
                if (!ioc->debugfs_root) {
                        dev_err(&ioc->pdev->dev,
                            "Cannot create per adapter debugfs directory\n");
                        return;
                }
        }

        snprintf(name, sizeof(name), "ioc_dump");
        ioc->ioc_dump = debugfs_create_file(name, 0444,
            ioc->debugfs_root, ioc, &mpt3sas_debugfs_iocdump_fops);
        if (!ioc->ioc_dump) {
                dev_err(&ioc->pdev->dev,
                    "Cannot create ioc_dump debugfs file\n");
                debugfs_remove(ioc->debugfs_root);
                return;
        }

        snprintf(name, sizeof(name), "host_recovery");
        debugfs_create_u8(name, 0444, ioc->debugfs_root, &ioc->shost_recovery);

}

/*
 * mpt3sas_destroy_debugfs :    Destroy debugfs per HBA adapter
 * @ioc:        MPT3SAS_ADAPTER object
 */
void mpt3sas_destroy_debugfs(struct MPT3SAS_ADAPTER *ioc)
{
        debugfs_remove_recursive(ioc->debugfs_root);
}