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

📄 mptscsih.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  linux/drivers/message/fusion/mptscsih.c *      High performance SCSI / Fibre Channel SCSI Host device 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! * *      (see mptbase.c) * *  Copyright (c) 1999-2002 LSI Logic Corporation *  Original author: Steven J. Ralston *  (mailto:sjralston1@netscape.net) *  (mailto:Pam.Delaney@lsil.com) * *  $Id: mptscsih.c,v 1.103 2002/10/17 20:15:59 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/module.h>#include <linux/version.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/kdev_t.h>#include <linux/blkdev.h>#include <linux/blk.h>		/* for io_request_lock (spinlock) decl */#include <linux/delay.h>	/* for mdelay */#include <linux/interrupt.h>	/* needed for in_interrupt() proto */#include <linux/reboot.h>	/* notifier code */#include "../../scsi/scsi.h"#include "../../scsi/hosts.h"#include "../../scsi/sd.h"#include "mptbase.h"#include "mptscsih.h"#include "isense.h"/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/#define my_NAME		"Fusion MPT SCSI Host driver"#define my_VERSION	MPT_LINUX_VERSION_COMMON#define MYNAM		"mptscsih"MODULE_AUTHOR(MODULEAUTHOR);MODULE_DESCRIPTION(my_NAME);MODULE_LICENSE("GPL");/* Set string for command line args from insmod */#ifdef MODULEchar *mptscsih = 0;MODULE_PARM(mptscsih, "s");#endif/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/typedef struct _BIG_SENSE_BUF {	u8		data[MPT_SENSE_BUFFER_ALLOC];} BIG_SENSE_BUF;#define MPT_SCANDV_GOOD			(0x00000000) /* must be 0 */#define MPT_SCANDV_DID_RESET		(0x00000001)#define MPT_SCANDV_SENSE		(0x00000002)#define MPT_SCANDV_SOME_ERROR		(0x00000004)#define MPT_SCANDV_SELECTION_TIMEOUT	(0x00000008)#define MPT_SCANDV_ISSUE_SENSE		(0x00000010)#define MPT_SCANDV_MAX_RETRIES		(10)#define MPT_ICFLAG_BUF_CAP	0x01	/* ReadBuffer Read Capacity format */#define MPT_ICFLAG_ECHO		0x02	/* ReadBuffer Echo buffer format */#define MPT_ICFLAG_PHYS_DISK	0x04	/* Any SCSI IO but do Phys Disk Format */#define MPT_ICFLAG_TAGGED_CMD	0x08	/* Do tagged IO */#define MPT_ICFLAG_DID_RESET	0x20	/* Bus Reset occured with this command */#define MPT_ICFLAG_RESERVED	0x40	/* Reserved has been issued */typedef struct _internal_cmd {	char		*data;		/* data pointer */	dma_addr_t	data_dma;	/* data dma address */	int		size;		/* transfer size */	u8		cmd;		/* SCSI Op Code */	u8		bus;		/* bus number */	u8		id;		/* SCSI ID (virtual) */	u8		lun;	u8		flags;		/* Bit Field - See above */	u8		physDiskNum;	/* Phys disk number, -1 else */	u8		rsvd2;	u8		rsvd;} INTERNAL_CMD;typedef struct _negoparms {	u8 width;	u8 offset;	u8 factor;	u8 flags;} NEGOPARMS;typedef struct _dv_parameters {	NEGOPARMS	 max;	NEGOPARMS	 now;	u8		 cmd;	u8		 id;	u16		 pad1;} DVPARAMETERS;/* *  Other private/forward protos... */static int	mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);static void	mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);static int	mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);static int	mptscsih_io_direction(Scsi_Cmnd *cmd);static int	mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,				 SCSIIORequest_t *pReq, int req_idx);static int	mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex);static void	mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);static int	mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);static void	copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);#ifndef MPT_SCSI_USE_NEW_EHstatic void	search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd);#elsestatic int	mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);#endifstatic u32	SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc);static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx);static void	post_pendingQ_commands(MPT_SCSI_HOST *hd);static int	mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag);static int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag);static int	mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);static int	mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);static VirtDevice	*mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);#ifdef MPT_SAVE_AUTOSENSEstatic void	clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);#endifstatic void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);static void	mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);static int	mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);static int	mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);static void	mptscsih_timer_expired(unsigned long data);static void	mptscsih_taskmgmt_timeout(unsigned long data);static int	mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);static int	mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum);#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATIONstatic int	mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);static void	mptscsih_domainValidation(void *hd);static int	mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);static void	mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);static int	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);static void	mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);static void	mptscsih_fillbuf(char *buffer, int size, int index, int width);#endifstatic int	mptscsih_setup(char *str);static int	mptscsih_halt(struct notifier_block *nb, ulong event, void *buf);/* *	Reboot Notification */static struct notifier_block mptscsih_notifier = {	mptscsih_halt, NULL, 0};/* *	Private data... */static int	mpt_scsi_hosts = 0;static atomic_t	queue_depth;static int	ScsiDoneCtx = -1;static int	ScsiTaskCtx = -1;static int	ScsiScanDvCtx = -1; /* Used only for bus scan and dv */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)static struct proc_dir_entry proc_mpt_scsihost ={	.low_ino =	PROC_SCSI_MPT,	.namelen =	8,	.name =		"mptscsih",	.mode =		S_IFDIR | S_IRUGO | S_IXUGO,	.nlink =	2,};#endif#define SNS_LEN(scp)	sizeof((scp)->sense_buffer)#ifndef MPT_SCSI_USE_NEW_EH/* *  Stuff to handle single-threading SCSI TaskMgmt *  (abort/reset) requests... */static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED;static int mytaskQ_bh_active = 0;static struct mpt_work_struct	mptscsih_ptaskfoo;static atomic_t	mpt_taskQdepth;#endif#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION/* * Domain Validation task structure */static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED;static int dvtaskQ_active = 0;static int dvtaskQ_release = 0;static struct mpt_work_struct	mptscsih_dvTask;#endif/* * Wait Queue setup */static DECLARE_WAIT_QUEUE_HEAD (scandv_waitq);static int scandv_wait_done = 1;/* Driver default setup */static struct mptscsih_driver_setup	driver_setup = MPTSCSIH_DRIVER_SETUP;/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *	mptscsih_io_done - Main SCSI IO callback routine registered to *	Fusion MPT (base) driver *	@ioc: Pointer to MPT_ADAPTER structure *	@mf: Pointer to original MPT request frame *	@r: Pointer to MPT reply frame (NULL if TurboReply) * *	This routine is called from mpt.c::mpt_interrupt() at the completion *	of any SCSI IO request. *	This routine is registered with the Fusion MPT (base) driver at driver *	load/init time via the mpt_register() API call. * *	Returns 1 indicating alloc'd request frame ptr should be freed. */static intmptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr){	Scsi_Cmnd	*sc;	MPT_SCSI_HOST	*hd;	SCSIIORequest_t	*pScsiReq;	SCSIIOReply_t	*pScsiReply;#ifndef MPT_SCSI_USE_NEW_EH	unsigned long	 flags;#endif	u16		 req_idx;	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;	if ((mf == NULL) ||	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {		printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",				ioc->name, mf?"BAD":"NULL", (void *) mf);		/* return 1; CHECKME SteveR. Don't free. */		return 0;	}	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);	sc = hd->ScsiLookup[req_idx];	if (sc == NULL) {		MPIHeader_t *hdr = (MPIHeader_t *)mf;		atomic_dec(&queue_depth);		/* writeSDP1 will use the ScsiDoneCtx		 * There is no processing for the reply.		 * Just return to the calling function.		 */		if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)			printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);		mptscsih_freeChainBuffers(hd, req_idx);		return 1;	}	dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",			ioc->name, mf, mr, sc, req_idx));	atomic_dec(&queue_depth);	sc->result = DID_OK << 16;		/* Set default reply as OK */	pScsiReq = (SCSIIORequest_t *) mf;	pScsiReply = (SCSIIOReply_t *) mr;	if (pScsiReply == NULL) {		/* special context reply handling */		/* If regular Inquiry cmd - save inquiry data		 */		if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) {			int	 dlen;			dlen = le32_to_cpu(pScsiReq->DataLength);			if (dlen >= SCSI_STD_INQUIRY_BYTES) {				mptscsih_initTarget(hd,						hd->port,						sc->target,						pScsiReq->LUN[1],						sc->buffer,						dlen);			}		}#ifdef MPT_SAVE_AUTOSENSE		clear_sense_flag(hd, pScsiReq);#endif	} else {		u32	 xfer_cnt;		u16	 status;		u8	 scsi_state;		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;		scsi_state = pScsiReply->SCSIState;		dprintk((KERN_NOTICE "  Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",				ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],				mf, mr, sc));		dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"				", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",				status, scsi_state, pScsiReply->SCSIStatus,				le32_to_cpu(pScsiReply->IOCLogInfo)));		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)			copy_sense_data(sc, hd, mf, pScsiReply);		/*		 *  Look for + dump FCP ResponseInfo[]!		 */		if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {			dprintk((KERN_NOTICE "  FCP_ResponseInfo=%08xh\n",					     le32_to_cpu(pScsiReply->ResponseInfo)));		}		switch(status) {		case MPI_IOCSTATUS_BUSY:			/* 0x0002 */			/* CHECKME!			 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)			 * But not: DID_BUS_BUSY lest one risk			 * killing interrupt handler:-(			 */			sc->result = STS_BUSY;			break;		case MPI_IOCSTATUS_SCSI_INVALID_BUS:		/* 0x0041 */		case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:	/* 0x0042 */			sc->result = DID_BAD_TARGET << 16;			break;		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */			/* Spoof to SCSI Selection Timeout! */			sc->result = DID_NO_CONNECT << 16;			break;		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */#ifndef MPT_SCSI_USE_NEW_EH			search_taskQ_for_cmd(sc, hd);#endif			/* Linux handles an unsolicited DID_RESET better 			 * than an unsolicited DID_ABORT.			 */			sc->result = DID_RESET << 16;			/* GEM Workaround. */ 			if (hd->is_spi)				mptscsih_no_negotiate(hd, sc->target);			break;		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */#ifndef MPT_SCSI_USE_NEW_EH			search_taskQ_for_cmd(sc, hd);#endif			sc->result = DID_RESET << 16;			/* GEM Workaround. */ 			if (hd->is_spi)				mptscsih_no_negotiate(hd, sc->target);			break;		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */			/*			 *  YIKES!  I just discovered that SCSI IO which			 *  returns check condition, SenseKey=05 (ILLEGAL REQUEST)			 *  and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),			 *  comes down this path!			 *  Do upfront check for valid SenseData and give it			 *  precedence!			 */			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;#ifdef MPT_SAVE_AUTOSENSE			clear_sense_flag(hd, pScsiReq);#endif			if (scsi_state == 0) {				;			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {				/* Have already saved the status and sense data				 */				;			} else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {				/* What to do?				 */				sc->result = DID_SOFT_ERROR << 16;			}			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {				/*  Not real sure here either...  */				sc->result = DID_RESET << 16;			}			/* Give report and update residual count.			 */			xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);			dprintk((KERN_NOTICE "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",

⌨️ 快捷键说明

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