/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_mm.c
* Version : v2.20.2.7 (Jul 16 2006)
*
* Common management module
*/
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include "megaraid_mm.h"
// Entry points for char node driver
static DEFINE_MUTEX(mraid_mm_mutex);
static int mraid_mm_open(struct inode *, struct file *);
static long mraid_mm_unlocked_ioctl(struct file *, uint, unsigned long);
// routines to convert to and from the old the format
static int mimd_to_kioc(mimd_t __user *, mraid_mmadp_t *, uioc_t *);
static int kioc_to_mimd(uioc_t *, mimd_t __user *);
// Helper functions
static int handle_drvrcmd(void __user *, uint8_t, int *);
static int lld_ioctl(mraid_mmadp_t *, uioc_t *);
static void ioctl_done(uioc_t *);
static void lld_timedout(unsigned long);
static void hinfo_to_cinfo(mraid_hba_info_t *, mcontroller_t *);
static mraid_mmadp_t *mraid_mm_get_adapter(mimd_t __user *, int *);
static uioc_t *mraid_mm_alloc_kioc(mraid_mmadp_t *);
static void mraid_mm_dealloc_kioc(mraid_mmadp_t *, uioc_t *);
static int mraid_mm_attach_buf(mraid_mmadp_t *, uioc_t *, int);
static int mraid_mm_setup_dma_pools(mraid_mmadp_t *);
static void mraid_mm_free_adp_resources(mraid_mmadp_t *);
static void mraid_mm_teardown_dma_pools(mraid_mmadp_t *);
#ifdef CONFIG_COMPAT
static long mraid_mm_compat_ioctl(struct file *, unsigned int, unsigned long);
#endif
MODULE_AUTHOR("LSI Logic Corporation");
MODULE_DESCRIPTION("LSI Logic Management Module");
MODULE_LICENSE("GPL");
MODULE_VERSION(LSI_COMMON_MOD_VERSION);
static int dbglevel = CL_ANN;
module_param_named(dlevel, dbglevel, int, 0);
MODULE_PARM_DESC(dlevel, "Debug level (default=0)");
EXPORT_SYMBOL(mraid_mm_register_adp);
EXPORT_SYMBOL(mraid_mm_unregister_adp);
EXPORT_SYMBOL(mraid_mm_adapter_app_handle);
static uint32_t drvr_ver = 0x02200207;
static int adapters_count_g;
static struct list_head adapters_list_g;
static wait_queue_head_t wait_q;
static const struct file_operations lsi_fops = {
.open = mraid_mm_open,
.unlocked_ioctl = mraid_mm_unlocked_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = mraid_mm_compat_ioctl,
#endif
.owner = THIS_MODULE,
.llseek = noop_llseek,
};
static struct miscdevice megaraid_mm_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "megadev0",
.fops = &lsi_fops,
};
/**
* mraid_mm_open - open routine for char node interface
* @inode : unused
* @filep : unused
*
* Allow ioctl operations by apps only if they have superuser privilege.
*/
static int
mraid_mm_open(struct inode *inode, struct file *filep)
{
/*
* Only allow superuser to access private ioctl interface
*/
if (!capable(CAP_SYS_ADMIN)) return (-EACCES);
return 0;
}
/**
* mraid_mm_ioctl - module entry-point for ioctls
* @inode : inode (ignored)
* @filep : file operations pointer (ignored)
* @cmd : ioctl command
* @arg : user ioctl packet
*/
static int
mraid_mm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
uioc_t *kioc;
char signature[EXT_IOCTL_SIGN_SZ] = {0};
int rval;
mraid_mmadp_t *adp;
uint8_t old_ioctl;
int drvrcmd_rval;
void __user *argp = (void __user *)arg;
/*
* Make sure only USCSICMD are issued through this interface.
* MIMD application would still fire different command.
*/
if ((_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD)) {
return (-EINVAL);
}
/*
* Look for signature to see if this is the new or old ioctl format.
*/
if (copy_from_user(signature, argp, EXT_IOCTL_SIGN_SZ)) {
con_log(CL_ANN, (KERN_WARNING
"megaraid cmm: copy from usr addr failed\n"));
return (-EFAULT);
}
if (memcmp(signature, EXT_IOCTL_SIGN, EXT_IOCTL_SIGN_SZ) == 0)
old_ioctl = 0;
else
old_ioctl = 1;
/*
* At present, we don't support the new ioctl packet
*/
if (!old_ioctl )
return (-EINVAL);
/*
* If it is a driver ioctl (as opposed to fw ioctls), then we can
* handle the command locally. rval > 0 means it is not a drvr cmd
*/
rval = handle_drvrcmd(argp, old_ioctl, &drvrcmd_rval);
if (rval < 0)
return rval;
else if (rval == 0)
return drvrcmd_rval;
rval = 0;
if ((adp = mraid_mm_get_adapter(argp, &rval)) == NULL) {
return rval;
}
/*
* Check if adapter can accept ioctl. We may have marked it offline
* if any previous kioc had timedout on this controller.
*/
if (!adp->quiescent) {
con_log(CL_ANN, (KERN_WARNING
"megaraid cmm: controller cannot accept cmds due to "
"earlier errors\n" ));
return -EFAULT;
}
/*
* The following call will block till a kioc is available
*/
kioc = mraid_mm_alloc_kioc(adp);
/*
* User sent the old mimd_t ioctl packet. Convert it to uioc_t.
*/
if ((rval = mimd_to_kioc(argp, adp, kioc))) {
mraid_mm_dealloc_kioc(adp, kioc);
return rval;
}
kioc->done = ioctl_done;
/*
* Issue the IOCTL to the low level driver. After the IOCTL completes
* release the kioc if and only if it was _not_ timedout. If it was
* timedout, that means that resources are still with low level driver.
*/
if ((rval = lld_ioctl(adp, kioc))) {
if (!kioc->timedout)
mraid_mm_dealloc_kioc(adp, kioc);
return rval;
}
/*
* Convert the kioc back to user space
*/
rval = kioc_to_mimd(kioc, argp);
/*
* Return the kioc to free pool
*/
mraid_mm_dealloc_kioc(adp, kioc);
return rval;
}
static long
mraid_mm_unlocked_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
int err;
/* inconsistent: mraid_mm_compat_ioctl doesn't take the BKL */
mutex_lock(&mraid_mm_mutex);
err = mraid_mm_ioctl(filep, cmd, arg);
mutex_unlock(&mraid_mm_mutex);
return err;
}
/**
* mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet
* @umimd : User space mimd_t ioctl packet
* @rval : returned success/error status
*
* The function return value is a pointer to the located @adapter.
*/
static mraid_mmadp_t *
mraid_mm_get_adapter(mimd_t __user *umimd, int *rval)
{
mraid_mmadp_t *adapter;
mimd_t mimd;
uint32_t adapno;
int iterator;
if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) {
*rval = -EFAULT;
return NULL;
}
adapno = GETADAP(mimd.ui.fcs.adapno);
if (adapno >= adapters_count_g) {
*rval = -ENODEV;
return NULL;
}
adapter = NULL;
iterator = 0;
list_for_each_entry(adapter, &adapters_list_g, list) {
if (iterator++ == adapno) break;
}
if (!adapter) {
*rval = -ENODEV;
return NULL;
}
return adapter;
}
/**
* handle_drvrcmd - Checks if the opcode is a driver cmd and if it is, handles it.
* @arg : packet sent by the user app
* @old_ioctl : mimd if 1; uioc otherwise
* @rval : pointer for command's returned value (not function status)
*/
static int
handle_drvrcmd(void __user *arg, uint8_t old_ioctl, int *rval)
{
mimd_t __user *umimd;
mimd_t kmimd;
uint8_t opcode;
uint8_t subopcode;
if (old_ioctl)
goto old_packet;
else
goto new_packet;
new_packet:
return (-ENOTSUPP);
old_packet:
*rval = 0;
umimd = arg;
if (copy_from_user(&kmimd, umimd, sizeof(mimd_t)))
return (-EFAULT);
opcode = kmimd.ui.fcs.opcode;
subopcode = kmimd.ui.fcs.subopcode;
/*
* If the opcode is 0x82 and the subopcode is either GET_DRVRVER or
* GET_NUMADP, then we can handle. Otherwise we should return 1 to
* indicate that we cannot handle this.
*/
if (opcode != 0x82)
return 1;
switch (subopcode) {
case MEGAIOC_QDRVRVER:
if (copy_to_user(kmimd.data, &drvr_ver, sizeof(uint32_t)))
return (-EFAULT);
return 0;
case MEGAIOC_QNADAP:
*rval = adapters_count_g;
if (copy_to_user(kmimd.data, &adapters_count_g,
sizeof(uint32_t)))
return (-EFAULT);
return 0;
default:
/* cannot handle */
return 1;
}
return 0;
}
/**
* mi
megaraid_mm.rar_V2
版权申诉
18 浏览量
2022-09-14
22:02:28
上传
评论
收藏 9KB RAR 举报
Kinonoyomeo
- 粉丝: 77
- 资源: 1万+
最新资源
- 基于Java的网上订餐系统设计源码 - online ordering system
- 基于Javascript的超级美眉网络资源管理应用模块设计源码
- 基于Typescript和PHP的编程知识储备库设计源码 - study-php
- Screenshot_2024-05-28-11-40-58-177_com.tencent.mm.jpg
- 基于Dart的Flutter小提琴调音器APP设计源码 - violinhelper
- 基于JavaScript和CSS的随寻订购网页设计源码 - web-order
- 基于MATLAB的声纹识别系统设计源码 - VoiceprintRecognition
- 基于Java的微服务插件集合设计源码 - wsy-plugins
- 基于Vue和微信小程序的监理日志系统设计源码 - supervisionLog
- 基于Java和LCN分布式事务框架的设计源码 - tx-lcn
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈