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

📄 mptfc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/drivers/message/fusion/mptfc.c *      For use with LSI PCI chip/adapter(s) *      running LSI Fusion MPT (Message Passing Technology) firmware. * *  Copyright (c) 1999-2007 LSI Corporation *  (mailto:DL-MPTFusionLinux@lsi.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/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/workqueue.h>#include <linux/sort.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 <scsi/scsi_transport_fc.h>#include "mptbase.h"#include "mptscsih.h"/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/#define my_NAME		"Fusion MPT FC Host driver"#define my_VERSION	MPT_LINUX_VERSION_COMMON#define MYNAM		"mptfc"MODULE_AUTHOR(MODULEAUTHOR);MODULE_DESCRIPTION(my_NAME);MODULE_LICENSE("GPL");MODULE_VERSION(my_VERSION);/* Command line args */#define MPTFC_DEV_LOSS_TMO (60)static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;	/* reasonable default */module_param(mptfc_dev_loss_tmo, int, 0);MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "    				     " transport to wait for an rport to "				     " return following a device loss event."				     "  Default=60.");/* scsi-mid layer global parmeter is max_report_luns, which is 511 */#define MPTFC_MAX_LUN (16895)static int max_lun = MPTFC_MAX_LUN;module_param(max_lun, int, 0);MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");static u8	mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;static u8	mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;static u8	mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS;static int mptfc_target_alloc(struct scsi_target *starget);static int mptfc_slave_alloc(struct scsi_device *sdev);static int mptfc_qcmd(struct scsi_cmnd *SCpnt,		      void (*done)(struct scsi_cmnd *));static void mptfc_target_destroy(struct scsi_target *starget);static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);static void __devexit mptfc_remove(struct pci_dev *pdev);static int mptfc_abort(struct scsi_cmnd *SCpnt);static int mptfc_dev_reset(struct scsi_cmnd *SCpnt);static int mptfc_bus_reset(struct scsi_cmnd *SCpnt);static int mptfc_host_reset(struct scsi_cmnd *SCpnt);static struct scsi_host_template mptfc_driver_template = {	.module				= THIS_MODULE,	.proc_name			= "mptfc",	.proc_info			= mptscsih_proc_info,	.name				= "MPT FC Host",	.info				= mptscsih_info,	.queuecommand			= mptfc_qcmd,	.target_alloc			= mptfc_target_alloc,	.slave_alloc			= mptfc_slave_alloc,	.slave_configure		= mptscsih_slave_configure,	.target_destroy			= mptfc_target_destroy,	.slave_destroy			= mptscsih_slave_destroy,	.change_queue_depth 		= mptscsih_change_queue_depth,	.eh_abort_handler		= mptfc_abort,	.eh_device_reset_handler	= mptfc_dev_reset,	.eh_bus_reset_handler		= mptfc_bus_reset,	.eh_host_reset_handler		= mptfc_host_reset,	.bios_param			= mptscsih_bios_param,	.can_queue			= MPT_FC_CAN_QUEUE,	.this_id			= -1,	.sg_tablesize			= MPT_SCSI_SG_DEPTH,	.max_sectors			= 8192,	.cmd_per_lun			= 7,	.use_clustering			= ENABLE_CLUSTERING,	.shost_attrs			= mptscsih_host_attrs,};/**************************************************************************** * Supported hardware */static struct pci_device_id mptfc_pci_table[] = {	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC909,		PCI_ANY_ID, PCI_ANY_ID },	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919,		PCI_ANY_ID, PCI_ANY_ID },	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929,		PCI_ANY_ID, PCI_ANY_ID },	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919X,		PCI_ANY_ID, PCI_ANY_ID },	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929X,		PCI_ANY_ID, PCI_ANY_ID },	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC939X,		PCI_ANY_ID, PCI_ANY_ID },	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949X,		PCI_ANY_ID, PCI_ANY_ID },	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E,		PCI_ANY_ID, PCI_ANY_ID },	{ PCI_VENDOR_ID_BROCADE, MPI_MANUFACTPAGE_DEVICEID_FC949E,		PCI_ANY_ID, PCI_ANY_ID },	{0}	/* Terminating entry */};MODULE_DEVICE_TABLE(pci, mptfc_pci_table);static struct scsi_transport_template *mptfc_transport_template = NULL;static struct fc_function_template mptfc_transport_functions = {	.dd_fcrport_size = 8,	.show_host_node_name = 1,	.show_host_port_name = 1,	.show_host_supported_classes = 1,	.show_host_port_id = 1,	.show_rport_supported_classes = 1,	.show_starget_node_name = 1,	.show_starget_port_name = 1,	.show_starget_port_id = 1,	.set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,	.show_rport_dev_loss_tmo = 1,	.show_host_supported_speeds = 1,	.show_host_maxframe_size = 1,	.show_host_speed = 1,	.show_host_fabric_name = 1,	.show_host_port_type = 1,	.show_host_port_state = 1,	.show_host_symbolic_name = 1,};static intmptfc_block_error_handler(struct scsi_cmnd *SCpnt,			  int (*func)(struct scsi_cmnd *SCpnt),			  const char *caller){	MPT_SCSI_HOST		*hd;	struct scsi_device	*sdev = SCpnt->device;	struct Scsi_Host	*shost = sdev->host;	struct fc_rport		*rport = starget_to_rport(scsi_target(sdev));	unsigned long		flags;	int			ready;	MPT_ADAPTER 		*ioc;	hd = shost_priv(SCpnt->device->host);	ioc = hd->ioc;	spin_lock_irqsave(shost->host_lock, flags);	while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {		spin_unlock_irqrestore(shost->host_lock, flags);		dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT			"mptfc_block_error_handler.%d: %d:%d, port status is "			"DID_IMM_RETRY, deferring %s recovery.\n",			ioc->name, ioc->sh->host_no,			SCpnt->device->id, SCpnt->device->lun, caller));		msleep(1000);		spin_lock_irqsave(shost->host_lock, flags);	}	spin_unlock_irqrestore(shost->host_lock, flags);	if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {		dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT			"%s.%d: %d:%d, failing recovery, "			"port state %d, vdevice %p.\n", caller,			ioc->name, ioc->sh->host_no,			SCpnt->device->id, SCpnt->device->lun, ready,			SCpnt->device->hostdata));		return FAILED;	}	dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT		"%s.%d: %d:%d, executing recovery.\n", caller,		ioc->name, ioc->sh->host_no,		SCpnt->device->id, SCpnt->device->lun));	return (*func)(SCpnt);}static intmptfc_abort(struct scsi_cmnd *SCpnt){	return	    mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);}static intmptfc_dev_reset(struct scsi_cmnd *SCpnt){	return	    mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);}static intmptfc_bus_reset(struct scsi_cmnd *SCpnt){	return	    mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);}static intmptfc_host_reset(struct scsi_cmnd *SCpnt){	return	    mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);}static voidmptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout){	if (timeout > 0)		rport->dev_loss_tmo = timeout;	else		rport->dev_loss_tmo = mptfc_dev_loss_tmo;}static intmptfc_FcDevPage0_cmp_func(const void *a, const void *b){	FCDevicePage0_t **aa = (FCDevicePage0_t **)a;	FCDevicePage0_t **bb = (FCDevicePage0_t **)b;	if ((*aa)->CurrentBus == (*bb)->CurrentBus) {		if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)			return 0;		if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)			return -1;		return 1;	}	if ((*aa)->CurrentBus < (*bb)->CurrentBus)		return -1;	return 1;}static intmptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,	void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg)){	ConfigPageHeader_t	 hdr;	CONFIGPARMS		 cfg;	FCDevicePage0_t		*ppage0_alloc, *fc;	dma_addr_t		 page0_dma;	int			 data_sz;	int			 ii;	FCDevicePage0_t		*p0_array=NULL, *p_p0;	FCDevicePage0_t		**pp0_array=NULL, **p_pp0;	int			 rc = -ENOMEM;	U32			 port_id = 0xffffff;	int			 num_targ = 0;	int			 max_bus = ioc->facts.MaxBuses;	int			 max_targ;	max_targ = (ioc->facts.MaxDevices == 0) ? 256 : ioc->facts.MaxDevices;	data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;	p_p0 = p0_array =  kzalloc(data_sz, GFP_KERNEL);	if (!p0_array)		goto out;	data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;	p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);	if (!pp0_array)		goto out;	do {		/* Get FC Device Page 0 header */		hdr.PageVersion = 0;		hdr.PageLength = 0;		hdr.PageNumber = 0;		hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;		cfg.cfghdr.hdr = &hdr;		cfg.physAddr = -1;		cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;		cfg.dir = 0;		cfg.pageAddr = port_id;		cfg.timeout = 0;		if ((rc = mpt_config(ioc, &cfg)) != 0)			break;		if (hdr.PageLength <= 0)			break;		data_sz = hdr.PageLength * 4;		ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,		    					&page0_dma);		rc = -ENOMEM;		if (!ppage0_alloc)			break;		cfg.physAddr = page0_dma;		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;		if ((rc = mpt_config(ioc, &cfg)) == 0) {			ppage0_alloc->PortIdentifier =				le32_to_cpu(ppage0_alloc->PortIdentifier);			ppage0_alloc->WWNN.Low =				le32_to_cpu(ppage0_alloc->WWNN.Low);			ppage0_alloc->WWNN.High =				le32_to_cpu(ppage0_alloc->WWNN.High);			ppage0_alloc->WWPN.Low =				le32_to_cpu(ppage0_alloc->WWPN.Low);			ppage0_alloc->WWPN.High =				le32_to_cpu(ppage0_alloc->WWPN.High);			ppage0_alloc->BBCredit =				le16_to_cpu(ppage0_alloc->BBCredit);			ppage0_alloc->MaxRxFrameSize =				le16_to_cpu(ppage0_alloc->MaxRxFrameSize);			port_id = ppage0_alloc->PortIdentifier;			num_targ++;			*p_p0 = *ppage0_alloc;	/* save data */			*p_pp0++ = p_p0++;	/* save addr */		}		pci_free_consistent(ioc->pcidev, data_sz,		    			(u8 *) ppage0_alloc, page0_dma);		if (rc != 0)			break;	} while (port_id <= 0xff0000);	if (num_targ) {		/* sort array */		if (num_targ > 1)			sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),				mptfc_FcDevPage0_cmp_func, NULL);		/* call caller's func for each targ */		for (ii = 0; ii < num_targ;  ii++) {			fc = *(pp0_array+ii);			func(ioc, ioc_port, fc);		}	} out:	kfree(pp0_array);	kfree(p0_array);	return rc;}static intmptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid){	/* not currently usable */	if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |			  MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))		return -1;	if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))		return -1;	if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))		return -1;	/*	 * board data structure already normalized to platform endianness	 * shifted to avoid unaligned access on 64 bit architecture	 */	rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;	rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;	rid->port_id =   pg0->PortIdentifier;	rid->roles = FC_RPORT_ROLE_UNKNOWN;	return 0;}static voidmptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0){	struct fc_rport_identifiers rport_ids;	struct fc_rport		*rport;	struct mptfc_rport_info	*ri;	int			new_ri = 1;	u64			pn, nn;	VirtTarget		*vtarget;	u32			roles = FC_RPORT_ROLE_UNKNOWN;	if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)		return;	roles |= FC_RPORT_ROLE_FCP_TARGET;	if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)		roles |= FC_RPORT_ROLE_FCP_INITIATOR;	/* scan list looking for a match */	list_for_each_entry(ri, &ioc->fc_rports, list) {		pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;		if (pn == rport_ids.port_name) {	/* match */			list_move_tail(&ri->list, &ioc->fc_rports);			new_ri = 0;			break;		}	}	if (new_ri) {	/* allocate one */		ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);		if (!ri)			return;		list_add_tail(&ri->list, &ioc->fc_rports);	}	ri->pg0 = *pg0;	/* add/update pg0 data */	ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;	/* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */	if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {		ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;		rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);		if (rport) {			ri->rport = rport;			if (new_ri) /* may have been reset by user */				rport->dev_loss_tmo = mptfc_dev_loss_tmo;			/*			 * if already mapped, remap here.  If not mapped,			 * target_alloc will allocate vtarget and map,			 * slave_alloc will fill in vdevice from vtarget.			 */			if (ri->starget) {				vtarget = ri->starget->hostdata;				if (vtarget) {					vtarget->id = pg0->CurrentTargetID;					vtarget->channel = pg0->CurrentBus;				}			}			*((struct mptfc_rport_info **)rport->dd_data) = ri;			/* scan will be scheduled once rport becomes a target */			fc_remote_port_rolechg(rport,roles);			pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;			nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;			dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT				"mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "				"rport tid %d, tmo %d\n",					ioc->name,					ioc->sh->host_no,					pg0->PortIdentifier,					(unsigned long long)nn,					(unsigned long long)pn,					pg0->CurrentTargetID,					ri->rport->scsi_target_id,					ri->rport->dev_loss_tmo));		} else {			list_del(&ri->list);			kfree(ri);			ri = NULL;		}	}}/* *	OS entry point to allow for host driver to free allocated memory *	Called if no device present or device being unloaded */static voidmptfc_target_destroy(struct scsi_target *starget){	struct fc_rport		*rport;	struct mptfc_rport_info *ri;	rport = starget_to_rport(starget);	if (rport) {		ri = *((struct mptfc_rport_info **)rport->dd_data);		if (ri)	/* better be! */

⌨️ 快捷键说明

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