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

📄 mptscsih.c

📁 ARM S3C2410 linux2.4 内核源码
💻 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 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-2001 LSI Logic Corporation *  Original author: Steven J. Ralston *  (mailto:Steve.Ralston@lsil.com) * *  $Id: mptscsih.c,v 1.29.4.1 2001/09/18 03:22:30 sralston 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 "../../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");/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/typedef struct _BIG_SENSE_BUF {	u8		data[256];} BIG_SENSE_BUF;typedef struct _MPT_SCSI_HOST {	MPT_ADAPTER		 *ioc;	int			  port;	struct scsi_cmnd	**ScsiLookup;	u8			 *SgHunks;	dma_addr_t		  SgHunksDMA;	u32			  qtag_tick;} MPT_SCSI_HOST;typedef struct _MPT_SCSI_DEV {	struct _MPT_SCSI_DEV	 *forw;	struct _MPT_SCSI_DEV	 *back;	MPT_ADAPTER		 *ioc;	int			  sense_sz;	BIG_SENSE_BUF		  CachedSense;	unsigned long		  io_cnt;	unsigned long		  read_cnt;} MPT_SCSI_DEV;/* *  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 void	copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);static u32	SCPNT_TO_MSGCTX(Scsi_Cmnd *sc);static int	mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);static int	mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);static int	mpt_scsi_hosts = 0;static atomic_t	queue_depth;static int	ScsiDoneCtx = -1;static int	ScsiTaskCtx = -1;#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 mpt_scsih_taskQ_lock = SPIN_LOCK_UNLOCKED;static MPT_Q_TRACKER mpt_scsih_taskQ = {	(MPT_FRAME_HDR*) &mpt_scsih_taskQ,	(MPT_FRAME_HDR*) &mpt_scsih_taskQ};static int mpt_scsih_taskQ_cnt = 0;static int mpt_scsih_taskQ_bh_active = 0;static MPT_FRAME_HDR *mpt_scsih_active_taskmgmt_mf = NULL;#endif/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *	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 *r){	Scsi_Cmnd	*sc;	MPT_SCSI_HOST	*hd;	MPT_SCSI_DEV	*mpt_sdev = NULL;	u16		 req_idx;	if ((mf == NULL) ||	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {		printk(KERN_ERR MYNAM ": ERROR! NULL or BAD req frame ptr (=%p)!\n", mf);		return 1;	}	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);	sc = hd->ScsiLookup[req_idx];	hd->ScsiLookup[req_idx] = NULL;	dmfprintk((KERN_INFO MYNAM ": ScsiDone (req:sc:reply=%p:%p:%p)\n", mf, sc, r));	atomic_dec(&queue_depth);	/*	 *  Check for {1st} {IO} completion to "new" device.	 *  How do we know it's a new device?	 *  If we haven't set SDpnt->hostdata I guess...	 */	if (sc && sc->device) {		mpt_sdev = (MPT_SCSI_DEV*)sc->device->hostdata;		if (!mpt_sdev) {			dprintk((KERN_INFO MYNAM ": *NEW* SCSI device (%d:%d:%d)!\n",					   sc->device->id, sc->device->lun, sc->device->channel));			if ((sc->device->hostdata = kmalloc(sizeof(MPT_SCSI_DEV), GFP_ATOMIC)) == NULL) {				printk(KERN_ERR MYNAM ": ERROR - kmalloc(%d) FAILED!\n", (int)sizeof(MPT_SCSI_DEV));			} else {				memset(sc->device->hostdata, 0, sizeof(MPT_SCSI_DEV));				mpt_sdev = (MPT_SCSI_DEV *) sc->device->hostdata;				mpt_sdev->ioc = ioc;			}		} else {			if (++mpt_sdev->io_cnt && mptscsih_io_direction(sc) < 0) {				if (++mpt_sdev->read_cnt == 3) {					dprintk((KERN_INFO MYNAM ": 3rd DATA_IN, CDB[0]=%02x\n",							sc->cmnd[0]));				}			}#if 0			if (mpt_sdev->sense_sz) {				/*				 *  Completion of first IO down this path				 *  *should* invalidate device SenseData...				 */				mpt_sdev->sense_sz = 0;			}#endif		}	}#if 0{	MPT_FRAME_HDR	*mf_chk;	/* This, I imagine, is a costly check, but...	 *  If abort/reset active, check to see if this is a IO	 *  that completed while ABORT/RESET for it is waiting	 *  on our taskQ!	 */	if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) {		/* If ABORT for this IO is queued, zap it! */		mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);		if (mf_chk != NULL) {			sc->result = DID_ABORT << 16;			spin_lock_irqsave(&io_request_lock, flags);			sc->scsi_done(sc);			spin_unlock_irqrestore(&io_request_lock, flags);			return 1;		}	}}#endif	if (r != NULL && sc != NULL) {		SCSIIOReply_t	*pScsiReply;		SCSIIORequest_t *pScsiReq;		u16		 status;		pScsiReply = (SCSIIOReply_t *) r;		pScsiReq = (SCSIIORequest_t *) mf;		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;		dprintk((KERN_NOTICE MYNAM ": Uh-Oh!  (req:sc:reply=%p:%p:%p)\n", mf, sc, r));		dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"				     ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",				     status, pScsiReply->SCSIState, pScsiReply->SCSIStatus,				     le32_to_cpu(pScsiReply->IOCLogInfo)));		/*		 *  Look for + dump FCP ResponseInfo[]!		 */		if (pScsiReply->SCSIState & 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 */			/*sc->result = DID_BUS_BUSY << 16;*/		/* YIKES! - Seems to									 * kill linux interrupt									 * handler									 */			sc->result = STS_BUSY;				/* Try SCSI BUSY! */			break;		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */			/*  Not real sure here...  */			sc->result = DID_OK << 16;			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_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!			 */			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {				copy_sense_data(sc, hd, mf, pScsiReply);				sc->result = pScsiReply->SCSIStatus;				break;			}			dprintk((KERN_NOTICE MYNAM ": sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow));			dprintk((KERN_NOTICE MYNAM ": ActBytesXferd=%02xh\n", le32_to_cpu(pScsiReply->TransferCount)));#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)			sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount);			dprintk((KERN_NOTICE MYNAM ": SET sc->resid=%02xh\n", sc->resid));#endif			if (pScsiReq->CDB[0] == INQUIRY) {				sc->result = (DID_OK << 16);				break;			}			/* workaround attempts... */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)			if (sc->resid >= 0x200) {				/* GRRRRR...				 *   //sc->result = DID_SOFT_ERROR << 16;				 * Try spoofing to BUSY				 */				sc->result = STS_BUSY;			} else {				sc->result = 0;			}#else			sc->result = 0;#endif			break;		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */			sc->result = DID_ABORT << 16;			break;		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */			sc->result = DID_RESET << 16;			break;		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */			sc->result = pScsiReply->SCSIStatus;			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {				copy_sense_data(sc, hd, mf, pScsiReply);				/*  If running agains circa 200003dd 909 MPT f/w,				 *  may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL				 *  (QUEUE_FULL) returned from device!	--> get 0x0000?128				 *  and with SenseBytes set to 0.				 */				if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)					mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);			}			else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {				/*				 *  What to do?				 */				sc->result = DID_SOFT_ERROR << 16;			}			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {				/*  Not real sure here either...  */				sc->result = DID_ABORT << 16;			}			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);			break;		case MPI_IOCSTATUS_INVALID_FUNCTION:		/* 0x0001 */		case MPI_IOCSTATUS_INVALID_SGL:			/* 0x0003 */		case MPI_IOCSTATUS_INTERNAL_ERROR:		/* 0x0004 */		case MPI_IOCSTATUS_RESERVED:			/* 0x0005 */		case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:	/* 0x0006 */		case MPI_IOCSTATUS_INVALID_FIELD:		/* 0x0007 */		case MPI_IOCSTATUS_INVALID_STATE:		/* 0x0008 */		case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:		/* 0x0044 */		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */		case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:	/* 0x004A */		default:			/*			 *  What to do?			 */			sc->result = DID_SOFT_ERROR << 16;			break;		}	/* switch(status) */		dprintk((KERN_NOTICE MYNAM ": sc->result set to %08xh\n", sc->result));	}	if (sc != NULL) {		unsigned long flags;		/* Unmap the DMA buffers, if any. */		if (sc->use_sg) {			pci_unmap_sg(ioc->pcidev,				     (struct scatterlist *) sc->request_buffer,				     sc->use_sg,				     scsi_to_pci_dma_dir(sc->sc_data_direction));		} else if (sc->request_bufflen) {			pci_unmap_single(ioc->pcidev,					 (dma_addr_t)((long)sc->SCp.ptr),					 sc->request_bufflen,					 scsi_to_pci_dma_dir(sc->sc_data_direction));		}		spin_lock_irqsave(&io_request_lock, flags);		sc->scsi_done(sc);		spin_unlock_irqrestore(&io_request_lock, flags);	}	return 1;}#ifndef MPT_SCSI_USE_NEW_EH/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *	search_taskQ - Search SCSI task mgmt request queue for specific *			request type *	@remove: (Boolean) Should request be removed if found? *	@sc: Pointer to Scsi_Cmnd structure *	@task_type: Task type to search for * *	Returns pointer to MPT request frame if found, or %NULL if request *	was not found. */static MPT_FRAME_HDR *search_taskQ(int remove, Scsi_Cmnd *sc, u8 task_type){	MPT_FRAME_HDR *mf = NULL;	unsigned long flags;

⌨️ 快捷键说明

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