brintos

brintos / linux-shallow public Read only

0
0
Text · 42.5 KiB · 91242f2 Raw
1585 lines · c
1/*2 *  linux/drivers/message/fusion/mptfc.c3 *      For use with LSI PCI chip/adapter(s)4 *      running LSI Fusion MPT (Message Passing Technology) firmware.5 *6 *  Copyright (c) 1999-2008 LSI Corporation7 *  (mailto:DL-MPTFusionLinux@lsi.com)8 *9 */10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/11/*12    This program is free software; you can redistribute it and/or modify13    it under the terms of the GNU General Public License as published by14    the Free Software Foundation; version 2 of the License.15 16    This program is distributed in the hope that it will be useful,17    but WITHOUT ANY WARRANTY; without even the implied warranty of18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the19    GNU General Public License for more details.20 21    NO WARRANTY22    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR23    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT24    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,25    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is26    solely responsible for determining the appropriateness of using and27    distributing the Program and assumes all risks associated with its28    exercise of rights under this Agreement, including but not limited to29    the risks and costs of program errors, damage to or loss of data,30    programs or equipment, and unavailability or interruption of operations.31 32    DISCLAIMER OF LIABILITY33    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY34    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL35    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND36    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR37    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE38    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED39    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES40 41    You should have received a copy of the GNU General Public License42    along with this program; if not, write to the Free Software43    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA44*/45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/46#include <linux/module.h>47#include <linux/kernel.h>48#include <linux/init.h>49#include <linux/errno.h>50#include <linux/kdev_t.h>51#include <linux/blkdev.h>52#include <linux/delay.h>	/* for mdelay */53#include <linux/interrupt.h>54#include <linux/reboot.h>	/* notifier code */55#include <linux/workqueue.h>56#include <linux/sort.h>57#include <linux/slab.h>58 59#include <scsi/scsi.h>60#include <scsi/scsi_cmnd.h>61#include <scsi/scsi_device.h>62#include <scsi/scsi_host.h>63#include <scsi/scsi_tcq.h>64#include <scsi/scsi_transport_fc.h>65 66#include "mptbase.h"67#include "mptscsih.h"68 69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/70#define my_NAME		"Fusion MPT FC Host driver"71#define my_VERSION	MPT_LINUX_VERSION_COMMON72#define MYNAM		"mptfc"73 74MODULE_AUTHOR(MODULEAUTHOR);75MODULE_DESCRIPTION(my_NAME);76MODULE_LICENSE("GPL");77MODULE_VERSION(my_VERSION);78 79/* Command line args */80#define MPTFC_DEV_LOSS_TMO (60)81static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;	/* reasonable default */82module_param(mptfc_dev_loss_tmo, int, 0);83MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "84    				     " transport to wait for an rport to "85				     " return following a device loss event."86				     "  Default=60.");87 88/* scsi-mid layer global parmeter is max_report_luns, which is 511 */89#define MPTFC_MAX_LUN (16895)90static int max_lun = MPTFC_MAX_LUN;91module_param(max_lun, int, 0);92MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");93 94static u8	mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;95static u8	mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;96static u8	mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS;97 98static int mptfc_target_alloc(struct scsi_target *starget);99static int mptfc_slave_alloc(struct scsi_device *sdev);100static int mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt);101static void mptfc_target_destroy(struct scsi_target *starget);102static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);103static void mptfc_remove(struct pci_dev *pdev);104static int mptfc_abort(struct scsi_cmnd *SCpnt);105static int mptfc_dev_reset(struct scsi_cmnd *SCpnt);106static int mptfc_bus_reset(struct scsi_cmnd *SCpnt);107 108static const struct scsi_host_template mptfc_driver_template = {109	.module				= THIS_MODULE,110	.proc_name			= "mptfc",111	.show_info			= mptscsih_show_info,112	.name				= "MPT FC Host",113	.info				= mptscsih_info,114	.queuecommand			= mptfc_qcmd,115	.target_alloc			= mptfc_target_alloc,116	.slave_alloc			= mptfc_slave_alloc,117	.slave_configure		= mptscsih_slave_configure,118	.target_destroy			= mptfc_target_destroy,119	.slave_destroy			= mptscsih_slave_destroy,120	.change_queue_depth 		= mptscsih_change_queue_depth,121	.eh_timed_out			= fc_eh_timed_out,122	.eh_abort_handler		= mptfc_abort,123	.eh_device_reset_handler	= mptfc_dev_reset,124	.eh_bus_reset_handler		= mptfc_bus_reset,125	.eh_host_reset_handler		= mptscsih_host_reset,126	.bios_param			= mptscsih_bios_param,127	.can_queue			= MPT_FC_CAN_QUEUE,128	.this_id			= -1,129	.sg_tablesize			= MPT_SCSI_SG_DEPTH,130	.max_sectors			= 8192,131	.cmd_per_lun			= 7,132	.dma_alignment			= 511,133	.shost_groups			= mptscsih_host_attr_groups,134};135 136/****************************************************************************137 * Supported hardware138 */139 140static struct pci_device_id mptfc_pci_table[] = {141	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC909,142		PCI_ANY_ID, PCI_ANY_ID },143	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919,144		PCI_ANY_ID, PCI_ANY_ID },145	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929,146		PCI_ANY_ID, PCI_ANY_ID },147	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919X,148		PCI_ANY_ID, PCI_ANY_ID },149	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929X,150		PCI_ANY_ID, PCI_ANY_ID },151	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC939X,152		PCI_ANY_ID, PCI_ANY_ID },153	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949X,154		PCI_ANY_ID, PCI_ANY_ID },155	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E,156		PCI_ANY_ID, PCI_ANY_ID },157	{ PCI_VENDOR_ID_BROCADE, MPI_MANUFACTPAGE_DEVICEID_FC949E,158		PCI_ANY_ID, PCI_ANY_ID },159	{0}	/* Terminating entry */160};161MODULE_DEVICE_TABLE(pci, mptfc_pci_table);162 163static struct scsi_transport_template *mptfc_transport_template = NULL;164 165static struct fc_function_template mptfc_transport_functions = {166	.dd_fcrport_size = 8,167	.show_host_node_name = 1,168	.show_host_port_name = 1,169	.show_host_supported_classes = 1,170	.show_host_port_id = 1,171	.show_rport_supported_classes = 1,172	.show_starget_node_name = 1,173	.show_starget_port_name = 1,174	.show_starget_port_id = 1,175	.set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,176	.show_rport_dev_loss_tmo = 1,177	.show_host_supported_speeds = 1,178	.show_host_maxframe_size = 1,179	.show_host_speed = 1,180	.show_host_fabric_name = 1,181	.show_host_port_type = 1,182	.show_host_port_state = 1,183	.show_host_symbolic_name = 1,184};185 186static int187mptfc_block_error_handler(struct fc_rport *rport)188{189	MPT_SCSI_HOST		*hd;190	struct Scsi_Host	*shost = rport_to_shost(rport);191	unsigned long		flags;192	int			ready;193	MPT_ADAPTER		*ioc;194	int			loops = 40;	/* seconds */195 196	hd = shost_priv(shost);197	ioc = hd->ioc;198	spin_lock_irqsave(shost->host_lock, flags);199	while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY200	 || (loops > 0 && ioc->active == 0)) {201		spin_unlock_irqrestore(shost->host_lock, flags);202		dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT203			"mptfc_block_error_handler.%d: %s, port status is "204			"%x, active flag %d, deferring recovery.\n",205			ioc->name, ioc->sh->host_no,206			dev_name(&rport->dev), ready, ioc->active));207		msleep(1000);208		spin_lock_irqsave(shost->host_lock, flags);209		loops --;210	}211	spin_unlock_irqrestore(shost->host_lock, flags);212 213	if (ready == DID_NO_CONNECT || ioc->active == 0) {214		dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT215			"mpt_block_error_handler.%d: %s, failing recovery, "216			"port state %x, active %d.\n",217			ioc->name, ioc->sh->host_no,218			dev_name(&rport->dev), ready, ioc->active));219		return FAILED;220	}221	return SUCCESS;222}223 224static int225mptfc_abort(struct scsi_cmnd *SCpnt)226{227	struct Scsi_Host *shost = SCpnt->device->host;228	struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));229	MPT_SCSI_HOST __maybe_unused *hd = shost_priv(shost);230	int rtn;231 232	rtn = mptfc_block_error_handler(rport);233	if (rtn == SUCCESS) {234		dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT235			"%s.%d: %d:%llu, executing recovery.\n", __func__,236			hd->ioc->name, shost->host_no,237			SCpnt->device->id, SCpnt->device->lun));238		rtn = mptscsih_abort(SCpnt);239	}240	return rtn;241}242 243static int244mptfc_dev_reset(struct scsi_cmnd *SCpnt)245{246	struct Scsi_Host *shost = SCpnt->device->host;247	struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));248	MPT_SCSI_HOST __maybe_unused *hd = shost_priv(shost);249	int rtn;250 251	rtn = mptfc_block_error_handler(rport);252	if (rtn == SUCCESS) {253		dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT254			"%s.%d: %d:%llu, executing recovery.\n", __func__,255			hd->ioc->name, shost->host_no,256			SCpnt->device->id, SCpnt->device->lun));257		rtn = mptscsih_dev_reset(SCpnt);258	}259	return rtn;260}261 262static int263mptfc_bus_reset(struct scsi_cmnd *SCpnt)264{265	struct Scsi_Host *shost = SCpnt->device->host;266	MPT_SCSI_HOST __maybe_unused *hd = shost_priv(shost);267	int channel = SCpnt->device->channel;268	struct mptfc_rport_info *ri;269	int rtn = FAILED;270 271	list_for_each_entry(ri, &hd->ioc->fc_rports, list) {272		if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {273			VirtTarget *vtarget = ri->starget->hostdata;274 275			if (!vtarget || vtarget->channel != channel)276				continue;277			rtn = fc_block_rport(ri->rport);278			if (rtn != 0)279				break;280		}281	}282	if (rtn == 0) {283		dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT284			"%s.%d: %d:%llu, executing recovery.\n", __func__,285			hd->ioc->name, shost->host_no,286			SCpnt->device->id, SCpnt->device->lun));287		rtn = mptscsih_bus_reset(SCpnt);288	}289	return rtn;290}291 292static void293mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)294{295	if (timeout > 0)296		rport->dev_loss_tmo = timeout;297	else298		rport->dev_loss_tmo = mptfc_dev_loss_tmo;299}300 301static int302mptfc_FcDevPage0_cmp_func(const void *a, const void *b)303{304	FCDevicePage0_t **aa = (FCDevicePage0_t **)a;305	FCDevicePage0_t **bb = (FCDevicePage0_t **)b;306 307	if ((*aa)->CurrentBus == (*bb)->CurrentBus) {308		if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)309			return 0;310		if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)311			return -1;312		return 1;313	}314	if ((*aa)->CurrentBus < (*bb)->CurrentBus)315		return -1;316	return 1;317}318 319static int320mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,321	void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))322{323	ConfigPageHeader_t	 hdr;324	CONFIGPARMS		 cfg;325	FCDevicePage0_t		*ppage0_alloc, *fc;326	dma_addr_t		 page0_dma;327	int			 data_sz;328	int			 ii;329 330	FCDevicePage0_t		*p0_array=NULL, *p_p0;331	FCDevicePage0_t		**pp0_array=NULL, **p_pp0;332 333	int			 rc = -ENOMEM;334	U32			 port_id = 0xffffff;335	int			 num_targ = 0;336	int			 max_bus = ioc->facts.MaxBuses;337	int			 max_targ;338 339	max_targ = (ioc->facts.MaxDevices == 0) ? 256 : ioc->facts.MaxDevices;340 341	data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;342	p_p0 = p0_array =  kzalloc(data_sz, GFP_KERNEL);343	if (!p0_array)344		goto out;345 346	data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;347	p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);348	if (!pp0_array)349		goto out;350 351	do {352		/* Get FC Device Page 0 header */353		hdr.PageVersion = 0;354		hdr.PageLength = 0;355		hdr.PageNumber = 0;356		hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;357		cfg.cfghdr.hdr = &hdr;358		cfg.physAddr = -1;359		cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;360		cfg.dir = 0;361		cfg.pageAddr = port_id;362		cfg.timeout = 0;363 364		if ((rc = mpt_config(ioc, &cfg)) != 0)365			break;366 367		if (hdr.PageLength <= 0)368			break;369 370		data_sz = hdr.PageLength * 4;371		ppage0_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz,372						  &page0_dma, GFP_KERNEL);373		rc = -ENOMEM;374		if (!ppage0_alloc)375			break;376 377		cfg.physAddr = page0_dma;378		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;379 380		if ((rc = mpt_config(ioc, &cfg)) == 0) {381			ppage0_alloc->PortIdentifier =382				le32_to_cpu(ppage0_alloc->PortIdentifier);383 384			ppage0_alloc->WWNN.Low =385				le32_to_cpu(ppage0_alloc->WWNN.Low);386 387			ppage0_alloc->WWNN.High =388				le32_to_cpu(ppage0_alloc->WWNN.High);389 390			ppage0_alloc->WWPN.Low =391				le32_to_cpu(ppage0_alloc->WWPN.Low);392 393			ppage0_alloc->WWPN.High =394				le32_to_cpu(ppage0_alloc->WWPN.High);395 396			ppage0_alloc->BBCredit =397				le16_to_cpu(ppage0_alloc->BBCredit);398 399			ppage0_alloc->MaxRxFrameSize =400				le16_to_cpu(ppage0_alloc->MaxRxFrameSize);401 402			port_id = ppage0_alloc->PortIdentifier;403			num_targ++;404			*p_p0 = *ppage0_alloc;	/* save data */405			*p_pp0++ = p_p0++;	/* save addr */406		}407		dma_free_coherent(&ioc->pcidev->dev, data_sz,408				  ppage0_alloc, page0_dma);409		if (rc != 0)410			break;411 412	} while (port_id <= 0xff0000);413 414	if (num_targ) {415		/* sort array */416		if (num_targ > 1)417			sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),418				mptfc_FcDevPage0_cmp_func, NULL);419		/* call caller's func for each targ */420		for (ii = 0; ii < num_targ;  ii++) {421			fc = *(pp0_array+ii);422			func(ioc, ioc_port, fc);423		}424	}425 426 out:427	kfree(pp0_array);428	kfree(p0_array);429	return rc;430}431 432static int433mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)434{435	/* not currently usable */436	if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |437			  MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))438		return -1;439 440	if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))441		return -1;442 443	if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))444		return -1;445 446	/*447	 * board data structure already normalized to platform endianness448	 * shifted to avoid unaligned access on 64 bit architecture449	 */450	rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;451	rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;452	rid->port_id =   pg0->PortIdentifier;453	rid->roles = FC_RPORT_ROLE_UNKNOWN;454 455	return 0;456}457 458static void459mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)460{461	struct fc_rport_identifiers rport_ids;462	struct fc_rport		*rport;463	struct mptfc_rport_info	*ri;464	int			new_ri = 1;465	u64			pn, nn;466	VirtTarget		*vtarget;467	u32			roles = FC_RPORT_ROLE_UNKNOWN;468 469	if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)470		return;471 472	roles |= FC_RPORT_ROLE_FCP_TARGET;473	if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)474		roles |= FC_RPORT_ROLE_FCP_INITIATOR;475 476	/* scan list looking for a match */477	list_for_each_entry(ri, &ioc->fc_rports, list) {478		pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;479		if (pn == rport_ids.port_name) {	/* match */480			list_move_tail(&ri->list, &ioc->fc_rports);481			new_ri = 0;482			break;483		}484	}485	if (new_ri) {	/* allocate one */486		ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);487		if (!ri)488			return;489		list_add_tail(&ri->list, &ioc->fc_rports);490	}491 492	ri->pg0 = *pg0;	/* add/update pg0 data */493	ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;494 495	/* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */496	if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {497		ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;498		rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);499		if (rport) {500			ri->rport = rport;501			if (new_ri) /* may have been reset by user */502				rport->dev_loss_tmo = mptfc_dev_loss_tmo;503			/*504			 * if already mapped, remap here.  If not mapped,505			 * target_alloc will allocate vtarget and map,506			 * slave_alloc will fill in vdevice from vtarget.507			 */508			if (ri->starget) {509				vtarget = ri->starget->hostdata;510				if (vtarget) {511					vtarget->id = pg0->CurrentTargetID;512					vtarget->channel = pg0->CurrentBus;513					vtarget->deleted = 0;514				}515			}516			*((struct mptfc_rport_info **)rport->dd_data) = ri;517			/* scan will be scheduled once rport becomes a target */518			fc_remote_port_rolechg(rport,roles);519 520			pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;521			nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;522			dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT523				"mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "524				"rport tid %d, tmo %d\n",525					ioc->name,526					ioc->sh->host_no,527					pg0->PortIdentifier,528					(unsigned long long)nn,529					(unsigned long long)pn,530					pg0->CurrentTargetID,531					ri->rport->scsi_target_id,532					ri->rport->dev_loss_tmo));533		} else {534			list_del(&ri->list);535			kfree(ri);536			ri = NULL;537		}538	}539}540 541/*542 *	OS entry point to allow for host driver to free allocated memory543 *	Called if no device present or device being unloaded544 */545static void546mptfc_target_destroy(struct scsi_target *starget)547{548	struct fc_rport		*rport;549	struct mptfc_rport_info *ri;550 551	rport = starget_to_rport(starget);552	if (rport) {553		ri = *((struct mptfc_rport_info **)rport->dd_data);554		if (ri)	/* better be! */555			ri->starget = NULL;556	}557	kfree(starget->hostdata);558	starget->hostdata = NULL;559}560 561/*562 *	OS entry point to allow host driver to alloc memory563 *	for each scsi target. Called once per device the bus scan.564 *	Return non-zero if allocation fails.565 */566static int567mptfc_target_alloc(struct scsi_target *starget)568{569	VirtTarget		*vtarget;570	struct fc_rport		*rport;571	struct mptfc_rport_info *ri;572	int			rc;573 574	vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);575	if (!vtarget)576		return -ENOMEM;577	starget->hostdata = vtarget;578 579	rc = -ENODEV;580	rport = starget_to_rport(starget);581	if (rport) {582		ri = *((struct mptfc_rport_info **)rport->dd_data);583		if (ri) {	/* better be! */584			vtarget->id = ri->pg0.CurrentTargetID;585			vtarget->channel = ri->pg0.CurrentBus;586			ri->starget = starget;587			rc = 0;588		}589	}590	if (rc != 0) {591		kfree(vtarget);592		starget->hostdata = NULL;593	}594 595	return rc;596}597/*598 *	mptfc_dump_lun_info599 *	@ioc600 *	@rport601 *	@sdev602 *603 */604static void605mptfc_dump_lun_info(MPT_ADAPTER *ioc, struct fc_rport *rport, struct scsi_device *sdev,606		VirtTarget *vtarget)607{608	u64 nn, pn;609	struct mptfc_rport_info *ri;610 611	ri = *((struct mptfc_rport_info **)rport->dd_data);612	pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;613	nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;614	dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT615		"mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "616		"CurrentTargetID %d, %x %llx %llx\n",617		ioc->name,618		sdev->host->host_no,619		vtarget->num_luns,620		sdev->id, ri->pg0.CurrentTargetID,621		ri->pg0.PortIdentifier,622		(unsigned long long)pn,623		(unsigned long long)nn));624}625 626 627/*628 *	OS entry point to allow host driver to alloc memory629 *	for each scsi device. Called once per device the bus scan.630 *	Return non-zero if allocation fails.631 *	Init memory once per LUN.632 */633static int634mptfc_slave_alloc(struct scsi_device *sdev)635{636	MPT_SCSI_HOST		*hd;637	VirtTarget		*vtarget;638	VirtDevice		*vdevice;639	struct scsi_target	*starget;640	struct fc_rport		*rport;641	MPT_ADAPTER 		*ioc;642 643	starget = scsi_target(sdev);644	rport = starget_to_rport(starget);645 646	if (!rport || fc_remote_port_chkready(rport))647		return -ENXIO;648 649	hd = shost_priv(sdev->host);650	ioc = hd->ioc;651 652	vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);653	if (!vdevice) {654		printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",655				ioc->name, sizeof(VirtDevice));656		return -ENOMEM;657	}658 659 660	sdev->hostdata = vdevice;661	vtarget = starget->hostdata;662 663	if (vtarget->num_luns == 0) {664		vtarget->ioc_id = ioc->id;665		vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;666	}667 668	vdevice->vtarget = vtarget;669	vdevice->lun = sdev->lun;670 671	vtarget->num_luns++;672 673 674	mptfc_dump_lun_info(ioc, rport, sdev, vtarget);675 676	return 0;677}678 679static int680mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)681{682	struct mptfc_rport_info	*ri;683	struct fc_rport	*rport = starget_to_rport(scsi_target(SCpnt->device));684	int		err;685	VirtDevice	*vdevice = SCpnt->device->hostdata;686 687	if (!vdevice || !vdevice->vtarget) {688		SCpnt->result = DID_NO_CONNECT << 16;689		scsi_done(SCpnt);690		return 0;691	}692 693	err = fc_remote_port_chkready(rport);694	if (unlikely(err)) {695		SCpnt->result = err;696		scsi_done(SCpnt);697		return 0;698	}699 700	/* dd_data is null until finished adding target */701	ri = *((struct mptfc_rport_info **)rport->dd_data);702	if (unlikely(!ri)) {703		SCpnt->result = DID_IMM_RETRY << 16;704		scsi_done(SCpnt);705		return 0;706	}707 708	return mptscsih_qcmd(SCpnt);709}710 711/*712 *	mptfc_display_port_link_speed - displaying link speed713 *	@ioc: Pointer to MPT_ADAPTER structure714 *	@portnum: IOC Port number715 *	@pp0dest: port page0 data payload716 *717 */718static void719mptfc_display_port_link_speed(MPT_ADAPTER *ioc, int portnum, FCPortPage0_t *pp0dest)720{721	u8	old_speed, new_speed, state;722	char	*old, *new;723 724	if (portnum >= 2)725		return;726 727	old_speed = ioc->fc_link_speed[portnum];728	new_speed = pp0dest->CurrentSpeed;729	state = pp0dest->PortState;730 731	if (state != MPI_FCPORTPAGE0_PORTSTATE_OFFLINE &&732	    new_speed != MPI_FCPORTPAGE0_CURRENT_SPEED_UNKNOWN) {733 734		old = old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :735		       old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :736			old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :737			 "Unknown";738		new = new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :739		       new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :740			new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :741			 "Unknown";742		if (old_speed == 0)743			printk(MYIOC_s_NOTE_FMT744				"FC Link Established, Speed = %s\n",745				ioc->name, new);746		else if (old_speed != new_speed)747			printk(MYIOC_s_WARN_FMT748				"FC Link Speed Change, Old Speed = %s, New Speed = %s\n",749				ioc->name, old, new);750 751		ioc->fc_link_speed[portnum] = new_speed;752	}753}754 755/*756 *	mptfc_GetFcPortPage0 - Fetch FCPort config Page0.757 *	@ioc: Pointer to MPT_ADAPTER structure758 *	@portnum: IOC Port number759 *760 *	Return: 0 for success761 *	-ENOMEM if no memory available762 *		-EPERM if not allowed due to ISR context763 *		-EAGAIN if no msg frames currently available764 *		-EFAULT for non-successful reply or no reply (timeout)765 *		-EINVAL portnum arg out of range (hardwired to two elements)766 */767static int768mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)769{770	ConfigPageHeader_t	 hdr;771	CONFIGPARMS		 cfg;772	FCPortPage0_t		*ppage0_alloc;773	FCPortPage0_t		*pp0dest;774	dma_addr_t		 page0_dma;775	int			 data_sz;776	int			 copy_sz;777	int			 rc;778	int			 count = 400;779 780	if (portnum > 1)781		return -EINVAL;782 783	/* Get FCPort Page 0 header */784	hdr.PageVersion = 0;785	hdr.PageLength = 0;786	hdr.PageNumber = 0;787	hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;788	cfg.cfghdr.hdr = &hdr;789	cfg.physAddr = -1;790	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;791	cfg.dir = 0;792	cfg.pageAddr = portnum;793	cfg.timeout = 0;794 795	if ((rc = mpt_config(ioc, &cfg)) != 0)796		return rc;797 798	if (hdr.PageLength == 0)799		return 0;800 801	data_sz = hdr.PageLength * 4;802	rc = -ENOMEM;803	ppage0_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz,804					  &page0_dma, GFP_KERNEL);805	if (ppage0_alloc) {806 807 try_again:808		memset((u8 *)ppage0_alloc, 0, data_sz);809		cfg.physAddr = page0_dma;810		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;811 812		if ((rc = mpt_config(ioc, &cfg)) == 0) {813			/* save the data */814			pp0dest = &ioc->fc_port_page0[portnum];815			copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);816			memcpy(pp0dest, ppage0_alloc, copy_sz);817 818			/*819			 *	Normalize endianness of structure data,820			 *	by byte-swapping all > 1 byte fields!821			 */822			pp0dest->Flags = le32_to_cpu(pp0dest->Flags);823			pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);824			pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);825			pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);826			pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);827			pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);828			pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);829			pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);830			pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);831			pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);832			pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);833			pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);834			pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);835			pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);836			pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);837			pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);838 839			/*840			 * if still doing discovery,841			 * hang loose a while until finished842			 */843			if ((pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) ||844			    (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE &&845			     (pp0dest->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK)846			      == MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT)) {847				if (count-- > 0) {848					msleep(100);849					goto try_again;850				}851				printk(MYIOC_s_INFO_FMT "Firmware discovery not"852							" complete.\n",853						ioc->name);854			}855			mptfc_display_port_link_speed(ioc, portnum, pp0dest);856		}857 858		dma_free_coherent(&ioc->pcidev->dev, data_sz, ppage0_alloc,859				  page0_dma);860	}861 862	return rc;863}864 865static int866mptfc_WriteFcPortPage1(MPT_ADAPTER *ioc, int portnum)867{868	ConfigPageHeader_t	 hdr;869	CONFIGPARMS		 cfg;870	int			 rc;871 872	if (portnum > 1)873		return -EINVAL;874 875	if (!(ioc->fc_data.fc_port_page1[portnum].data))876		return -EINVAL;877 878	/* get fcport page 1 header */879	hdr.PageVersion = 0;880	hdr.PageLength = 0;881	hdr.PageNumber = 1;882	hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;883	cfg.cfghdr.hdr = &hdr;884	cfg.physAddr = -1;885	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;886	cfg.dir = 0;887	cfg.pageAddr = portnum;888	cfg.timeout = 0;889 890	if ((rc = mpt_config(ioc, &cfg)) != 0)891		return rc;892 893	if (hdr.PageLength == 0)894		return -ENODEV;895 896	if (hdr.PageLength*4 != ioc->fc_data.fc_port_page1[portnum].pg_sz)897		return -EINVAL;898 899	cfg.physAddr = ioc->fc_data.fc_port_page1[portnum].dma;900	cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;901	cfg.dir = 1;902 903	rc = mpt_config(ioc, &cfg);904 905	return rc;906}907 908static int909mptfc_GetFcPortPage1(MPT_ADAPTER *ioc, int portnum)910{911	ConfigPageHeader_t	 hdr;912	CONFIGPARMS		 cfg;913	FCPortPage1_t		*page1_alloc;914	dma_addr_t		 page1_dma;915	int			 data_sz;916	int			 rc;917 918	if (portnum > 1)919		return -EINVAL;920 921	/* get fcport page 1 header */922	hdr.PageVersion = 0;923	hdr.PageLength = 0;924	hdr.PageNumber = 1;925	hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;926	cfg.cfghdr.hdr = &hdr;927	cfg.physAddr = -1;928	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;929	cfg.dir = 0;930	cfg.pageAddr = portnum;931	cfg.timeout = 0;932 933	if ((rc = mpt_config(ioc, &cfg)) != 0)934		return rc;935 936	if (hdr.PageLength == 0)937		return -ENODEV;938 939start_over:940 941	if (ioc->fc_data.fc_port_page1[portnum].data == NULL) {942		data_sz = hdr.PageLength * 4;943		if (data_sz < sizeof(FCPortPage1_t))944			data_sz = sizeof(FCPortPage1_t);945 946		page1_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz,947						 &page1_dma, GFP_KERNEL);948		if (!page1_alloc)949			return -ENOMEM;950	}951	else {952		page1_alloc = ioc->fc_data.fc_port_page1[portnum].data;953		page1_dma = ioc->fc_data.fc_port_page1[portnum].dma;954		data_sz = ioc->fc_data.fc_port_page1[portnum].pg_sz;955		if (hdr.PageLength * 4 > data_sz) {956			ioc->fc_data.fc_port_page1[portnum].data = NULL;957			dma_free_coherent(&ioc->pcidev->dev, data_sz,958					  page1_alloc, page1_dma);959			goto start_over;960		}961	}962 963	cfg.physAddr = page1_dma;964	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;965 966	if ((rc = mpt_config(ioc, &cfg)) == 0) {967		ioc->fc_data.fc_port_page1[portnum].data = page1_alloc;968		ioc->fc_data.fc_port_page1[portnum].pg_sz = data_sz;969		ioc->fc_data.fc_port_page1[portnum].dma = page1_dma;970	}971	else {972		ioc->fc_data.fc_port_page1[portnum].data = NULL;973		dma_free_coherent(&ioc->pcidev->dev, data_sz, page1_alloc,974				  page1_dma);975	}976 977	return rc;978}979 980static void981mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)982{983	int		ii;984	FCPortPage1_t	*pp1;985 986	#define MPTFC_FW_DEVICE_TIMEOUT	(1)987	#define MPTFC_FW_IO_PEND_TIMEOUT (1)988	#define ON_FLAGS  (MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY)989	#define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS)990 991	for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {992		if (mptfc_GetFcPortPage1(ioc, ii) != 0)993			continue;994		pp1 = ioc->fc_data.fc_port_page1[ii].data;995		if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT)996		 && (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT)997		 && ((pp1->Flags & ON_FLAGS) == ON_FLAGS)998		 && ((pp1->Flags & OFF_FLAGS) == 0))999			continue;1000		pp1->InitiatorDeviceTimeout = MPTFC_FW_DEVICE_TIMEOUT;1001		pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT;1002		pp1->Flags &= ~OFF_FLAGS;1003		pp1->Flags |= ON_FLAGS;1004		mptfc_WriteFcPortPage1(ioc, ii);1005	}1006}1007 1008 1009static void1010mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)1011{1012	unsigned	class = 0;1013	unsigned	cos = 0;1014	unsigned	speed;1015	unsigned	port_type;1016	unsigned	port_state;1017	FCPortPage0_t	*pp0;1018	struct Scsi_Host *sh;1019	char		*sn;1020 1021	/* don't know what to do as only one scsi (fc) host was allocated */1022	if (portnum != 0)1023		return;1024 1025	pp0 = &ioc->fc_port_page0[portnum];1026	sh = ioc->sh;1027 1028	sn = fc_host_symbolic_name(sh);1029	snprintf(sn, FC_SYMBOLIC_NAME_SIZE, "%s %s%08xh",1030	    ioc->prod_name,1031	    MPT_FW_REV_MAGIC_ID_STRING,1032	    ioc->facts.FWVersion.Word);1033 1034	fc_host_tgtid_bind_type(sh) = FC_TGTID_BIND_BY_WWPN;1035 1036	fc_host_maxframe_size(sh) = pp0->MaxFrameSize;1037 1038	fc_host_node_name(sh) =1039	    	(u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;1040 1041	fc_host_port_name(sh) =1042	    	(u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low;1043 1044	fc_host_port_id(sh) = pp0->PortIdentifier;1045 1046	class = pp0->SupportedServiceClass;1047	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)1048		cos |= FC_COS_CLASS1;1049	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)1050		cos |= FC_COS_CLASS2;1051	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)1052		cos |= FC_COS_CLASS3;1053	fc_host_supported_classes(sh) = cos;1054 1055	if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT)1056		speed = FC_PORTSPEED_1GBIT;1057	else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT)1058		speed = FC_PORTSPEED_2GBIT;1059	else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT)1060		speed = FC_PORTSPEED_4GBIT;1061	else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT)1062		speed = FC_PORTSPEED_10GBIT;1063	else1064		speed = FC_PORTSPEED_UNKNOWN;1065	fc_host_speed(sh) = speed;1066 1067	speed = 0;1068	if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED)1069		speed |= FC_PORTSPEED_1GBIT;1070	if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)1071		speed |= FC_PORTSPEED_2GBIT;1072	if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)1073		speed |= FC_PORTSPEED_4GBIT;1074	if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)1075		speed |= FC_PORTSPEED_10GBIT;1076	fc_host_supported_speeds(sh) = speed;1077 1078	port_state = FC_PORTSTATE_UNKNOWN;1079	if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE)1080		port_state = FC_PORTSTATE_ONLINE;1081	else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE)1082		port_state = FC_PORTSTATE_LINKDOWN;1083	fc_host_port_state(sh) = port_state;1084 1085	port_type = FC_PORTTYPE_UNKNOWN;1086	if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT)1087		port_type = FC_PORTTYPE_PTP;1088	else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP)1089		port_type = FC_PORTTYPE_LPORT;1090	else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP)1091		port_type = FC_PORTTYPE_NLPORT;1092	else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT)1093		port_type = FC_PORTTYPE_NPORT;1094	fc_host_port_type(sh) = port_type;1095 1096	fc_host_fabric_name(sh) =1097	    (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ?1098		(u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low :1099		(u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;1100 1101}1102 1103static void1104mptfc_link_status_change(struct work_struct *work)1105{1106	MPT_ADAPTER             *ioc =1107		container_of(work, MPT_ADAPTER, fc_rescan_work);1108	int ii;1109 1110	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++)1111		(void) mptfc_GetFcPortPage0(ioc, ii);1112 1113}1114 1115static void1116mptfc_setup_reset(struct work_struct *work)1117{1118	MPT_ADAPTER		*ioc =1119		container_of(work, MPT_ADAPTER, fc_setup_reset_work);1120	u64			pn;1121	struct mptfc_rport_info *ri;1122	struct scsi_target      *starget;1123	VirtTarget              *vtarget;1124 1125	/* reset about to happen, delete (block) all rports */1126	list_for_each_entry(ri, &ioc->fc_rports, list) {1127		if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {1128			ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;1129			fc_remote_port_delete(ri->rport);	/* won't sleep */1130			ri->rport = NULL;1131			starget = ri->starget;1132			if (starget) {1133				vtarget = starget->hostdata;1134				if (vtarget)1135					vtarget->deleted = 1;1136			}1137 1138			pn = (u64)ri->pg0.WWPN.High << 32 |1139			     (u64)ri->pg0.WWPN.Low;1140			dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT1141				"mptfc_setup_reset.%d: %llx deleted\n",1142				ioc->name,1143				ioc->sh->host_no,1144				(unsigned long long)pn));1145		}1146	}1147}1148 1149static void1150mptfc_rescan_devices(struct work_struct *work)1151{1152	MPT_ADAPTER		*ioc =1153		container_of(work, MPT_ADAPTER, fc_rescan_work);1154	int			ii;1155	u64			pn;1156	struct mptfc_rport_info *ri;1157	struct scsi_target      *starget;1158	VirtTarget              *vtarget;1159 1160	/* start by tagging all ports as missing */1161	list_for_each_entry(ri, &ioc->fc_rports, list) {1162		if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {1163			ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;1164		}1165	}1166 1167	/*1168	 * now rescan devices known to adapter,1169	 * will reregister existing rports1170	 */1171	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {1172		(void) mptfc_GetFcPortPage0(ioc, ii);1173		mptfc_init_host_attr(ioc, ii);	/* refresh */1174		mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev);1175	}1176 1177	/* delete devices still missing */1178	list_for_each_entry(ri, &ioc->fc_rports, list) {1179		/* if newly missing, delete it */1180		if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {1181 1182			ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|1183				       MPT_RPORT_INFO_FLAGS_MISSING);1184			fc_remote_port_delete(ri->rport);	/* won't sleep */1185			ri->rport = NULL;1186			starget = ri->starget;1187			if (starget) {1188				vtarget = starget->hostdata;1189				if (vtarget)1190					vtarget->deleted = 1;1191			}1192 1193			pn = (u64)ri->pg0.WWPN.High << 32 |1194			     (u64)ri->pg0.WWPN.Low;1195			dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT1196				"mptfc_rescan.%d: %llx deleted\n",1197				ioc->name,1198				ioc->sh->host_no,1199				(unsigned long long)pn));1200		}1201	}1202}1203 1204static int1205mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)1206{1207	struct Scsi_Host	*sh;1208	MPT_SCSI_HOST		*hd;1209	MPT_ADAPTER 		*ioc;1210	unsigned long		 flags;1211	int			 ii;1212	int			 numSGE = 0;1213	int			 scale;1214	int			 ioc_cap;1215	int			error=0;1216	int			r;1217 1218	if ((r = mpt_attach(pdev,id)) != 0)1219		return r;1220 1221	ioc = pci_get_drvdata(pdev);1222	ioc->DoneCtx = mptfcDoneCtx;1223	ioc->TaskCtx = mptfcTaskCtx;1224	ioc->InternalCtx = mptfcInternalCtx;1225 1226	/*  Added sanity check on readiness of the MPT adapter.1227	 */1228	if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {1229		printk(MYIOC_s_WARN_FMT1230		  "Skipping because it's not operational!\n",1231		  ioc->name);1232		error = -ENODEV;1233		goto out_mptfc_probe;1234	}1235 1236	if (!ioc->active) {1237		printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",1238		  ioc->name);1239		error = -ENODEV;1240		goto out_mptfc_probe;1241	}1242 1243	/*  Sanity check - ensure at least 1 port is INITIATOR capable1244	 */1245	ioc_cap = 0;1246	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {1247		if (ioc->pfacts[ii].ProtocolFlags &1248		    MPI_PORTFACTS_PROTOCOL_INITIATOR)1249			ioc_cap ++;1250	}1251 1252	if (!ioc_cap) {1253		printk(MYIOC_s_WARN_FMT1254			"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",1255			ioc->name, ioc);1256		return 0;1257	}1258 1259	sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));1260 1261	if (!sh) {1262		printk(MYIOC_s_WARN_FMT1263			"Unable to register controller with SCSI subsystem\n",1264			ioc->name);1265		error = -1;1266		goto out_mptfc_probe;1267        }1268 1269	spin_lock_init(&ioc->fc_rescan_work_lock);1270	INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);1271	INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);1272	INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change);1273 1274	spin_lock_irqsave(&ioc->FreeQlock, flags);1275 1276	/* Attach the SCSI Host to the IOC structure1277	 */1278	ioc->sh = sh;1279 1280	sh->io_port = 0;1281	sh->n_io_port = 0;1282	sh->irq = 0;1283 1284	/* set 16 byte cdb's */1285	sh->max_cmd_len = 16;1286 1287	sh->max_id = ioc->pfacts->MaxDevices;1288	sh->max_lun = max_lun;1289 1290	/* Required entry.1291	 */1292	sh->unique_id = ioc->id;1293 1294	/* Verify that we won't exceed the maximum1295	 * number of chain buffers1296	 * We can optimize:  ZZ = req_sz/sizeof(SGE)1297	 * For 32bit SGE's:1298	 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ1299	 *               + (req_sz - 64)/sizeof(SGE)1300	 * A slightly different algorithm is required for1301	 * 64bit SGEs.1302	 */1303	scale = ioc->req_sz/ioc->SGE_size;1304	if (ioc->sg_addr_size == sizeof(u64)) {1305		numSGE = (scale - 1) *1306		  (ioc->facts.MaxChainDepth-1) + scale +1307		  (ioc->req_sz - 60) / ioc->SGE_size;1308	} else {1309		numSGE = 1 + (scale - 1) *1310		  (ioc->facts.MaxChainDepth-1) + scale +1311		  (ioc->req_sz - 64) / ioc->SGE_size;1312	}1313 1314	if (numSGE < sh->sg_tablesize) {1315		/* Reset this value */1316		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT1317		  "Resetting sg_tablesize to %d from %d\n",1318		  ioc->name, numSGE, sh->sg_tablesize));1319		sh->sg_tablesize = numSGE;1320	}1321 1322	spin_unlock_irqrestore(&ioc->FreeQlock, flags);1323 1324	hd = shost_priv(sh);1325	hd->ioc = ioc;1326 1327	/* SCSI needs scsi_cmnd lookup table!1328	 * (with size equal to req_depth*PtrSz!)1329	 */1330	ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_KERNEL);1331	if (!ioc->ScsiLookup) {1332		error = -ENOMEM;1333		goto out_mptfc_probe;1334	}1335	spin_lock_init(&ioc->scsi_lookup_lock);1336 1337	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",1338		 ioc->name, ioc->ScsiLookup));1339 1340	hd->last_queue_full = 0;1341 1342	sh->transportt = mptfc_transport_template;1343	error = scsi_add_host (sh, &ioc->pcidev->dev);1344	if(error) {1345		dprintk(ioc, printk(MYIOC_s_ERR_FMT1346		  "scsi_add_host failed\n", ioc->name));1347		goto out_mptfc_probe;1348	}1349 1350	/* initialize workqueue */1351 1352	ioc->fc_rescan_work_q = alloc_ordered_workqueue(1353		"mptfc_wq_%d", WQ_MEM_RECLAIM, sh->host_no);1354	if (!ioc->fc_rescan_work_q) {1355		error = -ENOMEM;1356		goto out_mptfc_host;1357	}1358 1359	/*1360	 *  Pre-fetch FC port WWN and stuff...1361	 *  (FCPortPage0_t stuff)1362	 */1363	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {1364		(void) mptfc_GetFcPortPage0(ioc, ii);1365	}1366	mptfc_SetFcPortPage1_defaults(ioc);1367 1368	/*1369	 * scan for rports -1370	 *	by doing it via the workqueue, some locking is eliminated1371	 */1372 1373	queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);1374	flush_workqueue(ioc->fc_rescan_work_q);1375 1376	return 0;1377 1378out_mptfc_host:1379	scsi_remove_host(sh);1380 1381out_mptfc_probe:1382 1383	mptscsih_remove(pdev);1384	return error;1385}1386 1387static struct pci_driver mptfc_driver = {1388	.name		= "mptfc",1389	.id_table	= mptfc_pci_table,1390	.probe		= mptfc_probe,1391	.remove		= mptfc_remove,1392	.shutdown	= mptscsih_shutdown,1393#ifdef CONFIG_PM1394	.suspend	= mptscsih_suspend,1395	.resume		= mptscsih_resume,1396#endif1397};1398 1399static int1400mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)1401{1402	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;1403	unsigned long flags;1404	int rc=1;1405 1406	if (ioc->bus_type != FC)1407		return 0;1408 1409	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",1410			ioc->name, event));1411 1412	if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)1413		return 1;1414 1415	switch (event) {1416	case MPI_EVENT_RESCAN:1417		spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);1418		if (ioc->fc_rescan_work_q) {1419			queue_work(ioc->fc_rescan_work_q,1420				   &ioc->fc_rescan_work);1421		}1422		spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);1423		break;1424	case MPI_EVENT_LINK_STATUS_CHANGE:1425		spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);1426		if (ioc->fc_rescan_work_q) {1427			queue_work(ioc->fc_rescan_work_q,1428				   &ioc->fc_lsc_work);1429		}1430		spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);1431		break;1432	default:1433		rc = mptscsih_event_process(ioc,pEvReply);1434		break;1435	}1436	return rc;1437}1438 1439static int1440mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)1441{1442	int		rc;1443	unsigned long	flags;1444 1445	rc = mptscsih_ioc_reset(ioc,reset_phase);1446	if ((ioc->bus_type != FC) || (!rc))1447		return rc;1448 1449 1450	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT1451		": IOC %s_reset routed to FC host driver!\n",ioc->name,1452		reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (1453		reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));1454 1455	if (reset_phase == MPT_IOC_SETUP_RESET) {1456		spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);1457		if (ioc->fc_rescan_work_q) {1458			queue_work(ioc->fc_rescan_work_q,1459				   &ioc->fc_setup_reset_work);1460		}1461		spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);1462	}1463 1464	else if (reset_phase == MPT_IOC_PRE_RESET) {1465	}1466 1467	else {	/* MPT_IOC_POST_RESET */1468		mptfc_SetFcPortPage1_defaults(ioc);1469		spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);1470		if (ioc->fc_rescan_work_q) {1471			queue_work(ioc->fc_rescan_work_q,1472				   &ioc->fc_rescan_work);1473		}1474		spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);1475	}1476	return 1;1477}1478 1479/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1480/**1481 *	mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.1482 *1483 *	Returns 0 for success, non-zero for failure.1484 */1485static int __init1486mptfc_init(void)1487{1488	int error;1489 1490	show_mptmod_ver(my_NAME, my_VERSION);1491 1492	/* sanity check module parameters */1493	if (mptfc_dev_loss_tmo <= 0)1494		mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;1495 1496	mptfc_transport_template =1497		fc_attach_transport(&mptfc_transport_functions);1498 1499	if (!mptfc_transport_template)1500		return -ENODEV;1501 1502	mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER,1503	    "mptscsih_scandv_complete");1504	mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER,1505	    "mptscsih_scandv_complete");1506	mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER,1507	    "mptscsih_scandv_complete");1508 1509	mpt_event_register(mptfcDoneCtx, mptfc_event_process);1510	mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset);1511 1512	error = pci_register_driver(&mptfc_driver);1513	if (error)1514		fc_release_transport(mptfc_transport_template);1515 1516	return error;1517}1518 1519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1520/**1521 *	mptfc_remove - Remove fc infrastructure for devices1522 *	@pdev: Pointer to pci_dev structure1523 *1524 */1525static void mptfc_remove(struct pci_dev *pdev)1526{1527	MPT_ADAPTER		*ioc = pci_get_drvdata(pdev);1528	struct mptfc_rport_info	*p, *n;1529	struct workqueue_struct *work_q;1530	unsigned long		flags;1531	int			ii;1532 1533	/* destroy workqueue */1534	if ((work_q=ioc->fc_rescan_work_q)) {1535		spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);1536		ioc->fc_rescan_work_q = NULL;1537		spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);1538		destroy_workqueue(work_q);1539	}1540 1541	fc_remove_host(ioc->sh);1542 1543	list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {1544		list_del(&p->list);1545		kfree(p);1546	}1547 1548	for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {1549		if (ioc->fc_data.fc_port_page1[ii].data) {1550			dma_free_coherent(&ioc->pcidev->dev,1551					  ioc->fc_data.fc_port_page1[ii].pg_sz,1552					  ioc->fc_data.fc_port_page1[ii].data,1553					  ioc->fc_data.fc_port_page1[ii].dma);1554			ioc->fc_data.fc_port_page1[ii].data = NULL;1555		}1556	}1557 1558	scsi_remove_host(ioc->sh);1559 1560	mptscsih_remove(pdev);1561}1562 1563/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1564/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1565/**1566 *	mptfc_exit - Unregisters MPT adapter(s)1567 *1568 */1569static void __exit1570mptfc_exit(void)1571{1572	pci_unregister_driver(&mptfc_driver);1573	fc_release_transport(mptfc_transport_template);1574 1575	mpt_reset_deregister(mptfcDoneCtx);1576	mpt_event_deregister(mptfcDoneCtx);1577 1578	mpt_deregister(mptfcInternalCtx);1579	mpt_deregister(mptfcTaskCtx);1580	mpt_deregister(mptfcDoneCtx);1581}1582 1583module_init(mptfc_init);1584module_exit(mptfc_exit);1585