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

📄 mptbase.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  linux/drivers/message/fusion/mptbase.c *      This is the Fusion MPT base driver which supports multiple *      (SCSI + LAN) specialized protocol drivers. *      For use with LSI Logic PCI chip/adapter(s) *      running LSI Logic Fusion MPT (Message Passing Technology) firmware. * *  Copyright (c) 1999-2005 LSI Logic Corporation *  (mailto:mpt_linux_developer@lsil.com) * *//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//*    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/config.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/kdev_t.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/interrupt.h>		/* needed for in_interrupt() proto */#include <linux/dma-mapping.h>#include <asm/io.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif#ifdef __sparc__#include <asm/irq.h>			/* needed for __irq_itoa() proto */#endif#include "mptbase.h"/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/#define my_NAME		"Fusion MPT base driver"#define my_VERSION	MPT_LINUX_VERSION_COMMON#define MYNAM		"mptbase"MODULE_AUTHOR(MODULEAUTHOR);MODULE_DESCRIPTION(my_NAME);MODULE_LICENSE("GPL");/* *  cmd line parameters */#ifdef MFCNTstatic int mfcounter = 0;#define PRINT_MF_COUNT 20000#endif/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *  Public data... */int mpt_lan_index = -1;int mpt_stm_index = -1;struct proc_dir_entry *mpt_proc_root_dir;#define WHOINIT_UNKNOWN		0xAA/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *  Private data... */					/* Adapter link list */LIST_HEAD(ioc_list);					/* Callback lookup table */static MPT_CALLBACK		 MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];					/* Protocol driver class lookup table */static int			 MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];					/* Event handler lookup table */static MPT_EVHANDLER		 MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];					/* Reset handler lookup table */static MPT_RESETHANDLER		 MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];static struct mpt_pci_driver 	*MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];static int	mpt_base_index = -1;static int	last_drv_idx = -1;static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *  Forward protos... */static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);static int	mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);static int	mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,			u32 *req, int replyBytes, u16 *u16reply, int maxwait,			int sleepFlag);static int	mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);static void	mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);static void	mpt_adapter_disable(MPT_ADAPTER *ioc);static void	mpt_adapter_dispose(MPT_ADAPTER *ioc);static void	MptDisplayIocCapabilities(MPT_ADAPTER *ioc);static int	MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);static int	GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);static int	GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);static int	SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);static int	SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);static int	mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);static int	mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);static int	mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);static int	KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);static int	SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);static int	PrimeIocFifos(MPT_ADAPTER *ioc);static int	WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);static int	WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);static int	WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);static int	GetLanConfigPages(MPT_ADAPTER *ioc);static int	GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);static int	GetIoUnitPage2(MPT_ADAPTER *ioc);int		mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);static int	mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);static int	mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);static void 	mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);static void 	mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);static void	mpt_timer_expired(unsigned long data);static int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);static int	SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);static int	mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);static int	mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);#ifdef CONFIG_PROC_FSstatic int	procmpt_summary_read(char *buf, char **start, off_t offset,				int request, int *eof, void *data);static int	procmpt_version_read(char *buf, char **start, off_t offset,				int request, int *eof, void *data);static int	procmpt_iocinfo_read(char *buf, char **start, off_t offset,				int request, int *eof, void *data);#endifstatic void	mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);//int		mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);static int	ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);static void	mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);static void	mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);static void	mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);static void	mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);/* module entry point */static int  __init    fusion_init  (void);static void __exit    fusion_exit  (void);#define CHIPREG_READ32(addr) 		readl_relaxed(addr)#define CHIPREG_READ32_dmasync(addr)	readl(addr)#define CHIPREG_WRITE32(addr,val) 	writel(val, addr)#define CHIPREG_PIO_WRITE32(addr,val)	outl(val, (unsigned long)addr)#define CHIPREG_PIO_READ32(addr) 	inl((unsigned long)addr)static voidpci_disable_io_access(struct pci_dev *pdev){	u16 command_reg;	pci_read_config_word(pdev, PCI_COMMAND, &command_reg);	command_reg &= ~1;	pci_write_config_word(pdev, PCI_COMMAND, command_reg);}static voidpci_enable_io_access(struct pci_dev *pdev){	u16 command_reg;	pci_read_config_word(pdev, PCI_COMMAND, &command_reg);	command_reg |= 1;	pci_write_config_word(pdev, PCI_COMMAND, command_reg);}/* *  Process turbo (context) reply... */static voidmpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa){	MPT_FRAME_HDR *mf = NULL;	MPT_FRAME_HDR *mr = NULL;	int req_idx = 0;	int cb_idx;	dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",				ioc->name, pa));	switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {	case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:		req_idx = pa & 0x0000FFFF;		cb_idx = (pa & 0x00FF0000) >> 16;		mf = MPT_INDEX_2_MFPTR(ioc, req_idx);		break;	case MPI_CONTEXT_REPLY_TYPE_LAN:		cb_idx = mpt_lan_index;		/*		 *  Blind set of mf to NULL here was fatal		 *  after lan_reply says "freeme"		 *  Fix sort of combined with an optimization here;		 *  added explicit check for case where lan_reply		 *  was just returning 1 and doing nothing else.		 *  For this case skip the callback, but set up		 *  proper mf value first here:-)		 */		if ((pa & 0x58000000) == 0x58000000) {			req_idx = pa & 0x0000FFFF;			mf = MPT_INDEX_2_MFPTR(ioc, req_idx);			mpt_free_msg_frame(ioc, mf);			mb();			return;			break;		}		mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);		break;	case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:		cb_idx = mpt_stm_index;		mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);		break;	default:		cb_idx = 0;		BUG();	}	/*  Check for (valid) IO callback!  */	if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||			MptCallbacks[cb_idx] == NULL) {		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",				__FUNCTION__, ioc->name, cb_idx);		goto out;	}	if (MptCallbacks[cb_idx](ioc, mf, mr))		mpt_free_msg_frame(ioc, mf); out:	mb();}static voidmpt_reply(MPT_ADAPTER *ioc, u32 pa){	MPT_FRAME_HDR	*mf;	MPT_FRAME_HDR	*mr;	int		 req_idx;	int		 cb_idx;	int		 freeme;	u32 reply_dma_low;	u16 ioc_stat;	/* non-TURBO reply!  Hmmm, something may be up...	 *  Newest turbo reply mechanism; get address	 *  via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!	 */	/* Map DMA address of reply header to cpu address.	 * pa is 32 bits - but the dma address may be 32 or 64 bits	 * get offset based only only the low addresses	 */	reply_dma_low = (pa <<= 1);	mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +			 (reply_dma_low - ioc->reply_frames_low_dma));	req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);	cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;	mf = MPT_INDEX_2_MFPTR(ioc, req_idx);	dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",			ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));	DBG_DUMP_REPLY_FRAME(mr)	 /*  Check/log IOC log info	 */	ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);	if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {		u32	 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);		if (ioc->bus_type == FC)			mpt_fc_log_info(ioc, log_info);		else if (ioc->bus_type == SCSI)			mpt_sp_log_info(ioc, log_info);		else if (ioc->bus_type == SAS)			mpt_sas_log_info(ioc, log_info);	}	if (ioc_stat & MPI_IOCSTATUS_MASK) {		if (ioc->bus_type == SCSI &&		    cb_idx != mpt_stm_index &&		    cb_idx != mpt_lan_index)			mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);	}	/*  Check for (valid) IO callback!  */	if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||			MptCallbacks[cb_idx] == NULL) {		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",				__FUNCTION__, ioc->name, cb_idx);		freeme = 0;		goto out;	}	freeme = MptCallbacks[cb_idx](ioc, mf, mr); out:	/*  Flush (non-TURBO) reply with a WRITE!  */	CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);	if (freeme)		mpt_free_msg_frame(ioc, mf);	mb();}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *	mpt_interrupt - MPT adapter (IOC) specific interrupt handler. *	@irq: irq number (not used) *	@bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure *	@r: pt_regs pointer (not used) * *	This routine is registered via the request_irq() kernel API call, *	and handles all interrupts generated from a specific MPT adapter *	(also referred to as a IO Controller or IOC). *	This routine must clear the interrupt from the adapter and does *	so by reading the reply FIFO.  Multiple replies may be processed *	per single call to this routine. * *	This routine handles register-level access of the adapter but *	dispatches (calls) a protocol-specific callback routine to handle *	the protocol-specific details of the MPT request completion. */static irqreturn_tmpt_interrupt(int irq, void *bus_id, struct pt_regs *r){	MPT_ADAPTER *ioc = bus_id;	u32 pa;	/*	 *  Drain the reply FIFO!	 */	while (1) {		pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);		if (pa == 0xFFFFFFFF)			return IRQ_HANDLED;		else if (pa & MPI_ADDRESS_REPLY_A_BIT)			mpt_reply(ioc, pa);		else			mpt_turbo_reply(ioc, pa);	}	return IRQ_HANDLED;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *	mpt_base_reply - MPT base driver's callback routine; all base driver *	"internal" request/reply processing is routed here. *	Currently used for EventNotification and EventAck handling. *	@ioc: Pointer to MPT_ADAPTER structure *	@mf: Pointer to original MPT request frame *	@reply: Pointer to MPT reply frame (NULL if TurboReply) * *	Returns 1 indicating original alloc'd request frame ptr *	should be freed, or 0 if it shouldn't. */static intmpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply){	int freereq = 1;	u8 func;	dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));#if defined(MPT_DEBUG_MSG_FRAME)	if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {		dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));		DBG_DUMP_REQUEST_FRAME_HDR(mf)	}#endif	func = reply->u.hdr.Function;	dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",			ioc->name, func));	if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {		EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;		int evHandlers = 0;		int results;		results = ProcessEventNotification(ioc, pEvReply, &evHandlers);		if (results != evHandlers) {			/* CHECKME! Any special handling needed here? */			devtprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",					ioc->name, evHandlers, results));		}		/*		 *	Hmmm...  It seems that EventNotificationReply is an exception		 *	to the rule of one reply per request.		 */		if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {			freereq = 0;			devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",				ioc->name, pEvReply));		} else {			devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",				ioc->name, pEvReply));		}#ifdef CONFIG_PROC_FS//		LogEvent(ioc, pEvReply);#endif	} else if (func == MPI_FUNCTION_EVENT_ACK) {		dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",				ioc->name));	} else if (func == MPI_FUNCTION_CONFIG ||		   func == MPI_FUNCTION_TOOLBOX) {

⌨️ 快捷键说明

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