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

📄 mptspi.c

📁 linux-2.6.15.6
💻 C
字号:
/* *  linux/drivers/message/fusion/mptspi.c *      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_compat.h"	/* linux-2.6 tweaks */#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/kdev_t.h>#include <linux/blkdev.h>#include <linux/delay.h>	/* for mdelay */#include <linux/interrupt.h>	/* needed for in_interrupt() proto */#include <linux/reboot.h>	/* notifier code */#include <linux/sched.h>#include <linux/workqueue.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>#include "mptbase.h"#include "mptscsih.h"/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/#define my_NAME		"Fusion MPT SPI Host driver"#define my_VERSION	MPT_LINUX_VERSION_COMMON#define MYNAM		"mptspi"MODULE_AUTHOR(MODULEAUTHOR);MODULE_DESCRIPTION(my_NAME);MODULE_LICENSE("GPL");/* Command line args */#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATIONstatic int mpt_dv = MPTSCSIH_DOMAIN_VALIDATION;module_param(mpt_dv, int, 0);MODULE_PARM_DESC(mpt_dv, " DV Algorithm: enhanced=1, basic=0 (default=MPTSCSIH_DOMAIN_VALIDATION=1)");static int mpt_width = MPTSCSIH_MAX_WIDTH;module_param(mpt_width, int, 0);MODULE_PARM_DESC(mpt_width, " Max Bus Width: wide=1, narrow=0 (default=MPTSCSIH_MAX_WIDTH=1)");static ushort mpt_factor = MPTSCSIH_MIN_SYNC;module_param(mpt_factor, ushort, 0);MODULE_PARM_DESC(mpt_factor, " Min Sync Factor (default=MPTSCSIH_MIN_SYNC=0x08)");#endifstatic int mpt_saf_te = MPTSCSIH_SAF_TE;module_param(mpt_saf_te, int, 0);MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1  (default=MPTSCSIH_SAF_TE=0)");static int mpt_pq_filter = 0;module_param(mpt_pq_filter, int, 0);MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1  (default=0)");static int	mptspiDoneCtx = -1;static int	mptspiTaskCtx = -1;static int	mptspiInternalCtx = -1; /* Used only for internal commands */static struct scsi_host_template mptspi_driver_template = {	.proc_name			= "mptspi",	.proc_info			= mptscsih_proc_info,	.name				= "MPT SPI Host",	.info				= mptscsih_info,	.queuecommand			= mptscsih_qcmd,	.slave_alloc			= mptscsih_slave_alloc,	.slave_configure		= mptscsih_slave_configure,	.slave_destroy			= mptscsih_slave_destroy,	.change_queue_depth 		= mptscsih_change_queue_depth,	.eh_abort_handler		= mptscsih_abort,	.eh_device_reset_handler	= mptscsih_dev_reset,	.eh_bus_reset_handler		= mptscsih_bus_reset,	.eh_host_reset_handler		= mptscsih_host_reset,	.bios_param			= mptscsih_bios_param,	.can_queue			= MPT_SCSI_CAN_QUEUE,	.this_id			= -1,	.sg_tablesize			= MPT_SCSI_SG_DEPTH,	.max_sectors			= 8192,	.cmd_per_lun			= 7,	.use_clustering			= ENABLE_CLUSTERING,};/**************************************************************************** * Supported hardware */static struct pci_device_id mptspi_pci_table[] = {	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1030,		PCI_ANY_ID, PCI_ANY_ID },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_1030_53C1035,		PCI_ANY_ID, PCI_ANY_ID },	{0}	/* Terminating entry */};MODULE_DEVICE_TABLE(pci, mptspi_pci_table);/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *	mptspi_probe - Installs scsi devices per bus. *	@pdev: Pointer to pci_dev structure * *	Returns 0 for success, non-zero for failure. * */static intmptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id){	struct Scsi_Host	*sh;	MPT_SCSI_HOST		*hd;	MPT_ADAPTER 		*ioc;	unsigned long		 flags;	int			 sz, ii;	int			 numSGE = 0;	int			 scale;	int			 ioc_cap;	u8			*mem;	int			error=0;	int			r;	if ((r = mpt_attach(pdev,id)) != 0)		return r;	ioc = pci_get_drvdata(pdev);	ioc->DoneCtx = mptspiDoneCtx;	ioc->TaskCtx = mptspiTaskCtx;	ioc->InternalCtx = mptspiInternalCtx;	/*  Added sanity check on readiness of the MPT adapter.	 */	if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {		printk(MYIOC_s_WARN_FMT		  "Skipping because it's not operational!\n",		  ioc->name);		return -ENODEV;	}	if (!ioc->active) {		printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",		  ioc->name);		return -ENODEV;	}	/*  Sanity check - ensure at least 1 port is INITIATOR capable	 */	ioc_cap = 0;	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {		if (ioc->pfacts[ii].ProtocolFlags &		    MPI_PORTFACTS_PROTOCOL_INITIATOR)			ioc_cap ++;	}	if (!ioc_cap) {		printk(MYIOC_s_WARN_FMT			"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",			ioc->name, ioc);		return 0;	}	sh = scsi_host_alloc(&mptspi_driver_template, sizeof(MPT_SCSI_HOST));	if (!sh) {		printk(MYIOC_s_WARN_FMT			"Unable to register controller with SCSI subsystem\n",			ioc->name);                return -1;        }	spin_lock_irqsave(&ioc->FreeQlock, flags);	/* Attach the SCSI Host to the IOC structure	 */	ioc->sh = sh;	sh->io_port = 0;	sh->n_io_port = 0;	sh->irq = 0;	/* set 16 byte cdb's */	sh->max_cmd_len = 16;	/* Yikes!  This is important!	 * Otherwise, by default, linux	 * only scans target IDs 0-7!	 * pfactsN->MaxDevices unreliable	 * (not supported in early	 *	versions of the FW).	 * max_id = 1 + actual max id,	 * max_lun = 1 + actual last lun,	 *	see hosts.h :o(	 */	sh->max_id = MPT_MAX_SCSI_DEVICES;	sh->max_lun = MPT_LAST_LUN + 1;	sh->max_channel = 0;	sh->this_id = ioc->pfacts[0].PortSCSIID;	/* Required entry.	 */	sh->unique_id = ioc->id;	/* Verify that we won't exceed the maximum	 * number of chain buffers	 * We can optimize:  ZZ = req_sz/sizeof(SGE)	 * For 32bit SGE's:	 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ	 *               + (req_sz - 64)/sizeof(SGE)	 * A slightly different algorithm is required for	 * 64bit SGEs.	 */	scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));	if (sizeof(dma_addr_t) == sizeof(u64)) {		numSGE = (scale - 1) *		  (ioc->facts.MaxChainDepth-1) + scale +		  (ioc->req_sz - 60) / (sizeof(dma_addr_t) +		  sizeof(u32));	} else {		numSGE = 1 + (scale - 1) *		  (ioc->facts.MaxChainDepth-1) + scale +		  (ioc->req_sz - 64) / (sizeof(dma_addr_t) +		  sizeof(u32));	}	if (numSGE < sh->sg_tablesize) {		/* Reset this value */		dprintk((MYIOC_s_INFO_FMT		  "Resetting sg_tablesize to %d from %d\n",		  ioc->name, numSGE, sh->sg_tablesize));		sh->sg_tablesize = numSGE;	}	spin_unlock_irqrestore(&ioc->FreeQlock, flags);	hd = (MPT_SCSI_HOST *) sh->hostdata;	hd->ioc = ioc;	/* SCSI needs scsi_cmnd lookup table!	 * (with size equal to req_depth*PtrSz!)	 */	sz = ioc->req_depth * sizeof(void *);	mem = kmalloc(sz, GFP_ATOMIC);	if (mem == NULL) {		error = -ENOMEM;		goto mptspi_probe_failed;	}	memset(mem, 0, sz);	hd->ScsiLookup = (struct scsi_cmnd **) mem;	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",		 ioc->name, hd->ScsiLookup, sz));	/* Allocate memory for the device structures.	 * A non-Null pointer at an offset	 * indicates a device exists.	 * max_id = 1 + maximum id (hosts.h)	 */	sz = sh->max_id * sizeof(void *);	mem = kmalloc(sz, GFP_ATOMIC);	if (mem == NULL) {		error = -ENOMEM;		goto mptspi_probe_failed;	}	memset(mem, 0, sz);	hd->Targets = (VirtDevice **) mem;	dprintk((KERN_INFO	  "  Targets @ %p, sz=%d\n", hd->Targets, sz));	/* Clear the TM flags	 */	hd->tmPending = 0;	hd->tmState = TM_STATE_NONE;	hd->resetPending = 0;	hd->abortSCpnt = NULL;	/* Clear the pointer used to store	 * single-threaded commands, i.e., those	 * issued during a bus scan, dv and	 * configuration pages.	 */	hd->cmdPtr = NULL;	/* Initialize this SCSI Hosts' timers	 * To use, set the timer expires field	 * and add_timer	 */	init_timer(&hd->timer);	hd->timer.data = (unsigned long) hd;	hd->timer.function = mptscsih_timer_expired;	ioc->spi_data.Saf_Te = mpt_saf_te;	hd->mpt_pq_filter = mpt_pq_filter;#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION	if (ioc->spi_data.maxBusWidth > mpt_width)		ioc->spi_data.maxBusWidth = mpt_width;	if (ioc->spi_data.minSyncFactor < mpt_factor)		ioc->spi_data.minSyncFactor = mpt_factor;	if (ioc->spi_data.minSyncFactor == MPT_ASYNC) {		ioc->spi_data.maxSyncOffset = 0;	}	ioc->spi_data.mpt_dv = mpt_dv;	hd->negoNvram = 0;	ddvprintk((MYIOC_s_INFO_FMT		"dv %x width %x factor %x saf_te %x mpt_pq_filter %x\n",		ioc->name,		mpt_dv,		mpt_width,		mpt_factor,		mpt_saf_te,		mpt_pq_filter));#else	hd->negoNvram = MPT_SCSICFG_USE_NVRAM;	ddvprintk((MYIOC_s_INFO_FMT		"saf_te %x mpt_pq_filter %x\n",		ioc->name,		mpt_saf_te,		mpt_pq_filter));#endif	ioc->spi_data.forceDv = 0;	ioc->spi_data.noQas = 0;	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)		ioc->spi_data.dvStatus[ii] =		  MPT_SCSICFG_NEGOTIATE;	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)		ioc->spi_data.dvStatus[ii] |=		  MPT_SCSICFG_DV_NOT_DONE;	init_waitqueue_head(&hd->scandv_waitq);	hd->scandv_wait_done = 0;	hd->last_queue_full = 0;	error = scsi_add_host (sh, &ioc->pcidev->dev);	if(error) {		dprintk((KERN_ERR MYNAM		  "scsi_add_host failed\n"));		goto mptspi_probe_failed;	}	scsi_scan_host(sh);	return 0;mptspi_probe_failed:	mptscsih_remove(pdev);	return error;}static struct pci_driver mptspi_driver = {	.name		= "mptspi",	.id_table	= mptspi_pci_table,	.probe		= mptspi_probe,	.remove		= __devexit_p(mptscsih_remove),	.shutdown	= mptscsih_shutdown,#ifdef CONFIG_PM	.suspend	= mptscsih_suspend,	.resume		= mptscsih_resume,#endif};/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** *	mptspi_init - Register MPT adapter(s) as SCSI host(s) with *	linux scsi mid-layer. * *	Returns 0 for success, non-zero for failure. */static int __initmptspi_init(void){	show_mptmod_ver(my_NAME, my_VERSION);	mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER);	mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER);	mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER);	if (mpt_event_register(mptspiDoneCtx, mptscsih_event_process) == 0) {		devtprintk((KERN_INFO MYNAM		  ": Registered for IOC event notifications\n"));	}	if (mpt_reset_register(mptspiDoneCtx, mptscsih_ioc_reset) == 0) {		dprintk((KERN_INFO MYNAM		  ": Registered for IOC reset notifications\n"));	}	return pci_register_driver(&mptspi_driver);}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** *	mptspi_exit - Unregisters MPT adapter(s) * */static void __exitmptspi_exit(void){	pci_unregister_driver(&mptspi_driver);		mpt_reset_deregister(mptspiDoneCtx);	dprintk((KERN_INFO MYNAM	  ": Deregistered for IOC reset notifications\n"));	mpt_event_deregister(mptspiDoneCtx);	dprintk((KERN_INFO MYNAM	  ": Deregistered for IOC event notifications\n"));	mpt_deregister(mptspiInternalCtx);	mpt_deregister(mptspiTaskCtx);	mpt_deregister(mptspiDoneCtx);}module_init(mptspi_init);module_exit(mptspi_exit);

⌨️ 快捷键说明

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