⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mptctl.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  linux/drivers/message/fusion/mptctl.c *      Fusion MPT misc device (ioctl) driver. *      For use with PCI chip/adapter(s): *          LSIFC9xx/LSI409xx Fibre Channel *      running LSI Logic Fusion MPT (Message Passing Technology) firmware. * *  Credits: *      This driver would not exist if not for Alan Cox's development *      of the linux i2o driver. * *      A special thanks to Pamela Delaney (LSI Logic) for tons of work *      and countless enhancements while adding support for the 1030 *      chip family.  Pam has been instrumental in the development of *      of the 2.xx.xx series fusion drivers, and her contributions are *      far too numerous to hope to list in one place. * *      A huge debt of gratitude is owed to David S. Miller (DaveM) *      for fixing much of the stupid and broken stuff in the early *      driver while porting to sparc64 platform.  THANK YOU! * *      A big THANKS to Eddie C. Dost for fixing the ioctl path *      and most importantly f/w download on sparc64 platform! *      (plus Eddie's other helpful hints and insights) * *      Thanks to Arnaldo Carvalho de Melo for finding and patching *      a potential memory leak in mptctl_do_fw_download(), *      and for some kmalloc insight:-) * *      (see also mptbase.c) * *  Copyright (c) 1999-2004 LSI Logic Corporation *  Originally By: Steven J. Ralston, Noah Romer *  (mailto:sjralston1@netscape.net) *  (mailto:mpt_linux_developer@lsil.com) * *  $Id: mptctl.c,v 1.63 2002/12/03 21:26:33 pdelaney Exp $ *//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//*    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; version 2 of the License.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    NO WARRANTY    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    solely responsible for determining the appropriateness of using and    distributing the Program and assumes all risks associated with its    exercise of rights under this Agreement, including but not limited to    the risks and costs of program errors, damage to or loss of data,    programs or equipment, and unavailability or interruption of operations.    DISCLAIMER OF LIABILITY    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA*//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/#include <linux/version.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/miscdevice.h>#include <linux/smp_lock.h>#include <linux/compat.h>#include <asm/io.h>#include <asm/uaccess.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_tcq.h>#define COPYRIGHT	"Copyright (c) 1999-2004 LSI Logic Corporation"#define MODULEAUTHOR	"Steven J. Ralston, Noah Romer, Pamela Delaney"#include "mptbase.h"#include "mptctl.h"/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/#define my_NAME		"Fusion MPT misc device (ioctl) driver"#define my_VERSION	MPT_LINUX_VERSION_COMMON#define MYNAM		"mptctl"MODULE_AUTHOR(MODULEAUTHOR);MODULE_DESCRIPTION(my_NAME);MODULE_LICENSE("GPL");/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/static int mptctl_id = -1;static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/struct buflist {	u8	*kptr;	int	 len;};/* * Function prototypes. Called from OS entry point mptctl_ioctl. * arg contents specific to function. */static int mptctl_fw_download(unsigned long arg);static int mptctl_getiocinfo (unsigned long arg, unsigned int cmd);static int mptctl_gettargetinfo (unsigned long arg);static int mptctl_readtest (unsigned long arg);static int mptctl_mpt_command (unsigned long arg);static int mptctl_eventquery (unsigned long arg);static int mptctl_eventenable (unsigned long arg);static int mptctl_eventreport (unsigned long arg);static int mptctl_replace_fw (unsigned long arg);static int mptctl_do_reset(unsigned long arg);static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd);static int mptctl_hp_targetinfo(unsigned long arg);static int  mptctl_probe(struct pci_dev *, const struct pci_device_id *);static void mptctl_remove(struct pci_dev *);/* * Private function calls. */static int mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr);static int mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen);static MptSge_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int sge_offset, int *frags,		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);static void kfree_sgl( MptSge_t *sgl, dma_addr_t sgl_dma,		struct buflist *buflist, MPT_ADAPTER *ioc);static void mptctl_timer_expired (unsigned long data);static int  mptctl_bus_reset(MPT_IOCTL *ioctl);static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd);static void mptctl_free_tm_flags(MPT_ADAPTER *ioc);/* * Reset Handler cleanup function */static int  mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase);/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * Scatter gather list (SGL) sizes and limits... *///#define MAX_SCSI_FRAGS	9#define MAX_FRAGS_SPILL1	9#define MAX_FRAGS_SPILL2	15#define FRAGS_PER_BUCKET	(MAX_FRAGS_SPILL2 + 1)//#define MAX_CHAIN_FRAGS	64//#define MAX_CHAIN_FRAGS	(15+15+15+16)#define MAX_CHAIN_FRAGS		(4 * MAX_FRAGS_SPILL2 + 1)//  Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each)//  Works out to: 592d bytes!     (9+1)*8 + 4*(15+1)*8//                  ^----------------- 80 + 512#define MAX_SGL_BYTES		((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8)/* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */#define MAX_KMALLOC_SZ		(128*1024)#define MPT_IOCTL_DEFAULT_TIMEOUT 10	/* Default timeout value (seconds) */static u32 fwReplyBuffer[16];static pMPIDefaultReply_t ReplyMsg = NULL;/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** *	mptctl_syscall_down - Down the MPT adapter syscall semaphore. *	@ioc: Pointer to MPT adapter *	@nonblock: boolean, non-zero if O_NONBLOCK is set * *	All of the ioctl commands can potentially sleep, which is illegal *	with a spinlock held, thus we perform mutual exclusion here. * *	Returns negative errno on error, or zero for success. */static inline intmptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock){	int rc = 0;	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));	if (ioc->ioctl->tmPtr != NULL) {		dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down BUSY\n"));		return -EBUSY;	}	if (nonblock) {		if (down_trylock(&ioc->ioctl->sem_ioc))			rc = -EAGAIN;	} else {		if (down_interruptible(&ioc->ioctl->sem_ioc))			rc = -ERESTARTSYS;	}	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc));	return rc;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *  This is the callback for any message we have posted. The message itself *  will be returned to the message pool when we return from the IRQ * *  This runs in irq context so be short and sweet. */static intmptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply){	char *sense_data;	int sz, req_index;	u16 iocStatus;	u8 cmd;	dctlprintk((MYIOC_s_INFO_FMT ": mptctl_reply()!\n", ioc->name));	if (req)		 cmd = req->u.hdr.Function;	else		return 1;	if (ioc->ioctl) {		/* If timer is not running, then an error occurred.		 * A timeout will call the reset routine to reload the messaging		 * queues.		 * Main callback will free message and reply frames.		 */		if (reply && (cmd == MPI_FUNCTION_SCSI_TASK_MGMT) &&		    (ioc->ioctl->status & MPT_IOCTL_STATUS_TMTIMER_ACTIVE)) {			/* This is internally generated TM			 */			del_timer (&ioc->ioctl->TMtimer);			ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TMTIMER_ACTIVE;			mptctl_free_tm_flags(ioc);			/* If TM failed, reset the timer on the existing command,			 * will trigger an adapter reset.			 */			iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;			if (iocStatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED) {				if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {					ioc->ioctl->reset &= ~MPTCTL_RESET_OK;					del_timer (&ioc->ioctl->timer);					ioc->ioctl->timer.expires = jiffies + HZ;					add_timer(&ioc->ioctl->timer);				}			}			ioc->ioctl->tmPtr = NULL;		} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {			/* Delete this timer			 */			del_timer (&ioc->ioctl->timer);			ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE;			/* Set the overall status byte.  Good if:			 * IOC status is good OR if no reply and a SCSI IO request			 */			if (reply) {				/* Copy the reply frame (which much exist				 * for non-SCSI I/O) to the IOC structure.				 */				dctlprintk((MYIOC_s_INFO_FMT ": Copying Reply Frame @%p to IOC!\n",						ioc->name, reply));				memcpy(ioc->ioctl->ReplyFrame, reply,					min(ioc->reply_sz, 4*reply->u.reply.MsgLength));				ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;				/* Set the command status to GOOD if IOC Status is GOOD				 * OR if SCSI I/O cmd and data underrun or recovered error.				 */				iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;				if (iocStatus  == MPI_IOCSTATUS_SUCCESS)					ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;				if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||					(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {					ioc->ioctl->reset &= ~MPTCTL_RESET_OK;					if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||						(iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {						ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;					}				}				/* Copy the sense data - if present				 */				if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) &&					(reply->u.sreply.SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)){					sz = req->u.scsireq.SenseBufferLength;					req_index = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);					sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));					memcpy(ioc->ioctl->sense, sense_data, sz);					ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID;				}				if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT)					mptctl_free_tm_flags(ioc);			} else if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||					(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {				ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;				ioc->ioctl->reset &= ~MPTCTL_RESET_OK;			}			/* We are done, issue wake up			 */			ioc->ioctl->wait_done = 1;			wake_up (&mptctl_wait);		} else if (reply && cmd == MPI_FUNCTION_FW_DOWNLOAD) {			/* Two paths to FW DOWNLOAD! */			// NOTE: Expects/requires non-Turbo reply!			dctlprintk((MYIOC_s_INFO_FMT ":Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n",				ioc->name));			memcpy(fwReplyBuffer, reply, min_t(int, sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));			ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer;		}	}	return 1;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* mptctl_timer_expired * * Call back for timer process. Used only for ioctl functionality. * */static void mptctl_timer_expired (unsigned long data){	MPT_IOCTL *ioctl = (MPT_IOCTL *) data;	int rc = 1;	dctlprintk((KERN_NOTICE MYNAM ": Timer Expired! Host %d\n",				ioctl->ioc->id));	if (ioctl == NULL)		return;	if (ioctl->reset & MPTCTL_RESET_OK)		rc = mptctl_bus_reset(ioctl);	if (rc) {		/* Issue a reset for this device.		 * The IOC is not responding.		 */		mpt_HardResetHandler(ioctl->ioc, NO_SLEEP);	}	return;}/* mptctl_bus_reset * * Bus reset code. * */static int mptctl_bus_reset(MPT_IOCTL *ioctl){	MPT_FRAME_HDR	*mf;	SCSITaskMgmt_t	*pScsiTm;	MPT_SCSI_HOST	*hd;	int		 ii;	int		 retval;	ioctl->reset &= ~MPTCTL_RESET_OK;	if (ioctl->ioc->sh == NULL)		return -EPERM;		hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata;	if (hd == NULL)		return -EPERM;	/* Single threading ....	 */	if (mptctl_set_tm_flags(hd) != 0)		return -EPERM;	/* Send request	 */	if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) {		dctlprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",				ioctl->ioc->name));		mptctl_free_tm_flags(ioctl->ioc);		return -ENOMEM;	}	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",			ioctl->ioc->name, mf));	pScsiTm = (SCSITaskMgmt_t *) mf;	pScsiTm->TargetID = ioctl->target;	pScsiTm->Bus = hd->port;	/* 0 */	pScsiTm->ChainOffset = 0;	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;	pScsiTm->Reserved = 0;	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;	pScsiTm->Reserved1 = 0;	pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;	for (ii= 0; ii < 8; ii++)		pScsiTm->LUN[ii] = 0;	for (ii=0; ii < 7; ii++)		pScsiTm->Reserved2[ii] = 0;	pScsiTm->TaskMsgContext = 0;	dtmprintk((MYIOC_s_INFO_FMT "mptctl_bus_reset: issued.\n", ioctl->ioc->name));	ioctl->tmPtr = mf;	ioctl->TMtimer.expires = jiffies + HZ * 20;	/* 20 seconds */	ioctl->status |= MPT_IOCTL_STATUS_TMTIMER_ACTIVE;	add_timer(&ioctl->TMtimer);	retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,			sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, NO_SLEEP);	if (retval != 0) {		dtmprintk((MYIOC_s_WARN_FMT "_send_handshake FAILED!"			" (hd %p, ioc %p, mf %p) \n", ioctl->ioc->name, hd, hd->ioc, mf));		mptctl_free_tm_flags(ioctl->ioc);		del_timer(&ioctl->TMtimer);		mpt_free_msg_frame(ioctl->ioc, mf);		ioctl->tmPtr = NULL;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -