diff options
159 files changed, 15221 insertions, 4070 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index d329b053a71..3c41de95a33 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -131,19 +131,12 @@ L:	netdev@vger.kernel.org  S:	Maintained  F:	drivers/net/typhoon* -3W-9XXX SATA-RAID CONTROLLER DRIVER -M:	Adam Radford <linuxraid@amcc.com> +3WARE SAS/SATA-RAID SCSI DRIVERS (3W-XXXX, 3W-9XXX, 3W-SAS) +M:	Adam Radford <linuxraid@lsi.com>  L:	linux-scsi@vger.kernel.org -W:	http://www.amcc.com +W:	http://www.lsi.com  S:	Supported -F:	drivers/scsi/3w-9xxx* - -3W-XXXX ATA-RAID CONTROLLER DRIVER -M:	Adam Radford <linuxraid@amcc.com> -L:	linux-scsi@vger.kernel.org -W:	http://www.amcc.com -S:	Supported -F:	drivers/scsi/3w-xxxx* +F:	drivers/scsi/3w-*  53C700 AND 53C700-66 SCSI DRIVER  M:	"James E.J. Bottomley" <James.Bottomley@HansenPartnership.com> @@ -4577,6 +4570,14 @@ S:	Supported  F:	Documentation/scsi/LICENSE.qla2xxx  F:	drivers/scsi/qla2xxx/ +QLOGIC QLA4XXX iSCSI DRIVER +M:	Ravi Anand <ravi.anand@qlogic.com> +M:	Vikas Chaudhary <vikas.chaudhary@qlogic.com> +M:	iscsi-driver@qlogic.com +L:	linux-scsi@vger.kernel.org +S:	Supported +F:	drivers/scsi/qla4xxx/ +  QLOGIC QLA3XXX NETWORK DRIVER  M:	Ron Mercer <ron.mercer@qlogic.com>  M:	linux-driver@qlogic.com diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 5382b5a44af..a6a57011ba6 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -5064,7 +5064,7 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)  		if (!timeleft) {  			printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",  			    ioc->name, __func__); -			mpt_HardResetHandler(ioc, CAN_SLEEP); +			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);  			mpt_free_msg_frame(ioc, mf);  		}  		goto out; @@ -6456,10 +6456,15 @@ out:  		issue_hard_reset = 0;  		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",  		    ioc->name, __func__); -		mpt_HardResetHandler(ioc, CAN_SLEEP); +		if (retry_count == 0) { +			if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0) +				retry_count++; +		} else +			mpt_HardResetHandler(ioc, CAN_SLEEP); +  		mpt_free_msg_frame(ioc, mf);  		/* attempt one retry for a timed out command */ -		if (!retry_count) { +		if (retry_count < 2) {  			printk(MYIOC_s_INFO_FMT  			    "Attempting Retry Config request"  			    " type 0x%x, page 0x%x," @@ -6904,6 +6909,172 @@ mpt_halt_firmware(MPT_ADAPTER *ioc)  }  EXPORT_SYMBOL(mpt_halt_firmware); +/** + *	mpt_SoftResetHandler - Issues a less expensive reset + *	@ioc: Pointer to MPT_ADAPTER structure + *	@sleepFlag: Indicates if sleep or schedule must be called. + + * + *	Returns 0 for SUCCESS or -1 if FAILED. + * + *	Message Unit Reset - instructs the IOC to reset the Reply Post and + *	Free FIFO's. All the Message Frames on Reply Free FIFO are discarded. + *	All posted buffers are freed, and event notification is turned off. + *	IOC doesnt reply to any outstanding request. This will transfer IOC + *	to READY state. + **/ +int +mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag) +{ +	int		 rc; +	int		 ii; +	u8		 cb_idx; +	unsigned long	 flags; +	u32		 ioc_state; +	unsigned long	 time_count; + +	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n", +		ioc->name)); + +	ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; + +	if (mpt_fwfault_debug) +		mpt_halt_firmware(ioc); + +	if (ioc_state == MPI_IOC_STATE_FAULT || +	    ioc_state == MPI_IOC_STATE_RESET) { +		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +		    "skipping, either in FAULT or RESET state!\n", ioc->name)); +		return -1; +	} + +	if (ioc->bus_type == FC) { +		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +		    "skipping, because the bus type is FC!\n", ioc->name)); +		return -1; +	} + +	spin_lock_irqsave(&ioc->taskmgmt_lock, flags); +	if (ioc->ioc_reset_in_progress) { +		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +		return -1; +	} +	ioc->ioc_reset_in_progress = 1; +	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + +	rc = -1; + +	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { +		if (MptResetHandlers[cb_idx]) +			mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); +	} + +	spin_lock_irqsave(&ioc->taskmgmt_lock, flags); +	if (ioc->taskmgmt_in_progress) { +		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +		return -1; +	} +	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +	/* Disable reply interrupts (also blocks FreeQ) */ +	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); +	ioc->active = 0; +	time_count = jiffies; + +	rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); + +	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { +		if (MptResetHandlers[cb_idx]) +			mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); +	} + +	if (rc) +		goto out; + +	ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; +	if (ioc_state != MPI_IOC_STATE_READY) +		goto out; + +	for (ii = 0; ii < 5; ii++) { +		/* Get IOC facts! Allow 5 retries */ +		rc = GetIocFacts(ioc, sleepFlag, +			MPT_HOSTEVENT_IOC_RECOVER); +		if (rc == 0) +			break; +		if (sleepFlag == CAN_SLEEP) +			msleep(100); +		else +			mdelay(100); +	} +	if (ii == 5) +		goto out; + +	rc = PrimeIocFifos(ioc); +	if (rc != 0) +		goto out; + +	rc = SendIocInit(ioc, sleepFlag); +	if (rc != 0) +		goto out; + +	rc = SendEventNotification(ioc, 1, sleepFlag); +	if (rc != 0) +		goto out; + +	if (ioc->hard_resets < -1) +		ioc->hard_resets++; + +	/* +	 * At this point, we know soft reset succeeded. +	 */ + +	ioc->active = 1; +	CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); + + out: +	spin_lock_irqsave(&ioc->taskmgmt_lock, flags); +	ioc->ioc_reset_in_progress = 0; +	ioc->taskmgmt_quiesce_io = 0; +	ioc->taskmgmt_in_progress = 0; +	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + +	if (ioc->active) {	/* otherwise, hard reset coming */ +		for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { +			if (MptResetHandlers[cb_idx]) +				mpt_signal_reset(cb_idx, ioc, +					MPT_IOC_POST_RESET); +		} +	} + +	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +		"SoftResetHandler: completed (%d seconds): %s\n", +		ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, +		((rc == 0) ? "SUCCESS" : "FAILED"))); + +	return rc; +} + +/** + *	mpt_Soft_Hard_ResetHandler - Try less expensive reset + *	@ioc: Pointer to MPT_ADAPTER structure + *	@sleepFlag: Indicates if sleep or schedule must be called. + + * + *	Returns 0 for SUCCESS or -1 if FAILED. + *	Try for softreset first, only if it fails go for expensive + *	HardReset. + **/ +int +mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) { +	int ret = -1; + +	ret = mpt_SoftResetHandler(ioc, sleepFlag); +	if (ret == 0) +		return ret; +	ret = mpt_HardResetHandler(ioc, sleepFlag); +	return ret; +} +EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler); +  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/  /*   *	Reset Handling diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 9718c8f2e95..b613eb3d470 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@  #define COPYRIGHT	"Copyright (c) 1999-2008 " MODULEAUTHOR  #endif -#define MPT_LINUX_VERSION_COMMON	"3.04.14" -#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.04.14" +#define MPT_LINUX_VERSION_COMMON	"3.04.15" +#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.04.15"  #define WHAT_MAGIC_STRING		"@" "(" "#" ")"  #define show_mptmod_ver(s,ver)  \ @@ -940,6 +940,7 @@ extern int	 mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);  extern u32	 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);  extern void	 mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);  extern int	 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); +extern int	 mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag);  extern int	 mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);  extern int	 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);  extern void	 mpt_free_fw_memory(MPT_ADAPTER *ioc); diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index caa8f568a41..f06b29193b4 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -128,7 +128,6 @@ static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags  		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);  static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,  		struct buflist *buflist, MPT_ADAPTER *ioc); -static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function);  /*   * Reset Handler cleanup function @@ -275,45 +274,6 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)  	return 1;  } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptctl_timeout_expired - * - * Expecting an interrupt, however timed out. - * - */ -static void -mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) -{ -	unsigned long flags; - -	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n", -		ioc->name, __func__)); - -	if (mpt_fwfault_debug) -		mpt_halt_firmware(ioc); - -	spin_lock_irqsave(&ioc->taskmgmt_lock, flags); -	if (ioc->ioc_reset_in_progress) { -		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); -		CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) -		mpt_free_msg_frame(ioc, mf); -		return; -	} -	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - - -	if (!mptctl_bus_reset(ioc, mf->u.hdr.Function)) -		return; - -	/* Issue a reset for this device. -	 * The IOC is not responding. -	 */ -	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", -		 ioc->name)); -	CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) -	mpt_HardResetHandler(ioc, CAN_SLEEP); -	mpt_free_msg_frame(ioc, mf); -}  static int  mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) @@ -343,12 +303,8 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)  	return 0;  } -/* mptctl_bus_reset - * - * Bus reset code. - * - */ -static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function) +static int +mptctl_do_taskmgmt(MPT_ADAPTER *ioc, u8 tm_type, u8 bus_id, u8 target_id)  {  	MPT_FRAME_HDR	*mf;  	SCSITaskMgmt_t	*pScsiTm; @@ -359,13 +315,6 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)  	unsigned long	 time_count;  	u16		 iocstatus; -	/* bus reset is only good for SCSI IO, RAID PASSTHRU */ -	if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || -		function == MPI_FUNCTION_SCSI_IO_REQUEST)) { -		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT -			"TaskMgmt, not SCSI_IO!!\n", ioc->name)); -		return -EPERM; -	}  	mutex_lock(&ioc->taskmgmt_cmds.mutex);  	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { @@ -375,15 +324,14 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)  	retval = 0; -	/* Send request -	 */  	mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc);  	if (mf == NULL) { -		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT -			"TaskMgmt, no msg frames!!\n", ioc->name)); +		dtmprintk(ioc, +			printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n", +			ioc->name));  		mpt_clear_taskmgmt_in_progress_flag(ioc);  		retval = -ENOMEM; -		goto mptctl_bus_reset_done; +		goto tm_done;  	}  	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", @@ -392,10 +340,13 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)  	pScsiTm = (SCSITaskMgmt_t *) mf;  	memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));  	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; -	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; -	pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; -	pScsiTm->TargetID = 0; -	pScsiTm->Bus = 0; +	pScsiTm->TaskType = tm_type; +	if ((tm_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && +		(ioc->bus_type == FC)) +		pScsiTm->MsgFlags = +				MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; +	pScsiTm->TargetID = target_id; +	pScsiTm->Bus = bus_id;  	pScsiTm->ChainOffset = 0;  	pScsiTm->Reserved = 0;  	pScsiTm->Reserved1 = 0; @@ -413,17 +364,16 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)  		timeout = 30;  		break;  	case SPI: -	default: -		timeout = 2; +		default: +		timeout = 10;  		break;  	} -	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT -		"TaskMgmt type=%d timeout=%ld\n", -		ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout)); +	dtmprintk(ioc, +		printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n", +		ioc->name, tm_type, timeout));  	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) -	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)  	time_count = jiffies;  	if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&  	    (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) @@ -432,17 +382,20 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)  		retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,  		    sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP);  		if (retval != 0) { -			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +			dfailprintk(ioc, +				printk(MYIOC_s_ERR_FMT  				"TaskMgmt send_handshake FAILED!"  				" (ioc %p, mf %p, rc=%d) \n", ioc->name,  				ioc, mf, retval)); +			mpt_free_msg_frame(ioc, mf);  			mpt_clear_taskmgmt_in_progress_flag(ioc); -			goto mptctl_bus_reset_done; +			goto tm_done;  		}  	}  	/* Now wait for the command to complete */  	ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); +  	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {  		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT  		    "TaskMgmt failed\n", ioc->name)); @@ -452,14 +405,14 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)  			retval = 0;  		else  			retval = -1; /* return failure */ -		goto mptctl_bus_reset_done; +		goto tm_done;  	}  	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {  		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT  		    "TaskMgmt failed\n", ioc->name));  		retval = -1; /* return failure */ -		goto mptctl_bus_reset_done; +		goto tm_done;  	}  	pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; @@ -467,7 +420,7 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)  	    "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "  	    "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "  	    "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus, -	    pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, +	    pScsiTmReply->TargetID, tm_type,  	    le16_to_cpu(pScsiTmReply->IOCStatus),  	    le32_to_cpu(pScsiTmReply->IOCLogInfo),  	    pScsiTmReply->ResponseCode, @@ -485,13 +438,71 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)  		retval = -1; /* return failure */  	} - - mptctl_bus_reset_done: + tm_done:  	mutex_unlock(&ioc->taskmgmt_cmds.mutex);  	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)  	return retval;  } +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptctl_timeout_expired + * + * Expecting an interrupt, however timed out. + * + */ +static void +mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) +{ +	unsigned long flags; +	int ret_val = -1; +	SCSIIORequest_t *scsi_req = (SCSIIORequest_t *) mf; +	u8 function = mf->u.hdr.Function; + +	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n", +		ioc->name, __func__)); + +	if (mpt_fwfault_debug) +		mpt_halt_firmware(ioc); + +	spin_lock_irqsave(&ioc->taskmgmt_lock, flags); +	if (ioc->ioc_reset_in_progress) { +		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +		CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) +		mpt_free_msg_frame(ioc, mf); +		return; +	} +	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + +	CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) + +	if (ioc->bus_type == SAS) { +		if (function == MPI_FUNCTION_SCSI_IO_REQUEST) +			ret_val = mptctl_do_taskmgmt(ioc, +				MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, +				scsi_req->Bus, scsi_req->TargetID); +		else if (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) +			ret_val = mptctl_do_taskmgmt(ioc, +				MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, +				scsi_req->Bus, 0); +		if (!ret_val) +			return; +	} else { +		if ((function == MPI_FUNCTION_SCSI_IO_REQUEST) || +			(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) +			ret_val = mptctl_do_taskmgmt(ioc, +				MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, +				scsi_req->Bus, 0); +		if (!ret_val) +			return; +	} + +	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling Reset! \n", +		 ioc->name)); +	mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); +	mpt_free_msg_frame(ioc, mf); +} +  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/  /* mptctl_ioc_reset @@ -1318,6 +1329,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)  	if (ioc->sh) {  		shost_for_each_device(sdev, ioc->sh) {  			vdevice = sdev->hostdata; +			if (vdevice == NULL || vdevice->vtarget == NULL) +				continue;  			if (vdevice->vtarget->tflags &  			    MPT_TARGET_FLAGS_RAID_COMPONENT)  				continue; @@ -1439,6 +1452,8 @@ mptctl_gettargetinfo (unsigned long arg)  			if (!maxWordsLeft)  				continue;  			vdevice = sdev->hostdata; +			if (vdevice == NULL || vdevice->vtarget == NULL) +				continue;  			if (vdevice->vtarget->tflags &  			    MPT_TARGET_FLAGS_RAID_COMPONENT)  				continue; @@ -1967,6 +1982,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)  				struct scsi_target *starget = scsi_target(sdev);  				VirtTarget *vtarget = starget->hostdata; +				if (vtarget == NULL) +					continue; +  				if ((pScsiReq->TargetID == vtarget->id) &&  				    (pScsiReq->Bus == vtarget->channel) &&  				    (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) @@ -2991,6 +3009,14 @@ static int __init mptctl_init(void)  	}  	mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER); +	if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) { +		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); +		mpt_deregister(mptctl_id); +		misc_deregister(&mptctl_miscdev); +		err = -EBUSY; +		goto out_fail; +	} +  	mpt_reset_register(mptctl_id, mptctl_ioc_reset);  	mpt_event_register(mptctl_id, mptctl_event_process); @@ -3010,12 +3036,15 @@ static void mptctl_exit(void)  	printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",  			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); +	/* De-register event handler from base module */ +	mpt_event_deregister(mptctl_id); +  	/* De-register reset handler from base module */  	mpt_reset_deregister(mptctl_id);  	/* De-register callback handler from base module */ +	mpt_deregister(mptctl_taskmgmt_id);  	mpt_deregister(mptctl_id); -	mpt_reset_deregister(mptctl_taskmgmt_id);          mpt_device_driver_deregister(MPTCTL_DRIVER); diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 33f7256055b..b5f03ad8156 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -482,6 +482,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)  				if (vtarget) {  					vtarget->id = pg0->CurrentTargetID;  					vtarget->channel = pg0->CurrentBus; +					vtarget->deleted = 0;  				}  			}  			*((struct mptfc_rport_info **)rport->dd_data) = ri; @@ -1092,6 +1093,8 @@ mptfc_setup_reset(struct work_struct *work)  		container_of(work, MPT_ADAPTER, fc_setup_reset_work);  	u64			pn;  	struct mptfc_rport_info *ri; +	struct scsi_target      *starget; +	VirtTarget              *vtarget;  	/* reset about to happen, delete (block) all rports */  	list_for_each_entry(ri, &ioc->fc_rports, list) { @@ -1099,6 +1102,12 @@ mptfc_setup_reset(struct work_struct *work)  			ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;  			fc_remote_port_delete(ri->rport);	/* won't sleep */  			ri->rport = NULL; +			starget = ri->starget; +			if (starget) { +				vtarget = starget->hostdata; +				if (vtarget) +					vtarget->deleted = 1; +			}  			pn = (u64)ri->pg0.WWPN.High << 32 |  			     (u64)ri->pg0.WWPN.Low; @@ -1119,6 +1128,8 @@ mptfc_rescan_devices(struct work_struct *work)  	int			ii;  	u64			pn;  	struct mptfc_rport_info *ri; +	struct scsi_target      *starget; +	VirtTarget              *vtarget;  	/* start by tagging all ports as missing */  	list_for_each_entry(ri, &ioc->fc_rports, list) { @@ -1146,6 +1157,12 @@ mptfc_rescan_devices(struct work_struct *work)  				       MPT_RPORT_INFO_FLAGS_MISSING);  			fc_remote_port_delete(ri->rport);	/* won't sleep */  			ri->rport = NULL; +			starget = ri->starget; +			if (starget) { +				vtarget = starget->hostdata; +				if (vtarget) +					vtarget->deleted = 1; +			}  			pn = (u64)ri->pg0.WWPN.High << 32 |  			     (u64)ri->pg0.WWPN.Low; @@ -1358,6 +1375,9 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)  	unsigned long flags;  	int rc=1; +	if (ioc->bus_type != FC) +		return 0; +  	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",  			ioc->name, event)); @@ -1396,7 +1416,7 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)  	unsigned long	flags;  	rc = mptscsih_ioc_reset(ioc,reset_phase); -	if (rc == 0) +	if ((ioc->bus_type != FC) || (!rc))  		return rc; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 76687126b57..ac000e83db0 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1894,7 +1894,7 @@ static struct scsi_host_template mptsas_driver_template = {  	.module				= THIS_MODULE,  	.proc_name			= "mptsas",  	.proc_info			= mptscsih_proc_info, -	.name				= "MPT SPI Host", +	.name				= "MPT SAS Host",  	.info				= mptscsih_info,  	.queuecommand			= mptsas_qcmd,  	.target_alloc			= mptsas_target_alloc, @@ -2038,11 +2038,13 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)  	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,  			10 * HZ); -	if (!timeleft) { -		/* On timeout reset the board */ +	if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { +		error = -ETIME;  		mpt_free_msg_frame(ioc, mf); -		mpt_HardResetHandler(ioc, CAN_SLEEP); -		error = -ETIMEDOUT; +		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) +			goto out_unlock; +		if (!timeleft) +			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);  		goto out_unlock;  	} @@ -2223,11 +2225,14 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  	mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);  	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); -	if (!timeleft) { -		printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__); -		/* On timeout reset the board */ -		mpt_HardResetHandler(ioc, CAN_SLEEP); -		ret = -ETIMEDOUT; +	if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { +		ret = -ETIME; +		mpt_free_msg_frame(ioc, mf); +		mf = NULL; +		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) +			goto unmap; +		if (!timeleft) +			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);  		goto unmap;  	}  	mf = NULL; @@ -2518,6 +2523,12 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,  	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;  	error = mpt_config(ioc, &cfg); + +	if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { +		error = -ENODEV; +		goto out_free_consistent; +	} +  	if (error)  		goto out_free_consistent; @@ -2594,14 +2605,14 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,  	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;  	error = mpt_config(ioc, &cfg); -	if (error) -		goto out_free_consistent; - -	if (!buffer->NumPhys) { +	if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {  		error = -ENODEV;  		goto out_free_consistent;  	} +	if (error) +		goto out_free_consistent; +  	/* save config data */  	port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;  	port_info->phy_info = kcalloc(port_info->num_phys, @@ -2677,7 +2688,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,  	if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {  		error = -ENODEV; -		goto out; +		goto out_free_consistent;  	}  	if (error) @@ -2833,7 +2844,7 @@ mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,  		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)  			goto out_free;  		if (!timeleft) -			mpt_HardResetHandler(ioc, CAN_SLEEP); +			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);  		goto out_free;  	} @@ -4098,6 +4109,7 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)  	cfg.pageAddr = (channel << 8) + id;  	cfg.cfghdr.hdr = &hdr;  	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; +	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;  	if (mpt_config(ioc, &cfg) != 0)  		goto out; @@ -4717,7 +4729,7 @@ mptsas_broadcast_primative_work(struct fw_event_work *fw_event)  	if (issue_reset) {  		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",  		    ioc->name, __func__); -		mpt_HardResetHandler(ioc, CAN_SLEEP); +		mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);  	}  	mptsas_free_fw_event(ioc, fw_event);  } @@ -4779,6 +4791,9 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)  	struct fw_event_work *fw_event;  	unsigned long delay; +	if (ioc->bus_type != SAS) +		return 0; +  	/* events turned off due to host reset or driver unloading */  	if (ioc->fw_events_off)  		return 0; @@ -5073,6 +5088,12 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)  	struct mptsas_portinfo *p, *n;  	int i; +	if (!ioc->sh) { +		printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name); +		mpt_detach(pdev); +		return; +	} +  	mptsas_shutdown(pdev);  	mptsas_del_device_components(ioc); diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h index 953c2bfcf6a..7b249edbda7 100644 --- a/drivers/message/fusion/mptsas.h +++ b/drivers/message/fusion/mptsas.h @@ -110,7 +110,7 @@ struct fw_event_work {  	MPT_ADAPTER	*ioc;  	u32			event;  	u8			retries; -	u8			event_data[1]; +	u8			__attribute__((aligned(4))) event_data[1];  };  struct mptsas_discovery_event { diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 6796597dcee..7bd4c0fc23c 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1149,11 +1149,6 @@ mptscsih_remove(struct pci_dev *pdev)  	MPT_SCSI_HOST		*hd;  	int sz1; -	if(!host) { -		mpt_detach(pdev); -		return; -	} -  	scsi_remove_host(host);  	if((hd = shost_priv(host)) == NULL) @@ -1711,7 +1706,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,  	if (issue_hard_reset) {  		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",  			ioc->name, __func__); -		retval = mpt_HardResetHandler(ioc, CAN_SLEEP); +		retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);  		mpt_free_msg_frame(ioc, mf);  	} @@ -1728,6 +1723,7 @@ mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)  	case FC:  		return 40;  	case SAS: +		return 30;  	case SPI:  	default:  		return 10; @@ -1777,7 +1773,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)  		    ioc->name, SCpnt));  		SCpnt->result = DID_NO_CONNECT << 16;  		SCpnt->scsi_done(SCpnt); -		retval = 0; +		retval = SUCCESS;  		goto out;  	} @@ -1792,6 +1788,17 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)  		goto out;  	} +	/* Task aborts are not supported for volumes. +	 */ +	if (vdevice->vtarget->raidVolume) { +		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +		    "task abort: raid volume (sc=%p)\n", +		    ioc->name, SCpnt)); +		SCpnt->result = DID_RESET << 16; +		retval = FAILED; +		goto out; +	} +  	/* Find this command  	 */  	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) { @@ -1991,7 +1998,7 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)  	/*  If our attempts to reset the host failed, then return a failed  	 *  status.  The host will be taken off line by the SCSI mid-layer.  	 */ -    retval = mpt_HardResetHandler(ioc, CAN_SLEEP); +    retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);  	if (retval < 0)  		status = FAILED;  	else @@ -2344,6 +2351,8 @@ mptscsih_slave_destroy(struct scsi_device *sdev)  	starget = scsi_target(sdev);  	vtarget = starget->hostdata;  	vdevice = sdev->hostdata; +	if (!vdevice) +		return;  	mptscsih_search_running_cmds(hd, vdevice);  	vtarget->num_luns--; @@ -3040,7 +3049,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)  		if (!timeleft) {  			printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",  			    ioc->name, __func__); -			mpt_HardResetHandler(ioc, CAN_SLEEP); +			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);  			mpt_free_msg_frame(ioc, mf);  		}  		goto out; diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index e44365193fd..1abaa5d01ae 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -210,6 +210,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,  	target->maxOffset = offset;  	target->maxWidth = width; +	spi_min_period(scsi_target(sdev)) = factor; +	spi_max_offset(scsi_target(sdev)) = offset; +	spi_max_width(scsi_target(sdev)) = width; +  	target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;  	/* Disable unused features. @@ -558,6 +562,7 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,  	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;  	cfg.dir = 0;  	cfg.pageAddr = starget->id; +	cfg.timeout = 60;  	if (mpt_config(ioc, &cfg)) {  		starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name); @@ -1152,6 +1157,9 @@ mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)  	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;  	struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); +	if (ioc->bus_type != SPI) +		return 0; +  	if (hd && event ==  MPI_EVENT_INTEGRATED_RAID) {  		int reason  			= (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16; @@ -1283,6 +1291,8 @@ mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)  	int rc;  	rc = mptscsih_ioc_reset(ioc, reset_phase); +	if ((ioc->bus_type != SPI) || (!rc)) +		return rc;  	/* only try to do a renegotiation if we're properly set up  	 * if we get an ioc fault on bringup, ioc->sh will be NULL */ diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 1e6183a86ce..e331df2122f 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -425,7 +425,8 @@ int zfcp_status_read_refill(struct zfcp_adapter *adapter)  {  	while (atomic_read(&adapter->stat_miss) > 0)  		if (zfcp_fsf_status_read(adapter->qdio)) { -			if (atomic_read(&adapter->stat_miss) >= 16) { +			if (atomic_read(&adapter->stat_miss) >= +			    adapter->stat_read_buf_num) {  				zfcp_erp_adapter_reopen(adapter, 0, "axsref1",  							NULL);  				return 1; @@ -545,6 +546,10 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)  			       &zfcp_sysfs_adapter_attrs))  		goto failed; +	/* report size limit per scatter-gather segment */ +	adapter->dma_parms.max_segment_size = ZFCP_QDIO_SBALE_LEN; +	adapter->ccw_device->dev.dma_parms = &adapter->dma_parms; +  	if (!zfcp_adapter_scsi_register(adapter))  		return adapter; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 7131c7db1f0..9fa1b064893 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -44,23 +44,6 @@ struct zfcp_reqlist;  /********************* SCSI SPECIFIC DEFINES *********************************/  #define ZFCP_SCSI_ER_TIMEOUT                    (10*HZ) -/********************* CIO/QDIO SPECIFIC DEFINES *****************************/ - -/* DMQ bug workaround: don't use last SBALE */ -#define ZFCP_MAX_SBALES_PER_SBAL	(QDIO_MAX_ELEMENTS_PER_BUFFER - 1) - -/* index of last SBALE (with respect to DMQ bug workaround) */ -#define ZFCP_LAST_SBALE_PER_SBAL	(ZFCP_MAX_SBALES_PER_SBAL - 1) - -/* max. number of (data buffer) SBALEs in largest SBAL chain */ -#define ZFCP_MAX_SBALES_PER_REQ		\ -	(FSF_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2) -        /* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */ - -#define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8) -        /* max. number of (data buffer) SBALEs in largest SBAL chain -           multiplied with number of sectors per 4k block */ -  /********************* FSF SPECIFIC DEFINES *********************************/  /* ATTENTION: value must not be used by hardware */ @@ -181,6 +164,7 @@ struct zfcp_adapter {  						      stack abort/command  						      completion races */  	atomic_t		stat_miss;	   /* # missing status reads*/ +	unsigned int		stat_read_buf_num;  	struct work_struct	stat_work;  	atomic_t		status;	           /* status of this adapter */  	struct list_head	erp_ready_head;	   /* error recovery for this @@ -205,6 +189,7 @@ struct zfcp_adapter {  	struct work_struct	scan_work;  	struct service_level	service_level;  	struct workqueue_struct	*work_queue; +	struct device_dma_parameters dma_parms;  };  struct zfcp_port { diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 0be5e7ea282..e3dbeda9717 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -714,7 +714,7 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)  	if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)  		return ZFCP_ERP_FAILED; -	atomic_set(&act->adapter->stat_miss, 16); +	atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);  	if (zfcp_status_read_refill(act->adapter))  		return ZFCP_ERP_FAILED; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 8786a79c7f8..48a8f93b72f 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -3,7 +3,7 @@   *   * External function declarations.   * - * Copyright IBM Corporation 2002, 2009 + * Copyright IBM Corporation 2002, 2010   */  #ifndef ZFCP_EXT_H @@ -143,9 +143,9 @@ extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int);  /* zfcp_qdio.c */  extern int zfcp_qdio_setup(struct zfcp_adapter *);  extern void zfcp_qdio_destroy(struct zfcp_qdio *); +extern int zfcp_qdio_sbal_get(struct zfcp_qdio *);  extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *); -extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, -				   struct zfcp_qdio_req *, unsigned long, +extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,  				   struct scatterlist *, int);  extern int zfcp_qdio_open(struct zfcp_qdio *);  extern void zfcp_qdio_close(struct zfcp_qdio *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 2a1cbb74b99..6f8ab43a485 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -400,7 +400,7 @@ static int zfcp_fc_adisc(struct zfcp_port *port)  	struct zfcp_adapter *adapter = port->adapter;  	int ret; -	adisc = kmem_cache_alloc(zfcp_data.adisc_cache, GFP_ATOMIC); +	adisc = kmem_cache_zalloc(zfcp_data.adisc_cache, GFP_ATOMIC);  	if (!adisc)  		return -ENOMEM; @@ -493,7 +493,7 @@ static struct zfcp_fc_gpn_ft *zfcp_alloc_sg_env(int buf_num)  	if (!gpn_ft)  		return NULL; -	req = kmem_cache_alloc(zfcp_data.gpn_ft_cache, GFP_KERNEL); +	req = kmem_cache_zalloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);  	if (!req) {  		kfree(gpn_ft);  		gpn_ft = NULL; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index b3b1d2f7939..9ac6a6e4a60 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -496,6 +496,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)  	adapter->hydra_version = bottom->adapter_type;  	adapter->timer_ticks = bottom->timer_interval; +	adapter->stat_read_buf_num = max(bottom->status_read_buf_num, (u16)16);  	if (fc_host_permanent_port_name(shost) == -1)  		fc_host_permanent_port_name(shost) = fc_host_port_name(shost); @@ -640,37 +641,6 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)  	}  } -static int zfcp_fsf_sbal_check(struct zfcp_qdio *qdio) -{ -	struct zfcp_qdio_queue *req_q = &qdio->req_q; - -	spin_lock_bh(&qdio->req_q_lock); -	if (atomic_read(&req_q->count)) -		return 1; -	spin_unlock_bh(&qdio->req_q_lock); -	return 0; -} - -static int zfcp_fsf_req_sbal_get(struct zfcp_qdio *qdio) -{ -	struct zfcp_adapter *adapter = qdio->adapter; -	long ret; - -	spin_unlock_bh(&qdio->req_q_lock); -	ret = wait_event_interruptible_timeout(qdio->req_q_wq, -			       zfcp_fsf_sbal_check(qdio), 5 * HZ); -	if (ret > 0) -		return 0; -	if (!ret) { -		atomic_inc(&qdio->req_q_full); -		/* assume hanging outbound queue, try queue recovery */ -		zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL); -	} - -	spin_lock_bh(&qdio->req_q_lock); -	return -EIO; -} -  static struct zfcp_fsf_req *zfcp_fsf_alloc(mempool_t *pool)  {  	struct zfcp_fsf_req *req; @@ -705,10 +675,9 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool)  }  static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, -						u32 fsf_cmd, mempool_t *pool) +						u32 fsf_cmd, u32 sbtype, +						mempool_t *pool)  { -	struct qdio_buffer_element *sbale; -	struct zfcp_qdio_queue *req_q = &qdio->req_q;  	struct zfcp_adapter *adapter = qdio->adapter;  	struct zfcp_fsf_req *req = zfcp_fsf_alloc(pool); @@ -725,14 +694,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,  	req->adapter = adapter;  	req->fsf_command = fsf_cmd;  	req->req_id = adapter->req_no; -	req->qdio_req.sbal_number = 1; -	req->qdio_req.sbal_first = req_q->first; -	req->qdio_req.sbal_last = req_q->first; -	req->qdio_req.sbale_curr = 1; - -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].addr = (void *) req->req_id; -	sbale[0].flags |= SBAL_FLAGS0_COMMAND;  	if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {  		if (likely(pool)) @@ -753,10 +714,11 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,  		req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;  		req->qtcb->header.req_handle = req->req_id;  		req->qtcb->header.fsf_command = req->fsf_command; -		sbale[1].addr = (void *) req->qtcb; -		sbale[1].length = sizeof(struct fsf_qtcb);  	} +	zfcp_qdio_req_init(adapter->qdio, &req->qdio_req, req->req_id, sbtype, +			   req->qtcb, sizeof(struct fsf_qtcb)); +  	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {  		zfcp_fsf_req_free(req);  		return ERR_PTR(-EIO); @@ -803,24 +765,19 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)  	struct zfcp_adapter *adapter = qdio->adapter;  	struct zfcp_fsf_req *req;  	struct fsf_status_read_buffer *sr_buf; -	struct qdio_buffer_element *sbale;  	int retval = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out; -	req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, +	req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, 0,  				  adapter->pool.status_read_req);  	if (IS_ERR(req)) {  		retval = PTR_ERR(req);  		goto out;  	} -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; -	req->qdio_req.sbale_curr = 2; -  	sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC);  	if (!sr_buf) {  		retval = -ENOMEM; @@ -828,9 +785,9 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)  	}  	memset(sr_buf, 0, sizeof(*sr_buf));  	req->data = sr_buf; -	sbale = zfcp_qdio_sbale_curr(qdio, &req->qdio_req); -	sbale->addr = (void *) sr_buf; -	sbale->length = sizeof(*sr_buf); + +	zfcp_qdio_fill_next(qdio, &req->qdio_req, sr_buf, sizeof(*sr_buf)); +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	retval = zfcp_fsf_req_send(req);  	if (retval) @@ -907,14 +864,14 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)  struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,  						struct zfcp_unit *unit)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_fsf_req *req = NULL;  	struct zfcp_qdio *qdio = unit->port->adapter->qdio;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND, +				  SBAL_FLAGS0_TYPE_READ,  				  qdio->adapter->pool.scsi_abort);  	if (IS_ERR(req)) {  		req = NULL; @@ -925,9 +882,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,  		       ZFCP_STATUS_COMMON_UNBLOCKED)))  		goto out_error_free; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->data = unit;  	req->handler = zfcp_fsf_abort_fcp_command_handler; @@ -996,21 +951,14 @@ skip_fsfstatus:  		ct->handler(ct->handler_data);  } -static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale, +static void zfcp_fsf_setup_ct_els_unchained(struct zfcp_qdio *qdio, +					    struct zfcp_qdio_req *q_req,  					    struct scatterlist *sg_req,  					    struct scatterlist *sg_resp)  { -	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; -	sbale[2].addr   = sg_virt(sg_req); -	sbale[2].length = sg_req->length; -	sbale[3].addr   = sg_virt(sg_resp); -	sbale[3].length = sg_resp->length; -	sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; -} - -static int zfcp_fsf_one_sbal(struct scatterlist *sg) -{ -	return sg_is_last(sg) && sg->length <= PAGE_SIZE; +	zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_req), sg_req->length); +	zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_resp), sg_resp->length); +	zfcp_qdio_set_sbale_last(qdio, q_req);  }  static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, @@ -1019,35 +967,34 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,  				       int max_sbals)  {  	struct zfcp_adapter *adapter = req->adapter; -	struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(adapter->qdio, -							       &req->qdio_req);  	u32 feat = adapter->adapter_features;  	int bytes;  	if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { -		if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp)) +		if (!zfcp_qdio_sg_one_sbale(sg_req) || +		    !zfcp_qdio_sg_one_sbale(sg_resp))  			return -EOPNOTSUPP; -		zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp); +		zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req, +						sg_req, sg_resp);  		return 0;  	}  	/* use single, unchained SBAL if it can hold the request */ -	if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) { -		zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp); +	if (zfcp_qdio_sg_one_sbale(sg_req) || zfcp_qdio_sg_one_sbale(sg_resp)) { +		zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req, +						sg_req, sg_resp);  		return 0;  	}  	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, -					SBAL_FLAGS0_TYPE_WRITE_READ,  					sg_req, max_sbals);  	if (bytes <= 0)  		return -EIO;  	req->qtcb->bottom.support.req_buf_length = bytes; -	req->qdio_req.sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; +	zfcp_qdio_skip_to_last_sbale(&req->qdio_req);  	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, -					SBAL_FLAGS0_TYPE_WRITE_READ,  					sg_resp, max_sbals);  	req->qtcb->bottom.support.resp_buf_length = bytes;  	if (bytes <= 0) @@ -1091,10 +1038,11 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,  	int ret = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out; -	req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, pool); +	req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, +				  SBAL_FLAGS0_TYPE_WRITE_READ, pool);  	if (IS_ERR(req)) {  		ret = PTR_ERR(req); @@ -1103,7 +1051,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;  	ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, -				    FSF_MAX_SBALS_PER_REQ, timeout); +				    ZFCP_FSF_MAX_SBALS_PER_REQ, timeout);  	if (ret)  		goto failed_send; @@ -1187,10 +1135,11 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,  	int ret = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out; -	req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, NULL); +	req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, +				  SBAL_FLAGS0_TYPE_WRITE_READ, NULL);  	if (IS_ERR(req)) {  		ret = PTR_ERR(req); @@ -1224,16 +1173,16 @@ out:  int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_fsf_req *req;  	struct zfcp_qdio *qdio = erp_action->adapter->qdio;  	int retval = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, +				  SBAL_FLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1242,9 +1191,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->qtcb->bottom.config.feature_selection =  			FSF_FEATURE_CFDC | @@ -1269,24 +1216,22 @@ out:  int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,  				       struct fsf_qtcb_bottom_config *data)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_fsf_req *req = NULL;  	int retval = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out_unlock; -	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, NULL); +	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, +				  SBAL_FLAGS0_TYPE_READ, NULL);  	if (IS_ERR(req)) {  		retval = PTR_ERR(req);  		goto out_unlock;  	} -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->handler = zfcp_fsf_exchange_config_data_handler;  	req->qtcb->bottom.config.feature_selection = @@ -1320,7 +1265,6 @@ out_unlock:  int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)  {  	struct zfcp_qdio *qdio = erp_action->adapter->qdio; -	struct qdio_buffer_element *sbale;  	struct zfcp_fsf_req *req;  	int retval = -EIO; @@ -1328,10 +1272,11 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)  		return -EOPNOTSUPP;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, +				  SBAL_FLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1340,9 +1285,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->handler = zfcp_fsf_exchange_port_data_handler;  	req->erp_action = erp_action; @@ -1368,7 +1311,6 @@ out:  int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,  				     struct fsf_qtcb_bottom_port *data)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_fsf_req *req = NULL;  	int retval = -EIO; @@ -1376,10 +1318,11 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,  		return -EOPNOTSUPP;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out_unlock; -	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, NULL); +	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, +				  SBAL_FLAGS0_TYPE_READ, NULL);  	if (IS_ERR(req)) {  		retval = PTR_ERR(req); @@ -1389,9 +1332,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,  	if (data)  		req->data = data; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->handler = zfcp_fsf_exchange_port_data_handler;  	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); @@ -1485,17 +1426,17 @@ out:   */  int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_qdio *qdio = erp_action->adapter->qdio;  	struct zfcp_port *port = erp_action->port;  	struct zfcp_fsf_req *req;  	int retval = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID, +				  SBAL_FLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1504,9 +1445,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->handler = zfcp_fsf_open_port_handler;  	hton24(req->qtcb->bottom.support.d_id, port->d_id); @@ -1556,16 +1495,16 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)   */  int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_qdio *qdio = erp_action->adapter->qdio;  	struct zfcp_fsf_req *req;  	int retval = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT, +				  SBAL_FLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1574,9 +1513,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->handler = zfcp_fsf_close_port_handler;  	req->data = erp_action->port; @@ -1633,16 +1570,16 @@ out:   */  int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_qdio *qdio = wka_port->adapter->qdio;  	struct zfcp_fsf_req *req;  	int retval = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID, +				  SBAL_FLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (unlikely(IS_ERR(req))) { @@ -1651,9 +1588,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->handler = zfcp_fsf_open_wka_port_handler;  	hton24(req->qtcb->bottom.support.d_id, wka_port->d_id); @@ -1688,16 +1623,16 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)   */  int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_qdio *qdio = wka_port->adapter->qdio;  	struct zfcp_fsf_req *req;  	int retval = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT, +				  SBAL_FLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (unlikely(IS_ERR(req))) { @@ -1706,9 +1641,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->handler = zfcp_fsf_close_wka_port_handler;  	req->data = wka_port; @@ -1782,16 +1715,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)   */  int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_qdio *qdio = erp_action->adapter->qdio;  	struct zfcp_fsf_req *req;  	int retval = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT, +				  SBAL_FLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1800,9 +1733,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->data = erp_action->port;  	req->qtcb->header.port_handle = erp_action->port->handle; @@ -1954,17 +1885,17 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)   */  int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_adapter *adapter = erp_action->adapter;  	struct zfcp_qdio *qdio = adapter->qdio;  	struct zfcp_fsf_req *req;  	int retval = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN, +				  SBAL_FLAGS0_TYPE_READ,  				  adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1973,9 +1904,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->qtcb->header.port_handle = erp_action->port->handle;  	req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; @@ -2041,16 +1970,16 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)   */  int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_qdio *qdio = erp_action->adapter->qdio;  	struct zfcp_fsf_req *req;  	int retval = -EIO;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN, +				  SBAL_FLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -2059,9 +1988,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->qtcb->header.port_handle = erp_action->port->handle;  	req->qtcb->header.lun_handle = erp_action->unit->handle; @@ -2289,8 +2216,11 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,  		goto out;  	} +	if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) +		sbtype = SBAL_FLAGS0_TYPE_WRITE; +  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND, -				  adapter->pool.scsi_req); +				  sbtype, adapter->pool.scsi_req);  	if (IS_ERR(req)) {  		retval = PTR_ERR(req); @@ -2298,7 +2228,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	get_device(&unit->dev);  	req->unit = unit;  	req->data = scsi_cmnd;  	req->handler = zfcp_fsf_send_fcp_command_handler; @@ -2323,20 +2252,21 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,  		break;  	case DMA_TO_DEVICE:  		req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; -		sbtype = SBAL_FLAGS0_TYPE_WRITE;  		break;  	case DMA_BIDIRECTIONAL:  		goto failed_scsi_cmnd;  	} +	get_device(&unit->dev); +  	fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;  	zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd); -	real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sbtype, +	real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,  					     scsi_sglist(scsi_cmnd), -					     FSF_MAX_SBALS_PER_REQ); +					     ZFCP_FSF_MAX_SBALS_PER_REQ);  	if (unlikely(real_bytes < 0)) { -		if (req->qdio_req.sbal_number >= FSF_MAX_SBALS_PER_REQ) { +		if (req->qdio_req.sbal_number >= ZFCP_FSF_MAX_SBALS_PER_REQ) {  			dev_err(&adapter->ccw_device->dev,  				"Oversize data package, unit 0x%016Lx "  				"on port 0x%016Lx closed\n", @@ -2371,7 +2301,6 @@ out:   */  struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_fsf_req *req = NULL;  	struct fcp_cmnd *fcp_cmnd;  	struct zfcp_qdio *qdio = unit->port->adapter->qdio; @@ -2381,10 +2310,11 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)  		return NULL;  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND, +				  SBAL_FLAGS0_TYPE_WRITE,  				  qdio->adapter->pool.scsi_req);  	if (IS_ERR(req)) { @@ -2401,9 +2331,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)  	req->qtcb->bottom.io.service_class = FSF_CLASS_3;  	req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; -	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;  	zfcp_fc_fcp_tm(fcp_cmnd, unit->device, tm_flags); @@ -2432,7 +2360,6 @@ static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)  struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,  					   struct zfcp_fsf_cfdc *fsf_cfdc)  { -	struct qdio_buffer_element *sbale;  	struct zfcp_qdio *qdio = adapter->qdio;  	struct zfcp_fsf_req *req = NULL;  	struct fsf_qtcb_bottom_support *bottom; @@ -2453,10 +2380,10 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,  	}  	spin_lock_bh(&qdio->req_q_lock); -	if (zfcp_fsf_req_sbal_get(qdio)) +	if (zfcp_qdio_sbal_get(qdio))  		goto out; -	req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, NULL); +	req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, direction, NULL);  	if (IS_ERR(req)) {  		retval = -EPERM;  		goto out; @@ -2464,16 +2391,13 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,  	req->handler = zfcp_fsf_control_file_handler; -	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req); -	sbale[0].flags |= direction; -  	bottom = &req->qtcb->bottom.support;  	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;  	bottom->option = fsf_cfdc->option;  	bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, -					direction, fsf_cfdc->sg, -					FSF_MAX_SBALS_PER_REQ); +					fsf_cfdc->sg, +					ZFCP_FSF_MAX_SBALS_PER_REQ);  	if (bytes != ZFCP_CFDC_MAX_SIZE) {  		zfcp_fsf_req_free(req);  		goto out; diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index b3de682b64c..519083fd6e8 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -3,7 +3,7 @@   *   * Interface to the FSF support functions.   * - * Copyright IBM Corporation 2002, 2009 + * Copyright IBM Corporation 2002, 2010   */  #ifndef FSF_H @@ -152,7 +152,12 @@  #define FSF_CLASS_3				0x00000003  /* SBAL chaining */ -#define FSF_MAX_SBALS_PER_REQ			36 +#define ZFCP_FSF_MAX_SBALS_PER_REQ		36 + +/* max. number of (data buffer) SBALEs in largest SBAL chain + * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain   */ +#define ZFCP_FSF_MAX_SBALES_PER_REQ	\ +	(ZFCP_FSF_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)  /* logging space behind QTCB */  #define FSF_QTCB_LOG_SIZE			1024 @@ -361,7 +366,7 @@ struct fsf_qtcb_bottom_config {  	u32 adapter_type;  	u8 res0;  	u8 peer_d_id[3]; -	u8 res1[2]; +	u16 status_read_buf_num;  	u16 timer_interval;  	u8 res2[9];  	u8 s_id[3]; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index dbfa312a7f5..28117e130e2 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -3,7 +3,7 @@   *   * Setup and helper functions to access QDIO.   * - * Copyright IBM Corporation 2002, 2009 + * Copyright IBM Corporation 2002, 2010   */  #define KMSG_COMPONENT "zfcp" @@ -151,8 +151,7 @@ static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,  }  static struct qdio_buffer_element * -zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, -		     unsigned long sbtype) +zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)  {  	struct qdio_buffer_element *sbale; @@ -180,17 +179,16 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,  	/* set storage-block type for new SBAL */  	sbale = zfcp_qdio_sbale_curr(qdio, q_req); -	sbale->flags |= sbtype; +	sbale->flags |= q_req->sbtype;  	return sbale;  }  static struct qdio_buffer_element * -zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, -		     unsigned int sbtype) +zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)  { -	if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) -		return zfcp_qdio_sbal_chain(qdio, q_req, sbtype); +	if (q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL) +		return zfcp_qdio_sbal_chain(qdio, q_req);  	q_req->sbale_curr++;  	return zfcp_qdio_sbale_curr(qdio, q_req);  } @@ -206,62 +204,38 @@ static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,  	zfcp_qdio_zero_sbals(sbal, first, count);  } -static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio, -				struct zfcp_qdio_req *q_req, -				unsigned int sbtype, void *start_addr, -				unsigned int total_length) -{ -	struct qdio_buffer_element *sbale; -	unsigned long remaining, length; -	void *addr; - -	/* split segment up */ -	for (addr = start_addr, remaining = total_length; remaining > 0; -	     addr += length, remaining -= length) { -		sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype); -		if (!sbale) { -			atomic_inc(&qdio->req_q_full); -			zfcp_qdio_undo_sbals(qdio, q_req); -			return -EINVAL; -		} - -		/* new piece must not exceed next page boundary */ -		length = min(remaining, -			     (PAGE_SIZE - ((unsigned long)addr & -					   (PAGE_SIZE - 1)))); -		sbale->addr = addr; -		sbale->length = length; -	} -	return 0; -} -  /**   * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list - * @fsf_req: request to be processed - * @sbtype: SBALE flags + * @qdio: pointer to struct zfcp_qdio + * @q_req: pointer to struct zfcp_qdio_req   * @sg: scatter-gather list   * @max_sbals: upper bound for number of SBALs to be used   * Returns: number of bytes, or error (negativ)   */  int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, -			    unsigned long sbtype, struct scatterlist *sg, -			    int max_sbals) +			    struct scatterlist *sg, int max_sbals)  {  	struct qdio_buffer_element *sbale; -	int retval, bytes = 0; +	int bytes = 0;  	/* figure out last allowed SBAL */  	zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);  	/* set storage-block type for this request */  	sbale = zfcp_qdio_sbale_req(qdio, q_req); -	sbale->flags |= sbtype; +	sbale->flags |= q_req->sbtype;  	for (; sg; sg = sg_next(sg)) { -		retval = zfcp_qdio_fill_sbals(qdio, q_req, sbtype, -					      sg_virt(sg), sg->length); -		if (retval < 0) -			return retval; +		sbale = zfcp_qdio_sbale_next(qdio, q_req); +		if (!sbale) { +			atomic_inc(&qdio->req_q_full); +			zfcp_qdio_undo_sbals(qdio, q_req); +			return -EINVAL; +		} + +		sbale->addr = sg_virt(sg); +		sbale->length = sg->length; +  		bytes += sg->length;  	} @@ -272,6 +246,46 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,  	return bytes;  } +static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio) +{ +	struct zfcp_qdio_queue *req_q = &qdio->req_q; + +	spin_lock_bh(&qdio->req_q_lock); +	if (atomic_read(&req_q->count)) +		return 1; +	spin_unlock_bh(&qdio->req_q_lock); +	return 0; +} + +/** + * zfcp_qdio_sbal_get - get free sbal in request queue, wait if necessary + * @qdio: pointer to struct zfcp_qdio + * + * The req_q_lock must be held by the caller of this function, and + * this function may only be called from process context; it will + * sleep when waiting for a free sbal. + * + * Returns: 0 on success, -EIO if there is no free sbal after waiting. + */ +int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) +{ +	long ret; + +	spin_unlock_bh(&qdio->req_q_lock); +	ret = wait_event_interruptible_timeout(qdio->req_q_wq, +			       zfcp_qdio_sbal_check(qdio), 5 * HZ); +	if (ret > 0) +		return 0; +	if (!ret) { +		atomic_inc(&qdio->req_q_full); +		/* assume hanging outbound queue, try queue recovery */ +		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL); +	} + +	spin_lock_bh(&qdio->req_q_lock); +	return -EIO; +} +  /**   * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO   * @qdio: pointer to struct zfcp_qdio diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h index 8cca54631e1..138fba577b4 100644 --- a/drivers/s390/scsi/zfcp_qdio.h +++ b/drivers/s390/scsi/zfcp_qdio.h @@ -11,6 +11,14 @@  #include <asm/qdio.h> +#define ZFCP_QDIO_SBALE_LEN	PAGE_SIZE + +/* DMQ bug workaround: don't use last SBALE */ +#define ZFCP_QDIO_MAX_SBALES_PER_SBAL	(QDIO_MAX_ELEMENTS_PER_BUFFER - 1) + +/* index of last SBALE (with respect to DMQ bug workaround) */ +#define ZFCP_QDIO_LAST_SBALE_PER_SBAL	(ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1) +  /**   * struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count   * @sbal: qdio buffers @@ -49,6 +57,7 @@ struct zfcp_qdio {  /**   * struct zfcp_qdio_req - qdio queue related values for a request + * @sbtype: sbal type flags for sbale 0   * @sbal_number: number of free sbals   * @sbal_first: first sbal for this request   * @sbal_last: last sbal for this request @@ -59,6 +68,7 @@ struct zfcp_qdio {   * @qdio_inb_usage: usage of inbound queue   */  struct zfcp_qdio_req { +	u32	sbtype;  	u8	sbal_number;  	u8	sbal_first;  	u8	sbal_last; @@ -106,4 +116,98 @@ zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)  			       q_req->sbale_curr);  } +/** + * zfcp_qdio_req_init - initialize qdio request + * @qdio: request queue where to start putting the request + * @q_req: the qdio request to start + * @req_id: The request id + * @sbtype: type flags to set for all sbals + * @data: First data block + * @len: Length of first data block + * + * This is the start of putting the request into the queue, the last + * step is passing the request to zfcp_qdio_send. The request queue + * lock must be held during the whole process from init to send. + */ +static inline +void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, +			unsigned long req_id, u32 sbtype, void *data, u32 len) +{ +	struct qdio_buffer_element *sbale; + +	q_req->sbal_first = q_req->sbal_last = qdio->req_q.first; +	q_req->sbal_number = 1; +	q_req->sbtype = sbtype; + +	sbale = zfcp_qdio_sbale_req(qdio, q_req); +	sbale->addr = (void *) req_id; +	sbale->flags |= SBAL_FLAGS0_COMMAND; +	sbale->flags |= sbtype; + +	q_req->sbale_curr = 1; +	sbale++; +	sbale->addr = data; +	if (likely(data)) +		sbale->length = len; +} + +/** + * zfcp_qdio_fill_next - Fill next sbale, only for single sbal requests + * @qdio: pointer to struct zfcp_qdio + * @q_req: pointer to struct zfcp_queue_req + * + * This is only required for single sbal requests, calling it when + * wrapping around to the next sbal is a bug. + */ +static inline +void zfcp_qdio_fill_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, +			 void *data, u32 len) +{ +	struct qdio_buffer_element *sbale; + +	BUG_ON(q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL); +	q_req->sbale_curr++; +	sbale = zfcp_qdio_sbale_curr(qdio, q_req); +	sbale->addr = data; +	sbale->length = len; +} + +/** + * zfcp_qdio_set_sbale_last - set last entry flag in current sbale + * @qdio: pointer to struct zfcp_qdio + * @q_req: pointer to struct zfcp_queue_req + */ +static inline +void zfcp_qdio_set_sbale_last(struct zfcp_qdio *qdio, +			      struct zfcp_qdio_req *q_req) +{ +	struct qdio_buffer_element *sbale; + +	sbale = zfcp_qdio_sbale_curr(qdio, q_req); +	sbale->flags |= SBAL_FLAGS_LAST_ENTRY; +} + +/** + * zfcp_qdio_sg_one_sbal - check if one sbale is enough for sg data + * @sg: The scatterlist where to check the data size + * + * Returns: 1 when one sbale is enough for the data in the scatterlist, + *	    0 if not. + */ +static inline +int zfcp_qdio_sg_one_sbale(struct scatterlist *sg) +{ +	return sg_is_last(sg) && sg->length <= ZFCP_QDIO_SBALE_LEN; +} + +/** + * zfcp_qdio_skip_to_last_sbale - skip to last sbale in sbal + * @q_req: The current zfcp_qdio_req + */ +static inline +void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio_req *q_req) +{ +	q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL; +} +  #endif /* ZFCP_QDIO_H */ diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 174b6d57d57..be5d2c60453 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -175,7 +175,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)  	struct zfcp_fsf_req *old_req, *abrt_req;  	unsigned long flags;  	unsigned long old_reqid = (unsigned long) scpnt->host_scribble; -	int retval = SUCCESS; +	int retval = SUCCESS, ret;  	int retry = 3;  	char *dbf_tag; @@ -200,7 +200,9 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)  			break;  		zfcp_erp_wait(adapter); -		fc_block_scsi_eh(scpnt); +		ret = fc_block_scsi_eh(scpnt); +		if (ret) +			return ret;  		if (!(atomic_read(&adapter->status) &  		      ZFCP_STATUS_COMMON_RUNNING)) {  			zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL, @@ -231,7 +233,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)  	struct zfcp_unit *unit = scpnt->device->hostdata;  	struct zfcp_adapter *adapter = unit->port->adapter;  	struct zfcp_fsf_req *fsf_req = NULL; -	int retval = SUCCESS; +	int retval = SUCCESS, ret;  	int retry = 3;  	while (retry--) { @@ -240,7 +242,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)  			break;  		zfcp_erp_wait(adapter); -		fc_block_scsi_eh(scpnt); +		ret = fc_block_scsi_eh(scpnt); +		if (ret) +			return ret; +  		if (!(atomic_read(&adapter->status) &  		      ZFCP_STATUS_COMMON_RUNNING)) {  			zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt); @@ -276,10 +281,13 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)  {  	struct zfcp_unit *unit = scpnt->device->hostdata;  	struct zfcp_adapter *adapter = unit->port->adapter; +	int ret;  	zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);  	zfcp_erp_wait(adapter); -	fc_block_scsi_eh(scpnt); +	ret = fc_block_scsi_eh(scpnt); +	if (ret) +		return ret;  	return SUCCESS;  } @@ -669,11 +677,12 @@ struct zfcp_data zfcp_data = {  		.eh_host_reset_handler	 = zfcp_scsi_eh_host_reset_handler,  		.can_queue		 = 4096,  		.this_id		 = -1, -		.sg_tablesize		 = ZFCP_MAX_SBALES_PER_REQ, +		.sg_tablesize		 = ZFCP_FSF_MAX_SBALES_PER_REQ,  		.cmd_per_lun		 = 1,  		.use_clustering		 = 1,  		.sdev_attrs		 = zfcp_sysfs_sdev_attrs, -		.max_sectors		 = (ZFCP_MAX_SBALES_PER_REQ * 8), +		.max_sectors		 = (ZFCP_FSF_MAX_SBALES_PER_REQ * 8), +		.dma_boundary		 = ZFCP_QDIO_SBALE_LEN - 1,  		.shost_attrs		 = zfcp_sysfs_shost_attrs,  	},  }; diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index e9788f55ab1..1bb774becf2 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1,10 +1,11 @@  /*     3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux. -   Written By: Adam Radford <linuxraid@amcc.com> -   Modifications By: Tom Couch <linuxraid@amcc.com> +   Written By: Adam Radford <linuxraid@lsi.com> +   Modifications By: Tom Couch <linuxraid@lsi.com>     Copyright (C) 2004-2009 Applied Micro Circuits Corporation. +   Copyright (C) 2010 LSI Corporation.     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 @@ -40,10 +41,10 @@     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA     Bugs/Comments/Suggestions should be mailed to: -   linuxraid@amcc.com +   linuxraid@lsi.com     For more information, goto: -   http://www.amcc.com +   http://www.lsi.com     Note: This version of the driver does not contain a bundled firmware           image. @@ -77,6 +78,7 @@                   Use pci_resource_len() for ioremap().     2.26.02.012 - Add power management support.     2.26.02.013 - Fix bug in twa_load_sgl(). +   2.26.02.014 - Force 60 second timeout default.  */  #include <linux/module.h> @@ -102,14 +104,14 @@  #include "3w-9xxx.h"  /* Globals */ -#define TW_DRIVER_VERSION "2.26.02.013" +#define TW_DRIVER_VERSION "2.26.02.014"  static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];  static unsigned int twa_device_extension_count;  static int twa_major = -1;  extern struct timezone sys_tz;  /* Module parameters */ -MODULE_AUTHOR ("AMCC"); +MODULE_AUTHOR ("LSI");  MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");  MODULE_LICENSE("GPL");  MODULE_VERSION(TW_DRIVER_VERSION); @@ -1990,6 +1992,15 @@ static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)  		scsi_dma_unmap(cmd);  } /* End twa_unmap_scsi_data() */ +/* This function gets called when a disk is coming on-line */ +static int twa_slave_configure(struct scsi_device *sdev) +{ +	/* Force 60 second timeout */ +	blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); + +	return 0; +} /* End twa_slave_configure() */ +  /* scsi_host_template initializer */  static struct scsi_host_template driver_template = {  	.module			= THIS_MODULE, @@ -1999,6 +2010,7 @@ static struct scsi_host_template driver_template = {  	.bios_param		= twa_scsi_biosparam,  	.change_queue_depth	= twa_change_queue_depth,  	.can_queue		= TW_Q_LENGTH-2, +	.slave_configure	= twa_slave_configure,  	.this_id		= -1,  	.sg_tablesize		= TW_APACHE_MAX_SGL_LENGTH,  	.max_sectors		= TW_MAX_SECTORS, diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h index 2893eec78ed..3343824855d 100644 --- a/drivers/scsi/3w-9xxx.h +++ b/drivers/scsi/3w-9xxx.h @@ -1,10 +1,11 @@  /*     3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux. -   Written By: Adam Radford <linuxraid@amcc.com> -   Modifications By: Tom Couch <linuxraid@amcc.com> +   Written By: Adam Radford <linuxraid@lsi.com> +   Modifications By: Tom Couch <linuxraid@lsi.com>     Copyright (C) 2004-2009 Applied Micro Circuits Corporation. +   Copyright (C) 2010 LSI Corporation.     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 @@ -40,10 +41,10 @@     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA     Bugs/Comments/Suggestions should be mailed to: -   linuxraid@amcc.com +   linuxraid@lsi.com     For more information, goto: -   http://www.amcc.com +   http://www.lsi.com  */  #ifndef _3W_9XXX_H diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 5faf903ca8c..d119a614bf7 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1,12 +1,12 @@  /*      3w-xxxx.c -- 3ware Storage Controller device driver for Linux. -   Written By: Adam Radford <linuxraid@amcc.com> +   Written By: Adam Radford <linuxraid@lsi.com>     Modifications By: Joel Jacobson <linux@3ware.com>     		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>                       Brad Strand <linux@3ware.com> -   Copyright (C) 1999-2009 3ware Inc. +   Copyright (C) 1999-2010 3ware Inc.     Kernel compatibility By: 	Andre Hedrick <andre@suse.com>     Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com> @@ -47,10 +47,10 @@     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA      Bugs/Comments/Suggestions should be mailed to:                             -   linuxraid@amcc.com +   linuxraid@lsi.com     For more information, goto: -   http://www.amcc.com +   http://www.lsi.com     History     ------- @@ -194,6 +194,7 @@     1.26.02.002 - Free irq handler in __tw_shutdown().                   Turn on RCD bit for caching mode page.                   Serialize reset code. +   1.26.02.003 - Force 60 second timeout default.  */  #include <linux/module.h> @@ -219,13 +220,13 @@  #include "3w-xxxx.h"  /* Globals */ -#define TW_DRIVER_VERSION "1.26.02.002" +#define TW_DRIVER_VERSION "1.26.02.003"  static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];  static int tw_device_extension_count = 0;  static int twe_major = -1;  /* Module parameters */ -MODULE_AUTHOR("AMCC"); +MODULE_AUTHOR("LSI");  MODULE_DESCRIPTION("3ware Storage Controller Linux Driver");  MODULE_LICENSE("GPL");  MODULE_VERSION(TW_DRIVER_VERSION); @@ -2245,6 +2246,15 @@ static void tw_shutdown(struct pci_dev *pdev)  	__tw_shutdown(tw_dev);  } /* End tw_shutdown() */ +/* This function gets called when a disk is coming online */ +static int tw_slave_configure(struct scsi_device *sdev) +{ +	/* Force 60 second timeout */ +	blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); + +	return 0; +} /* End tw_slave_configure() */ +  static struct scsi_host_template driver_template = {  	.module			= THIS_MODULE,  	.name			= "3ware Storage Controller", @@ -2253,6 +2263,7 @@ static struct scsi_host_template driver_template = {  	.bios_param		= tw_scsi_biosparam,  	.change_queue_depth	= tw_change_queue_depth,  	.can_queue		= TW_Q_LENGTH-2, +	.slave_configure	= tw_slave_configure,  	.this_id		= -1,  	.sg_tablesize		= TW_MAX_SGL_LENGTH,  	.max_sectors		= TW_MAX_SECTORS, diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index a5a2ba2561d..8b9f9d17e7f 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -1,12 +1,12 @@  /*      3w-xxxx.h -- 3ware Storage Controller device driver for Linux. -   Written By: Adam Radford <linuxraid@amcc.com> +   Written By: Adam Radford <linuxraid@lsi.com>     Modifications By: Joel Jacobson <linux@3ware.com>     		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>                       Brad Strand <linux@3ware.com> -   Copyright (C) 1999-2009 3ware Inc. +   Copyright (C) 1999-2010 3ware Inc.     Kernel compatiblity By:	Andre Hedrick <andre@suse.com>     Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com> @@ -45,10 +45,10 @@     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA      Bugs/Comments/Suggestions should be mailed to:                             -   linuxraid@amcc.com +   linuxraid@lsi.com     For more information, goto: -   http://www.amcc.com +   http://www.lsi.com  */  #ifndef _3W_XXXX_H diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 92a8c500b23..1c7ac49be64 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -162,6 +162,7 @@ scsi_mod-y			+= scsi_scan.o scsi_sysfs.o scsi_devinfo.o  scsi_mod-$(CONFIG_SCSI_NETLINK)	+= scsi_netlink.o  scsi_mod-$(CONFIG_SYSCTL)	+= scsi_sysctl.o  scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o +scsi_mod-y			+= scsi_trace.o  scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_if.o diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index d8fe5b76fee..308541ff85c 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -19,186 +19,190 @@  #include "wd33c93.h"  #include "a2091.h" -#include<linux/stat.h> +#include <linux/stat.h> -#define DMA(ptr) ((a2091_scsiregs *)((ptr)->base)) -#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))  static int a2091_release(struct Scsi_Host *instance); -static irqreturn_t a2091_intr (int irq, void *_instance) +static irqreturn_t a2091_intr(int irq, void *data)  { -    unsigned long flags; -    unsigned int status; -    struct Scsi_Host *instance = (struct Scsi_Host *)_instance; +	struct Scsi_Host *instance = data; +	a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base); +	unsigned int status = regs->ISTR; +	unsigned long flags; -    status = DMA(instance)->ISTR; -    if (!(status & (ISTR_INT_F|ISTR_INT_P)) || !(status & ISTR_INTS)) -	return IRQ_NONE; +	if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS)) +		return IRQ_NONE; -    spin_lock_irqsave(instance->host_lock, flags); -    wd33c93_intr(instance); -    spin_unlock_irqrestore(instance->host_lock, flags); -    return IRQ_HANDLED; +	spin_lock_irqsave(instance->host_lock, flags); +	wd33c93_intr(instance); +	spin_unlock_irqrestore(instance->host_lock, flags); +	return IRQ_HANDLED;  }  static int dma_setup(struct scsi_cmnd *cmd, int dir_in)  { -    unsigned short cntr = CNTR_PDMD | CNTR_INTEN; -    unsigned long addr = virt_to_bus(cmd->SCp.ptr); -    struct Scsi_Host *instance = cmd->device->host; +	struct Scsi_Host *instance = cmd->device->host; +	struct WD33C93_hostdata *hdata = shost_priv(instance); +	a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base); +	unsigned short cntr = CNTR_PDMD | CNTR_INTEN; +	unsigned long addr = virt_to_bus(cmd->SCp.ptr); -    /* don't allow DMA if the physical address is bad */ -    if (addr & A2091_XFER_MASK) -    { -	HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511) -	    & ~0x1ff; -	HDATA(instance)->dma_bounce_buffer = -	    kmalloc (HDATA(instance)->dma_bounce_len, GFP_KERNEL); -	 -	/* can't allocate memory; use PIO */ -	if (!HDATA(instance)->dma_bounce_buffer) { -	    HDATA(instance)->dma_bounce_len = 0; -	    return 1; -	} +	/* don't allow DMA if the physical address is bad */ +	if (addr & A2091_XFER_MASK) { +		hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; +		hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len, +						   GFP_KERNEL); -	/* get the physical address of the bounce buffer */ -	addr = virt_to_bus(HDATA(instance)->dma_bounce_buffer); +		/* can't allocate memory; use PIO */ +		if (!hdata->dma_bounce_buffer) { +			hdata->dma_bounce_len = 0; +			return 1; +		} -	/* the bounce buffer may not be in the first 16M of physmem */ -	if (addr & A2091_XFER_MASK) { -	    /* we could use chipmem... maybe later */ -	    kfree (HDATA(instance)->dma_bounce_buffer); -	    HDATA(instance)->dma_bounce_buffer = NULL; -	    HDATA(instance)->dma_bounce_len = 0; -	    return 1; -	} +		/* get the physical address of the bounce buffer */ +		addr = virt_to_bus(hdata->dma_bounce_buffer); -	if (!dir_in) { -		/* copy to bounce buffer for a write */ -		memcpy (HDATA(instance)->dma_bounce_buffer, -			cmd->SCp.ptr, cmd->SCp.this_residual); +		/* the bounce buffer may not be in the first 16M of physmem */ +		if (addr & A2091_XFER_MASK) { +			/* we could use chipmem... maybe later */ +			kfree(hdata->dma_bounce_buffer); +			hdata->dma_bounce_buffer = NULL; +			hdata->dma_bounce_len = 0; +			return 1; +		} + +		if (!dir_in) { +			/* copy to bounce buffer for a write */ +			memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr, +			       cmd->SCp.this_residual); +		}  	} -    } -    /* setup dma direction */ -    if (!dir_in) -	cntr |= CNTR_DDIR; +	/* setup dma direction */ +	if (!dir_in) +		cntr |= CNTR_DDIR; -    /* remember direction */ -    HDATA(cmd->device->host)->dma_dir = dir_in; +	/* remember direction */ +	hdata->dma_dir = dir_in; -    DMA(cmd->device->host)->CNTR = cntr; +	regs->CNTR = cntr; -    /* setup DMA *physical* address */ -    DMA(cmd->device->host)->ACR = addr; +	/* setup DMA *physical* address */ +	regs->ACR = addr; -    if (dir_in){ -	/* invalidate any cache */ -	cache_clear (addr, cmd->SCp.this_residual); -    }else{ -	/* push any dirty cache */ -	cache_push (addr, cmd->SCp.this_residual); -      } -    /* start DMA */ -    DMA(cmd->device->host)->ST_DMA = 1; +	if (dir_in) { +		/* invalidate any cache */ +		cache_clear(addr, cmd->SCp.this_residual); +	} else { +		/* push any dirty cache */ +		cache_push(addr, cmd->SCp.this_residual); +	} +	/* start DMA */ +	regs->ST_DMA = 1; -    /* return success */ -    return 0; +	/* return success */ +	return 0;  }  static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, -		      int status) +		     int status)  { -    /* disable SCSI interrupts */ -    unsigned short cntr = CNTR_PDMD; +	struct WD33C93_hostdata *hdata = shost_priv(instance); +	a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base); -    if (!HDATA(instance)->dma_dir) -	    cntr |= CNTR_DDIR; +	/* disable SCSI interrupts */ +	unsigned short cntr = CNTR_PDMD; -    /* disable SCSI interrupts */ -    DMA(instance)->CNTR = cntr; +	if (!hdata->dma_dir) +		cntr |= CNTR_DDIR; -    /* flush if we were reading */ -    if (HDATA(instance)->dma_dir) { -	DMA(instance)->FLUSH = 1; -	while (!(DMA(instance)->ISTR & ISTR_FE_FLG)) -	    ; -    } +	/* disable SCSI interrupts */ +	regs->CNTR = cntr; -    /* clear a possible interrupt */ -    DMA(instance)->CINT = 1; +	/* flush if we were reading */ +	if (hdata->dma_dir) { +		regs->FLUSH = 1; +		while (!(regs->ISTR & ISTR_FE_FLG)) +			; +	} + +	/* clear a possible interrupt */ +	regs->CINT = 1; -    /* stop DMA */ -    DMA(instance)->SP_DMA = 1; +	/* stop DMA */ +	regs->SP_DMA = 1; -    /* restore the CONTROL bits (minus the direction flag) */ -    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; +	/* restore the CONTROL bits (minus the direction flag) */ +	regs->CNTR = CNTR_PDMD | CNTR_INTEN; -    /* copy from a bounce buffer, if necessary */ -    if (status && HDATA(instance)->dma_bounce_buffer) { -	if( HDATA(instance)->dma_dir ) -		memcpy (SCpnt->SCp.ptr,  -			HDATA(instance)->dma_bounce_buffer, -			SCpnt->SCp.this_residual); -	kfree (HDATA(instance)->dma_bounce_buffer); -	HDATA(instance)->dma_bounce_buffer = NULL; -	HDATA(instance)->dma_bounce_len = 0; -    } +	/* copy from a bounce buffer, if necessary */ +	if (status && hdata->dma_bounce_buffer) { +		if (hdata->dma_dir) +			memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer, +			       SCpnt->SCp.this_residual); +		kfree(hdata->dma_bounce_buffer); +		hdata->dma_bounce_buffer = NULL; +		hdata->dma_bounce_len = 0; +	}  }  static int __init a2091_detect(struct scsi_host_template *tpnt)  { -    static unsigned char called = 0; -    struct Scsi_Host *instance; -    unsigned long address; -    struct zorro_dev *z = NULL; -    wd33c93_regs regs; -    int num_a2091 = 0; +	static unsigned char called = 0; +	struct Scsi_Host *instance; +	unsigned long address; +	struct zorro_dev *z = NULL; +	wd33c93_regs wdregs; +	a2091_scsiregs *regs; +	struct WD33C93_hostdata *hdata; +	int num_a2091 = 0; -    if (!MACH_IS_AMIGA || called) -	return 0; -    called = 1; +	if (!MACH_IS_AMIGA || called) +		return 0; +	called = 1; -    tpnt->proc_name = "A2091"; -    tpnt->proc_info = &wd33c93_proc_info; +	tpnt->proc_name = "A2091"; +	tpnt->proc_info = &wd33c93_proc_info; -    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { -	if (z->id != ZORRO_PROD_CBM_A590_A2091_1 && -	    z->id != ZORRO_PROD_CBM_A590_A2091_2) -	    continue; -	address = z->resource.start; -	if (!request_mem_region(address, 256, "wd33c93")) -	    continue; +	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { +		if (z->id != ZORRO_PROD_CBM_A590_A2091_1 && +		    z->id != ZORRO_PROD_CBM_A590_A2091_2) +			continue; +		address = z->resource.start; +		if (!request_mem_region(address, 256, "wd33c93")) +			continue; -	instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata)); -	if (instance == NULL) -	    goto release; -	instance->base = ZTWO_VADDR(address); -	instance->irq = IRQ_AMIGA_PORTS; -	instance->unique_id = z->slotaddr; -	DMA(instance)->DAWR = DAWR_A2091; -	regs.SASR = &(DMA(instance)->SASR); -	regs.SCMD = &(DMA(instance)->SCMD); -	HDATA(instance)->no_sync = 0xff; -	HDATA(instance)->fast = 0; -	HDATA(instance)->dma_mode = CTRL_DMA; -	wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10); -	if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI", -			instance)) -	    goto unregister; -	DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; -	num_a2091++; -	continue; +		instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata)); +		if (instance == NULL) +			goto release; +		instance->base = ZTWO_VADDR(address); +		instance->irq = IRQ_AMIGA_PORTS; +		instance->unique_id = z->slotaddr; +		regs = (a2091_scsiregs *)(instance->base); +		regs->DAWR = DAWR_A2091; +		wdregs.SASR = ®s->SASR; +		wdregs.SCMD = ®s->SCMD; +		hdata = shost_priv(instance); +		hdata->no_sync = 0xff; +		hdata->fast = 0; +		hdata->dma_mode = CTRL_DMA; +		wd33c93_init(instance, wdregs, dma_setup, dma_stop, +			     WD33C93_FS_8_10); +		if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, +				"A2091 SCSI", instance)) +			goto unregister; +		regs->CNTR = CNTR_PDMD | CNTR_INTEN; +		num_a2091++; +		continue;  unregister: -	scsi_unregister(instance); -	wd33c93_release(); +		scsi_unregister(instance);  release: -	release_mem_region(address, 256); -    } +		release_mem_region(address, 256); +	} -    return num_a2091; +	return num_a2091;  }  static int a2091_bus_reset(struct scsi_cmnd *cmd) @@ -239,10 +243,11 @@ static struct scsi_host_template driver_template = {  static int a2091_release(struct Scsi_Host *instance)  {  #ifdef MODULE -	DMA(instance)->CNTR = 0; +	a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base); + +	regs->CNTR = 0;  	release_mem_region(ZTWO_PADDR(instance->base), 256);  	free_irq(IRQ_AMIGA_PORTS, instance); -	wd33c93_release();  #endif  	return 1;  } diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h index 252528f2672..1c3daa1fd75 100644 --- a/drivers/scsi/a2091.h +++ b/drivers/scsi/a2091.h @@ -12,38 +12,38 @@  #include <linux/types.h>  #ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 +#define CMD_PER_LUN		2  #endif  #ifndef CAN_QUEUE -#define CAN_QUEUE 16 +#define CAN_QUEUE		16  #endif  /*   * if the transfer address ANDed with this results in a non-zero   * result, then we can't use DMA.   */ -#define A2091_XFER_MASK  (0xff000001) +#define A2091_XFER_MASK		(0xff000001)  typedef struct { -             unsigned char      pad1[64]; -    volatile unsigned short     ISTR; -    volatile unsigned short     CNTR; -             unsigned char      pad2[60]; -    volatile unsigned int       WTC; -    volatile unsigned long      ACR; -             unsigned char      pad3[6]; -    volatile unsigned short     DAWR; -             unsigned char      pad4; -    volatile unsigned char      SASR; -             unsigned char      pad5; -    volatile unsigned char      SCMD; -             unsigned char      pad6[76]; -    volatile unsigned short     ST_DMA; -    volatile unsigned short     SP_DMA; -    volatile unsigned short     CINT; -             unsigned char      pad7[2]; -    volatile unsigned short     FLUSH; +		 unsigned char	pad1[64]; +	volatile unsigned short	ISTR; +	volatile unsigned short	CNTR; +		 unsigned char	pad2[60]; +	volatile unsigned int	WTC; +	volatile unsigned long	ACR; +		 unsigned char	pad3[6]; +	volatile unsigned short	DAWR; +		 unsigned char	pad4; +	volatile unsigned char	SASR; +		 unsigned char	pad5; +	volatile unsigned char	SCMD; +		 unsigned char	pad6[76]; +	volatile unsigned short	ST_DMA; +	volatile unsigned short	SP_DMA; +	volatile unsigned short	CINT; +		 unsigned char	pad7[2]; +	volatile unsigned short	FLUSH;  } a2091_scsiregs;  #define DAWR_A2091		(3) diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index c35fc55f1c9..bc6eb69f5fd 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -19,26 +19,25 @@  #include "wd33c93.h"  #include "a3000.h" -#include<linux/stat.h> +#include <linux/stat.h> -#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base)) -#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) + +#define DMA(ptr)	((a3000_scsiregs *)((ptr)->base))  static struct Scsi_Host *a3000_host = NULL;  static int a3000_release(struct Scsi_Host *instance); -static irqreturn_t a3000_intr (int irq, void *dummy) +static irqreturn_t a3000_intr(int irq, void *dummy)  {  	unsigned long flags;  	unsigned int status = DMA(a3000_host)->ISTR;  	if (!(status & ISTR_INT_P))  		return IRQ_NONE; -	if (status & ISTR_INTS) -	{ +	if (status & ISTR_INTS) {  		spin_lock_irqsave(a3000_host->host_lock, flags); -		wd33c93_intr (a3000_host); +		wd33c93_intr(a3000_host);  		spin_unlock_irqrestore(a3000_host->host_lock, flags);  		return IRQ_HANDLED;  	} @@ -48,162 +47,165 @@ static irqreturn_t a3000_intr (int irq, void *dummy)  static int dma_setup(struct scsi_cmnd *cmd, int dir_in)  { -    unsigned short cntr = CNTR_PDMD | CNTR_INTEN; -    unsigned long addr = virt_to_bus(cmd->SCp.ptr); +	struct WD33C93_hostdata *hdata = shost_priv(a3000_host); +	unsigned short cntr = CNTR_PDMD | CNTR_INTEN; +	unsigned long addr = virt_to_bus(cmd->SCp.ptr); -    /* -     * if the physical address has the wrong alignment, or if -     * physical address is bad, or if it is a write and at the -     * end of a physical memory chunk, then allocate a bounce -     * buffer -     */ -    if (addr & A3000_XFER_MASK) -    { -	HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511) -	    & ~0x1ff; -	HDATA(a3000_host)->dma_bounce_buffer = -	    kmalloc (HDATA(a3000_host)->dma_bounce_len, GFP_KERNEL); -	 -	/* can't allocate memory; use PIO */ -	if (!HDATA(a3000_host)->dma_bounce_buffer) { -	    HDATA(a3000_host)->dma_bounce_len = 0; -	    return 1; -	} +	/* +	 * if the physical address has the wrong alignment, or if +	 * physical address is bad, or if it is a write and at the +	 * end of a physical memory chunk, then allocate a bounce +	 * buffer +	 */ +	if (addr & A3000_XFER_MASK) { +		hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; +		hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len, +						   GFP_KERNEL); -	if (!dir_in) { -	    /* copy to bounce buffer for a write */ -	    memcpy (HDATA(a3000_host)->dma_bounce_buffer, -		cmd->SCp.ptr, cmd->SCp.this_residual); -	} +		/* can't allocate memory; use PIO */ +		if (!hdata->dma_bounce_buffer) { +			hdata->dma_bounce_len = 0; +			return 1; +		} + +		if (!dir_in) { +			/* copy to bounce buffer for a write */ +			memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr, +			       cmd->SCp.this_residual); +		} -	addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer); -    } +		addr = virt_to_bus(hdata->dma_bounce_buffer); +	} -    /* setup dma direction */ -    if (!dir_in) -	cntr |= CNTR_DDIR; +	/* setup dma direction */ +	if (!dir_in) +		cntr |= CNTR_DDIR; -    /* remember direction */ -    HDATA(a3000_host)->dma_dir = dir_in; +	/* remember direction */ +	hdata->dma_dir = dir_in; -    DMA(a3000_host)->CNTR = cntr; +	DMA(a3000_host)->CNTR = cntr; -    /* setup DMA *physical* address */ -    DMA(a3000_host)->ACR = addr; +	/* setup DMA *physical* address */ +	DMA(a3000_host)->ACR = addr; -    if (dir_in) -  	/* invalidate any cache */ -	cache_clear (addr, cmd->SCp.this_residual); -    else -	/* push any dirty cache */ -	cache_push (addr, cmd->SCp.this_residual); +	if (dir_in) { +		/* invalidate any cache */ +		cache_clear(addr, cmd->SCp.this_residual); +	} else { +		/* push any dirty cache */ +		cache_push(addr, cmd->SCp.this_residual); +	} -    /* start DMA */ -    mb();			/* make sure setup is completed */ -    DMA(a3000_host)->ST_DMA = 1; -    mb();			/* make sure DMA has started before next IO */ +	/* start DMA */ +	mb();			/* make sure setup is completed */ +	DMA(a3000_host)->ST_DMA = 1; +	mb();			/* make sure DMA has started before next IO */ -    /* return success */ -    return 0; +	/* return success */ +	return 0;  }  static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,  		     int status)  { -    /* disable SCSI interrupts */ -    unsigned short cntr = CNTR_PDMD; +	struct WD33C93_hostdata *hdata = shost_priv(instance); -    if (!HDATA(instance)->dma_dir) -	cntr |= CNTR_DDIR; +	/* disable SCSI interrupts */ +	unsigned short cntr = CNTR_PDMD; -    DMA(instance)->CNTR = cntr; -    mb();			/* make sure CNTR is updated before next IO */ +	if (!hdata->dma_dir) +		cntr |= CNTR_DDIR; -    /* flush if we were reading */ -    if (HDATA(instance)->dma_dir) { -	DMA(instance)->FLUSH = 1; -	mb();			/* don't allow prefetch */ -	while (!(DMA(instance)->ISTR & ISTR_FE_FLG)) -	    barrier(); -	mb();			/* no IO until FLUSH is done */ -    } +	DMA(instance)->CNTR = cntr; +	mb();			/* make sure CNTR is updated before next IO */ -    /* clear a possible interrupt */ -    /* I think that this CINT is only necessary if you are -     * using the terminal count features.   HM 7 Mar 1994 -     */ -    DMA(instance)->CINT = 1; +	/* flush if we were reading */ +	if (hdata->dma_dir) { +		DMA(instance)->FLUSH = 1; +		mb();		/* don't allow prefetch */ +		while (!(DMA(instance)->ISTR & ISTR_FE_FLG)) +			barrier(); +		mb();		/* no IO until FLUSH is done */ +	} -    /* stop DMA */ -    DMA(instance)->SP_DMA = 1; -    mb();			/* make sure DMA is stopped before next IO */ +	/* clear a possible interrupt */ +	/* I think that this CINT is only necessary if you are +	 * using the terminal count features.   HM 7 Mar 1994 +	 */ +	DMA(instance)->CINT = 1; -    /* restore the CONTROL bits (minus the direction flag) */ -    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; -    mb();			/* make sure CNTR is updated before next IO */ +	/* stop DMA */ +	DMA(instance)->SP_DMA = 1; +	mb();			/* make sure DMA is stopped before next IO */ -    /* copy from a bounce buffer, if necessary */ -    if (status && HDATA(instance)->dma_bounce_buffer) { -	if (SCpnt) { -	    if (HDATA(instance)->dma_dir && SCpnt) -		memcpy (SCpnt->SCp.ptr, -			HDATA(instance)->dma_bounce_buffer, -			SCpnt->SCp.this_residual); -	    kfree (HDATA(instance)->dma_bounce_buffer); -	    HDATA(instance)->dma_bounce_buffer = NULL; -	    HDATA(instance)->dma_bounce_len = 0; -	} else { -	    kfree (HDATA(instance)->dma_bounce_buffer); -	    HDATA(instance)->dma_bounce_buffer = NULL; -	    HDATA(instance)->dma_bounce_len = 0; +	/* restore the CONTROL bits (minus the direction flag) */ +	DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; +	mb();			/* make sure CNTR is updated before next IO */ + +	/* copy from a bounce buffer, if necessary */ +	if (status && hdata->dma_bounce_buffer) { +		if (SCpnt) { +			if (hdata->dma_dir && SCpnt) +				memcpy(SCpnt->SCp.ptr, +				       hdata->dma_bounce_buffer, +				       SCpnt->SCp.this_residual); +			kfree(hdata->dma_bounce_buffer); +			hdata->dma_bounce_buffer = NULL; +			hdata->dma_bounce_len = 0; +		} else { +			kfree(hdata->dma_bounce_buffer); +			hdata->dma_bounce_buffer = NULL; +			hdata->dma_bounce_len = 0; +		}  	} -    }  }  static int __init a3000_detect(struct scsi_host_template *tpnt)  { -    wd33c93_regs regs; +	wd33c93_regs regs; +	struct WD33C93_hostdata *hdata; -    if  (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI)) -	return 0; -    if (!request_mem_region(0xDD0000, 256, "wd33c93")) -	return 0; +	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI)) +		return 0; +	if (!request_mem_region(0xDD0000, 256, "wd33c93")) +		return 0; -    tpnt->proc_name = "A3000"; -    tpnt->proc_info = &wd33c93_proc_info; +	tpnt->proc_name = "A3000"; +	tpnt->proc_info = &wd33c93_proc_info; -    a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata)); -    if (a3000_host == NULL) -	goto fail_register; +	a3000_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata)); +	if (a3000_host == NULL) +		goto fail_register; -    a3000_host->base = ZTWO_VADDR(0xDD0000); -    a3000_host->irq = IRQ_AMIGA_PORTS; -    DMA(a3000_host)->DAWR = DAWR_A3000; -    regs.SASR = &(DMA(a3000_host)->SASR); -    regs.SCMD = &(DMA(a3000_host)->SCMD); -    HDATA(a3000_host)->no_sync = 0xff; -    HDATA(a3000_host)->fast = 0; -    HDATA(a3000_host)->dma_mode = CTRL_DMA; -    wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15); -    if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI", -		    a3000_intr)) -        goto fail_irq; -    DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN; +	a3000_host->base = ZTWO_VADDR(0xDD0000); +	a3000_host->irq = IRQ_AMIGA_PORTS; +	DMA(a3000_host)->DAWR = DAWR_A3000; +	regs.SASR = &(DMA(a3000_host)->SASR); +	regs.SCMD = &(DMA(a3000_host)->SCMD); +	hdata = shost_priv(a3000_host); +	hdata->no_sync = 0xff; +	hdata->fast = 0; +	hdata->dma_mode = CTRL_DMA; +	wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15); +	if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI", +			a3000_intr)) +		goto fail_irq; +	DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN; -    return 1; +	return 1;  fail_irq: -    wd33c93_release(); -    scsi_unregister(a3000_host); +	scsi_unregister(a3000_host);  fail_register: -    release_mem_region(0xDD0000, 256); -    return 0; +	release_mem_region(0xDD0000, 256); +	return 0;  }  static int a3000_bus_reset(struct scsi_cmnd *cmd)  {  	/* FIXME perform bus-specific reset */ -	 +  	/* FIXME 2: kill this entire function, which should  	   cause mid-layer to call wd33c93_host_reset anyway? */ @@ -237,11 +239,10 @@ static struct scsi_host_template driver_template = {  static int a3000_release(struct Scsi_Host *instance)  { -    wd33c93_release(); -    DMA(instance)->CNTR = 0; -    release_mem_region(0xDD0000, 256); -    free_irq(IRQ_AMIGA_PORTS, a3000_intr); -    return 1; +	DMA(instance)->CNTR = 0; +	release_mem_region(0xDD0000, 256); +	free_irq(IRQ_AMIGA_PORTS, a3000_intr); +	return 1;  }  MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h index c7afe16fd6e..684813ee378 100644 --- a/drivers/scsi/a3000.h +++ b/drivers/scsi/a3000.h @@ -12,40 +12,40 @@  #include <linux/types.h>  #ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 +#define CMD_PER_LUN		2  #endif  #ifndef CAN_QUEUE -#define CAN_QUEUE 16 +#define CAN_QUEUE		16  #endif  /*   * if the transfer address ANDed with this results in a non-zero   * result, then we can't use DMA.   */ -#define A3000_XFER_MASK  (0x00000003) +#define A3000_XFER_MASK		(0x00000003)  typedef struct { -             unsigned char      pad1[2]; -    volatile unsigned short     DAWR; -    volatile unsigned int       WTC; -             unsigned char      pad2[2]; -    volatile unsigned short     CNTR; -    volatile unsigned long      ACR; -             unsigned char      pad3[2]; -    volatile unsigned short     ST_DMA; -             unsigned char      pad4[2]; -    volatile unsigned short     FLUSH; -             unsigned char      pad5[2]; -    volatile unsigned short     CINT; -             unsigned char      pad6[2]; -    volatile unsigned short     ISTR; -	     unsigned char      pad7[30]; -    volatile unsigned short     SP_DMA; -             unsigned char      pad8; -    volatile unsigned char      SASR; -             unsigned char      pad9; -    volatile unsigned char      SCMD; +		 unsigned char	pad1[2]; +	volatile unsigned short	DAWR; +	volatile unsigned int	WTC; +		 unsigned char	pad2[2]; +	volatile unsigned short	CNTR; +	volatile unsigned long	ACR; +		 unsigned char	pad3[2]; +	volatile unsigned short	ST_DMA; +		 unsigned char	pad4[2]; +	volatile unsigned short	FLUSH; +		 unsigned char	pad5[2]; +	volatile unsigned short	CINT; +		 unsigned char	pad6[2]; +	volatile unsigned short	ISTR; +		 unsigned char	pad7[30]; +	volatile unsigned short	SP_DMA; +		 unsigned char	pad8; +	volatile unsigned char	SASR; +		 unsigned char	pad9; +	volatile unsigned char	SCMD;  } a3000_scsiregs;  #define DAWR_A3000		(3) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 7e26ebc2666..7df2dd1d2c6 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -328,6 +328,16 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)  	return status;  } +static void aac_expose_phy_device(struct scsi_cmnd *scsicmd) +{ +	char inq_data; +	scsi_sg_copy_to_buffer(scsicmd,  &inq_data, sizeof(inq_data)); +	if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) { +		inq_data &= 0xdf; +		scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); +	} +} +  /**   *	aac_get_containers	-	list containers   *	@common: adapter to probe @@ -1598,6 +1608,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)  	int status;  	struct aac_dev *dev;  	struct fib * cmd_fibcontext; +	int cid;  	dev = (struct aac_dev *)scsicmd->device->host->hostdata;  	/* @@ -1647,6 +1658,22 @@ static int aac_read(struct scsi_cmnd * scsicmd)  		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];  		break;  	} + +	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) { +		cid = scmd_id(scsicmd); +		dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); +		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | +			SAM_STAT_CHECK_CONDITION; +		set_sense(&dev->fsa_dev[cid].sense_data, +			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, +			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); +		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, +		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), +			     SCSI_SENSE_BUFFERSIZE)); +		scsicmd->scsi_done(scsicmd); +		return 1; +	} +  	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",  	  smp_processor_id(), (unsigned long long)lba, jiffies));  	if (aac_adapter_bounds(dev,scsicmd,lba)) @@ -1688,6 +1715,7 @@ static int aac_write(struct scsi_cmnd * scsicmd)  	int status;  	struct aac_dev *dev;  	struct fib * cmd_fibcontext; +	int cid;  	dev = (struct aac_dev *)scsicmd->device->host->hostdata;  	/* @@ -1727,6 +1755,22 @@ static int aac_write(struct scsi_cmnd * scsicmd)  		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];  		fua = scsicmd->cmnd[1] & 0x8;  	} + +	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) { +		cid = scmd_id(scsicmd); +		dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); +		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | +			SAM_STAT_CHECK_CONDITION; +		set_sense(&dev->fsa_dev[cid].sense_data, +			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, +			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); +		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, +		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), +			     SCSI_SENSE_BUFFERSIZE)); +		scsicmd->scsi_done(scsicmd); +		return 1; +	} +  	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",  	  smp_processor_id(), (unsigned long long)lba, jiffies));  	if (aac_adapter_bounds(dev,scsicmd,lba)) @@ -2573,6 +2617,11 @@ static void aac_srb_callback(void *context, struct fib * fibptr)  	scsi_dma_unmap(scsicmd); +	/* expose physical device if expose_physicald flag is on */ +	if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) +	  && expose_physicals > 0) +		aac_expose_phy_device(scsicmd); +  	/*  	 * First check the fib status  	 */ @@ -2678,8 +2727,22 @@ static void aac_srb_callback(void *context, struct fib * fibptr)  			scsicmd->cmnd[0],  			le32_to_cpu(srbreply->scsi_status));  #endif -		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; -		break; +		if ((scsicmd->cmnd[0] == ATA_12) +		  || (scsicmd->cmnd[0] == ATA_16)) { +			if (scsicmd->cmnd[2] & (0x01 << 5)) { +				scsicmd->result = DID_OK << 16 +						| COMMAND_COMPLETE << 8; +				break; +			} else { +				scsicmd->result = DID_ERROR << 16 +						| COMMAND_COMPLETE << 8; +				break; +			} +		} else { +			scsicmd->result = DID_ERROR << 16 +					| COMMAND_COMPLETE << 8; +			break; +		}  	}  	if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {  		int len; diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 619c02d9c86..4dbcc055ac7 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -12,7 +12,7 @@   *----------------------------------------------------------------------------*/  #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 24702 +# define AAC_DRIVER_BUILD 26400  # define AAC_DRIVER_BRANCH "-ms"  #endif  #define MAXIMUM_NUM_CONTAINERS	32 @@ -26,6 +26,8 @@  #define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff)  #define AAC_MAX_32BIT_SGBCOUNT	((unsigned short)256) +#define AAC_DEBUG_INSTRUMENT_AIF_DELETE +  /*   * These macros convert from physical channels to virtual channels   */ diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 94d2954d79a..70079146e20 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -966,6 +966,16 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)  			device_config_needed =  			  (((__le32 *)aifcmd->data)[0] ==  			    cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE; +			if (device_config_needed == ADD) { +				device = scsi_device_lookup(dev->scsi_host_ptr, +					channel, +					id, +					lun); +				if (device) { +					scsi_remove_device(device); +					scsi_device_put(device); +				} +			}  			break;  		case AifEnEnclosureManagement: @@ -1123,6 +1133,9 @@ retry_next:  	if (device) {  		switch (device_config_needed) {  		case DELETE: +#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE)) +			scsi_remove_device(device); +#else  			if (scsi_device_online(device)) {  				scsi_device_set_state(device, SDEV_OFFLINE);  				sdev_printk(KERN_INFO, device, @@ -1131,6 +1144,7 @@ retry_next:  						"array deleted" :  						"enclosure services event");  			} +#endif  			break;  		case ADD:  			if (!scsi_device_online(device)) { @@ -1145,12 +1159,16 @@ retry_next:  		case CHANGE:  			if ((channel == CONTAINER_CHANNEL)  			 && (!dev->fsa_dev[container].valid)) { +#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE)) +				scsi_remove_device(device); +#else  				if (!scsi_device_online(device))  					break;  				scsi_device_set_state(device, SDEV_OFFLINE);  				sdev_printk(KERN_INFO, device,  					"Device offlined - %s\n",  					"array failed"); +#endif  				break;  			}  			scsi_rescan_device(&device->sdev_gendev); diff --git a/drivers/scsi/bfa/bfa_cb_ioim_macros.h b/drivers/scsi/bfa/bfa_cb_ioim_macros.h index 961fe439daa..53a616f5f50 100644 --- a/drivers/scsi/bfa/bfa_cb_ioim_macros.h +++ b/drivers/scsi/bfa/bfa_cb_ioim_macros.h @@ -117,35 +117,6 @@ bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio)  }  /** - * Get SG element for the I/O request given the SG element index - */ -static inline union bfi_addr_u -bfa_cb_ioim_get_sgaddr(struct bfad_ioim_s *dio, int sgeid) -{ -	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; -	struct scatterlist *sge; -	u64        addr; - -	sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid; -	addr = (u64) sg_dma_address(sge); - -	return *((union bfi_addr_u *) &addr); -} - -static inline u32 -bfa_cb_ioim_get_sglen(struct bfad_ioim_s *dio, int sgeid) -{ -	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; -	struct scatterlist *sge; -	u32        len; - -	sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid; -	len = sg_dma_len(sge); - -	return len; -} - -/**   * Get Command Reference Number for the I/O request. 0 if none.   */  static inline u8 diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c index 5b107abe46e..687f3d6e252 100644 --- a/drivers/scsi/bfa/bfa_ioim.c +++ b/drivers/scsi/bfa/bfa_ioim.c @@ -731,6 +731,9 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)  	static struct fcp_cmnd_s cmnd_z0 = { 0 };  	struct bfi_sge_s      *sge;  	u32        pgdlen = 0; +	u64 addr; +	struct scatterlist *sg; +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;  	/**  	 * check for room in queue to send request now @@ -754,8 +757,10 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)  	 */  	sge = &m->sges[0];  	if (ioim->nsges) { -		sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, 0); -		pgdlen = bfa_cb_ioim_get_sglen(ioim->dio, 0); +		sg = (struct scatterlist *)scsi_sglist(cmnd); +		addr = bfa_os_sgaddr(sg_dma_address(sg)); +		sge->sga = *(union bfi_addr_u *) &addr; +		pgdlen = sg_dma_len(sg);  		sge->sg_len = pgdlen;  		sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?  					BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST; @@ -868,10 +873,16 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)  	struct bfi_sge_s      *sge;  	struct bfa_sgpg_s *sgpg;  	u32        pgcumsz; +	u64        addr; +	struct scatterlist *sg; +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;  	sgeid = BFI_SGE_INLINE;  	ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q); +	sg = scsi_sglist(cmnd); +	sg = sg_next(sg); +  	do {  		sge = sgpg->sgpg->sges;  		nsges = ioim->nsges - sgeid; @@ -879,9 +890,10 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)  			nsges = BFI_SGPG_DATA_SGES;  		pgcumsz = 0; -		for (i = 0; i < nsges; i++, sge++, sgeid++) { -			sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, sgeid); -			sge->sg_len = bfa_cb_ioim_get_sglen(ioim->dio, sgeid); +		for (i = 0; i < nsges; i++, sge++, sgeid++, sg = sg_next(sg)) { +			addr = bfa_os_sgaddr(sg_dma_address(sg)); +			sge->sga = *(union bfi_addr_u *) &addr; +			sge->sg_len = sg_dma_len(sg);  			pgcumsz += sge->sg_len;  			/** diff --git a/drivers/scsi/bfa/bfa_os_inc.h b/drivers/scsi/bfa/bfa_os_inc.h index 10a89f75fa9..bd1cd3ee302 100644 --- a/drivers/scsi/bfa/bfa_os_inc.h +++ b/drivers/scsi/bfa/bfa_os_inc.h @@ -50,6 +50,10 @@  #include <scsi/scsi_transport_fc.h>  #include <scsi/scsi_transport.h> +#ifdef __BIG_ENDIAN +#define __BIGENDIAN +#endif +  #define BFA_ERR			KERN_ERR  #define BFA_WARNING		KERN_WARNING  #define BFA_NOTICE		KERN_NOTICE @@ -123,6 +127,15 @@ int bfa_os_MWB(void *);  	(((_x) & 0x00ff0000) >> 8)	|	\  	(((_x) & 0xff000000) >> 24)) +#define bfa_os_swap_sgaddr(_x)	((u64)(					\ +	(((u64)(_x) & (u64)0x00000000000000ffull) << 32)	|	\ +	(((u64)(_x) & (u64)0x000000000000ff00ull) << 32)	|	\ +	(((u64)(_x) & (u64)0x0000000000ff0000ull) << 32)	|	\ +	(((u64)(_x) & (u64)0x00000000ff000000ull) << 32)	|	\ +	(((u64)(_x) & (u64)0x000000ff00000000ull) >> 32)	|	\ +	(((u64)(_x) & (u64)0x0000ff0000000000ull) >> 32)	|	\ +	(((u64)(_x) & (u64)0x00ff000000000000ull) >> 32)	|	\ +	(((u64)(_x) & (u64)0xff00000000000000ull) >> 32)))  #ifndef __BIGENDIAN  #define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \ @@ -133,6 +146,7 @@ int bfa_os_MWB(void *);  #define bfa_os_hton3b(_x)	bfa_swap_3b(_x)  #define bfa_os_wtole(_x)   (_x) +#define bfa_os_sgaddr(_x)  (_x)  #else @@ -141,6 +155,7 @@ int bfa_os_MWB(void *);  #define bfa_os_hton3b(_x)  (_x)  #define bfa_os_htonll(_x)  (_x)  #define bfa_os_wtole(_x)   bfa_os_swap32(_x) +#define bfa_os_sgaddr(_x)  bfa_os_swap_sgaddr(_x)  #endif @@ -161,12 +176,12 @@ int bfa_os_MWB(void *);  #define bfa_os_addr_t char __iomem *  #define bfa_os_panic() -#define bfa_os_reg_read(_raddr) bfa_os_wtole(readl(_raddr)) -#define bfa_os_reg_write(_raddr, _val) writel(bfa_os_wtole((_val)), (_raddr)) +#define bfa_os_reg_read(_raddr) readl(_raddr) +#define bfa_os_reg_write(_raddr, _val) writel((_val), (_raddr))  #define bfa_os_mem_read(_raddr, _off)                                   \ -	bfa_os_ntohl(readl(((_raddr) + (_off)))) +	bfa_os_swap32(readl(((_raddr) + (_off))))  #define bfa_os_mem_write(_raddr, _off, _val)                            \ -	writel(bfa_os_htonl((_val)), ((_raddr) + (_off))) +	writel(bfa_os_swap32((_val)), ((_raddr) + (_off)))  #define BFA_TRC_TS(_trcm)						\  			({						\ diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 13f5feb308c..d4fc4287ebd 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -33,7 +33,7 @@  #include <fcb/bfa_fcb.h>  BFA_TRC_FILE(LDRV, BFAD); -static DEFINE_MUTEX(bfad_mutex); +DEFINE_MUTEX(bfad_mutex);  LIST_HEAD(bfad_list);  static int      bfad_inst;  int bfad_supported_fc4s; @@ -299,8 +299,6 @@ bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv)  		complete(vport_drv->comp_del);  		return;  	} - -	kfree(vport_drv);  }  /** @@ -483,7 +481,7 @@ ext:   */  bfa_status_t  bfad_vport_create(struct bfad_s *bfad, u16 vf_id, -		  struct bfa_port_cfg_s *port_cfg) +		  struct bfa_port_cfg_s *port_cfg, struct device *dev)  {  	struct bfad_vport_s *vport;  	int             rc = BFA_STATUS_OK; @@ -506,7 +504,8 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id,  		goto ext_free_vport;  	if (port_cfg->roles & BFA_PORT_ROLE_FCP_IM) { -		rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port); +		rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port, +							dev);  		if (rc != BFA_STATUS_OK)  			goto ext_free_fcs_vport;  	} @@ -591,7 +590,6 @@ bfad_init_timer(struct bfad_s *bfad)  int  bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)  { -	unsigned long   bar0_len;  	int             rc = -ENODEV;  	if (pci_enable_device(pdev)) { @@ -611,9 +609,7 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)  			goto out_release_region;  		} -	bfad->pci_bar0_map = pci_resource_start(pdev, 0); -	bar0_len = pci_resource_len(pdev, 0); -	bfad->pci_bar0_kva = ioremap(bfad->pci_bar0_map, bar0_len); +	bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));  	if (bfad->pci_bar0_kva == NULL) {  		BFA_PRINTF(BFA_ERR, "Fail to map bar0\n"); @@ -646,11 +642,7 @@ out:  void  bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad)  { -#if defined(__ia64__)  	pci_iounmap(pdev, bfad->pci_bar0_kva); -#else -	iounmap(bfad->pci_bar0_kva); -#endif  	pci_release_regions(pdev);  	pci_disable_device(pdev);  	pci_set_drvdata(pdev, NULL); @@ -848,7 +840,8 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role)  			goto out;  		} -		rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port); +		rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port, +						&bfad->pcidev->dev);  		if (rc != BFA_STATUS_OK)  			goto out; diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index 6a2efdd5ef2..e477bfbfa7d 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -364,6 +364,152 @@ bfad_im_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)  } +static int +bfad_im_vport_create(struct fc_vport *fc_vport, bool disable) +{ +	char *vname = fc_vport->symbolic_name; +	struct Scsi_Host *shost = fc_vport->shost; +	struct bfad_im_port_s *im_port = +		(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s *bfad = im_port->bfad; +	struct bfa_port_cfg_s port_cfg; +	int status = 0, rc; +	unsigned long flags; + +	memset(&port_cfg, 0, sizeof(port_cfg)); + +	port_cfg.pwwn = wwn_to_u64((u8 *) &fc_vport->port_name); +	port_cfg.nwwn = wwn_to_u64((u8 *) &fc_vport->node_name); + +	if (strlen(vname) > 0) +		strcpy((char *)&port_cfg.sym_name, vname); + +	port_cfg.roles = BFA_PORT_ROLE_FCP_IM; +	rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev); + +	if (rc == BFA_STATUS_OK) { +		struct bfad_vport_s   *vport; +		struct bfa_fcs_vport_s *fcs_vport; +		struct Scsi_Host *vshost; + +		spin_lock_irqsave(&bfad->bfad_lock, flags); +		fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, +					port_cfg.pwwn); +		if (fcs_vport == NULL) { +			spin_unlock_irqrestore(&bfad->bfad_lock, flags); +			return VPCERR_BAD_WWN; +		} + +		fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE); +		if (disable) { +			bfa_fcs_vport_stop(fcs_vport); +			fc_vport_set_state(fc_vport, FC_VPORT_DISABLED); +		} +		spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +		vport = fcs_vport->vport_drv; +		vshost = vport->drv_port.im_port->shost; +		fc_host_node_name(vshost) = wwn_to_u64((u8 *) &port_cfg.nwwn); +		fc_host_port_name(vshost) = wwn_to_u64((u8 *) &port_cfg.pwwn); +		fc_vport->dd_data = vport; +		vport->drv_port.im_port->fc_vport = fc_vport; + +	} else if (rc == BFA_STATUS_INVALID_WWN) +		return VPCERR_BAD_WWN; +	else if (rc == BFA_STATUS_VPORT_EXISTS) +		return VPCERR_BAD_WWN; +	else if (rc == BFA_STATUS_VPORT_MAX) +		return VPCERR_NO_FABRIC_SUPP; +	else if (rc == BFA_STATUS_VPORT_WWN_BP) +		return VPCERR_BAD_WWN; +	 else +		return FC_VPORT_FAILED; + +	return status; +} + +static int +bfad_im_vport_delete(struct fc_vport *fc_vport) +{ +	struct bfad_vport_s *vport = (struct bfad_vport_s *)fc_vport->dd_data; +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) vport->drv_port.im_port; +	struct bfad_s *bfad = im_port->bfad; +	struct bfad_port_s *port; +	struct bfa_fcs_vport_s *fcs_vport; +	struct Scsi_Host *vshost; +	wwn_t   pwwn; +	int rc; +	unsigned long flags; +	struct completion fcomp; + +	if (im_port->flags & BFAD_PORT_DELETE) +		goto free_scsi_host; + +	port = im_port->port; + +	vshost = vport->drv_port.im_port->shost; +	pwwn = wwn_to_u64((u8 *) &fc_host_port_name(vshost)); + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	if (fcs_vport == NULL) +		return VPCERR_BAD_WWN; + +	vport->drv_port.flags |= BFAD_PORT_DELETE; + +	vport->comp_del = &fcomp; +	init_completion(vport->comp_del); + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	rc = bfa_fcs_vport_delete(&vport->fcs_vport); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	wait_for_completion(vport->comp_del); + +free_scsi_host: +	bfad_os_scsi_host_free(bfad, im_port); + +	kfree(vport); + +	return 0; +} + +static int +bfad_im_vport_disable(struct fc_vport *fc_vport, bool disable) +{ +	struct bfad_vport_s *vport; +	struct bfad_s *bfad; +	struct bfa_fcs_vport_s *fcs_vport; +	struct Scsi_Host *vshost; +	wwn_t   pwwn; +	unsigned long flags; + +	vport = (struct bfad_vport_s *)fc_vport->dd_data; +	bfad = vport->drv_port.bfad; +	vshost = vport->drv_port.im_port->shost; +	pwwn = wwn_to_u64((u8 *) &fc_vport->port_name); + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	if (fcs_vport == NULL) +		return VPCERR_BAD_WWN; + +	if (disable) { +		bfa_fcs_vport_stop(fcs_vport); +		fc_vport_set_state(fc_vport, FC_VPORT_DISABLED); +	} else { +		bfa_fcs_vport_start(fcs_vport); +		fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE); +	} + +	return 0; +} +  struct fc_function_template bfad_im_fc_function_template = {  	/* Target dynamic attributes */ @@ -413,6 +559,61 @@ struct fc_function_template bfad_im_fc_function_template = {  	.show_rport_dev_loss_tmo = 1,  	.get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo,  	.set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo, + +	.vport_create = bfad_im_vport_create, +	.vport_delete = bfad_im_vport_delete, +	.vport_disable = bfad_im_vport_disable, +}; + +struct fc_function_template bfad_im_vport_fc_function_template = { + +	/* Target dynamic attributes */ +	.get_starget_port_id = bfad_im_get_starget_port_id, +	.show_starget_port_id = 1, +	.get_starget_node_name = bfad_im_get_starget_node_name, +	.show_starget_node_name = 1, +	.get_starget_port_name = bfad_im_get_starget_port_name, +	.show_starget_port_name = 1, + +	/* Host dynamic attribute */ +	.get_host_port_id = bfad_im_get_host_port_id, +	.show_host_port_id = 1, + +	/* Host fixed attributes */ +	.show_host_node_name = 1, +	.show_host_port_name = 1, +	.show_host_supported_classes = 1, +	.show_host_supported_fc4s = 1, +	.show_host_supported_speeds = 1, +	.show_host_maxframe_size = 1, + +	/* More host dynamic attributes */ +	.show_host_port_type = 1, +	.get_host_port_type = bfad_im_get_host_port_type, +	.show_host_port_state = 1, +	.get_host_port_state = bfad_im_get_host_port_state, +	.show_host_active_fc4s = 1, +	.get_host_active_fc4s = bfad_im_get_host_active_fc4s, +	.show_host_speed = 1, +	.get_host_speed = bfad_im_get_host_speed, +	.show_host_fabric_name = 1, +	.get_host_fabric_name = bfad_im_get_host_fabric_name, + +	.show_host_symbolic_name = 1, + +	/* Statistics */ +	.get_fc_host_stats = bfad_im_get_stats, +	.reset_fc_host_stats = bfad_im_reset_stats, + +	/* Allocation length for host specific data */ +	.dd_fcrport_size = sizeof(struct bfad_itnim_data_s *), + +	/* Remote port fixed attributes */ +	.show_rport_maxframe_size = 1, +	.show_rport_supported_classes = 1, +	.show_rport_dev_loss_tmo = 1, +	.get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo, +	.set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,  };  /** diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 107848cd3b6..6c920c1b53a 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -162,7 +162,6 @@ struct bfad_s {  	const char *pci_name;  	struct bfa_pcidev_s hal_pcidev;  	struct bfa_ioc_pci_attr_s pci_attr; -	unsigned long   pci_bar0_map;  	void __iomem   *pci_bar0_kva;  	struct completion comp;  	struct completion suspend; @@ -254,7 +253,7 @@ do {                                            	\  bfa_status_t    bfad_vport_create(struct bfad_s *bfad, u16 vf_id, -				  struct bfa_port_cfg_s *port_cfg); +			  struct bfa_port_cfg_s *port_cfg, struct device *dev);  bfa_status_t    bfad_vf_create(struct bfad_s *bfad, u16 vf_id,  			       struct bfa_port_cfg_s *port_cfg);  bfa_status_t    bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role); @@ -294,5 +293,6 @@ extern struct list_head bfad_list;  extern int bfa_lun_queue_depth;  extern int bfad_supported_fc4s;  extern int bfa_linkup_delay; +extern struct mutex bfad_mutex;  #endif /* __BFAD_DRV_H__ */ diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 78f42aa5736..5b7cf539e50 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -30,6 +30,7 @@ BFA_TRC_FILE(LDRV, IM);  DEFINE_IDR(bfad_im_port_index);  struct scsi_transport_template *bfad_im_scsi_transport_template; +struct scsi_transport_template *bfad_im_scsi_vport_transport_template;  static void bfad_im_itnim_work_handler(struct work_struct *work);  static int bfad_im_queuecommand(struct scsi_cmnd *cmnd,  		void (*done)(struct scsi_cmnd *)); @@ -252,7 +253,6 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,  	struct bfa_itnim_s *bfa_itnim;  	bfa_status_t    rc = BFA_STATUS_OK; -	bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);  	tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);  	if (!tskim) {  		BFA_DEV_PRINTF(bfad, BFA_ERR, @@ -513,11 +513,14 @@ void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim)   * Allocate a Scsi_Host for a port.   */  int -bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port) +bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, +				struct device *dev)  {  	int error = 1; +	mutex_lock(&bfad_mutex);  	if (!idr_pre_get(&bfad_im_port_index, GFP_KERNEL)) { +		mutex_unlock(&bfad_mutex);  		printk(KERN_WARNING "idr_pre_get failure\n");  		goto out;  	} @@ -525,10 +528,13 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)  	error = idr_get_new(&bfad_im_port_index, im_port,  					 &im_port->idr_id);  	if (error) { +		mutex_unlock(&bfad_mutex);  		printk(KERN_WARNING "idr_get_new failure\n");  		goto out;  	} +	mutex_unlock(&bfad_mutex); +  	im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad);  	if (!im_port->shost) {  		error = 1; @@ -542,12 +548,15 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)  	im_port->shost->max_lun = MAX_FCP_LUN;  	im_port->shost->max_cmd_len = 16;  	im_port->shost->can_queue = bfad->cfg_data.ioc_queue_depth; -	im_port->shost->transportt = bfad_im_scsi_transport_template; +	if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE) +		im_port->shost->transportt = bfad_im_scsi_transport_template; +	else +		im_port->shost->transportt = +				bfad_im_scsi_vport_transport_template; -	error = bfad_os_scsi_add_host(im_port->shost, im_port, bfad); +	error = scsi_add_host(im_port->shost, dev);  	if (error) { -		printk(KERN_WARNING "bfad_os_scsi_add_host failure %d\n", -							error); +		printk(KERN_WARNING "scsi_add_host failure %d\n", error);  		goto out_fc_rel;  	} @@ -559,7 +568,9 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)  out_fc_rel:  	scsi_host_put(im_port->shost);  out_free_idr: +	mutex_lock(&bfad_mutex);  	idr_remove(&bfad_im_port_index, im_port->idr_id); +	mutex_unlock(&bfad_mutex);  out:  	return error;  } @@ -567,8 +578,6 @@ out:  void  bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)  { -	unsigned long flags; -  	bfa_trc(bfad, bfad->inst_no);  	bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_HOST_FREE,  			im_port->shost->host_no); @@ -578,9 +587,9 @@ bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)  	scsi_remove_host(im_port->shost);  	scsi_host_put(im_port->shost); -	spin_lock_irqsave(&bfad->bfad_lock, flags); +	mutex_lock(&bfad_mutex);  	idr_remove(&bfad_im_port_index, im_port->idr_id); -	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	mutex_unlock(&bfad_mutex);  }  static void @@ -589,9 +598,11 @@ bfad_im_port_delete_handler(struct work_struct *work)  	struct bfad_im_port_s *im_port =  		container_of(work, struct bfad_im_port_s, port_delete_work); -	bfad_im_scsi_host_free(im_port->bfad, im_port); -	bfad_im_port_clean(im_port); -	kfree(im_port); +	if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) { +		im_port->flags |= BFAD_PORT_DELETE; +		fc_vport_terminate(im_port->fc_vport); +	} +  }  bfa_status_t @@ -690,23 +701,6 @@ bfad_im_probe_undo(struct bfad_s *bfad)  	}  } - - - -int -bfad_os_scsi_add_host(struct Scsi_Host *shost, struct bfad_im_port_s *im_port, -			struct bfad_s *bfad) -{ -    struct device *dev; - -    if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE) -		dev = &bfad->pcidev->dev; -    else -		dev = &bfad->pport.im_port->shost->shost_gendev; - -    return scsi_add_host(shost, dev); -} -  struct Scsi_Host *  bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)  { @@ -725,7 +719,8 @@ bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)  void  bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)  { -	flush_workqueue(bfad->im->drv_workq); +	if (!(im_port->flags & BFAD_PORT_DELETE)) +		flush_workqueue(bfad->im->drv_workq);  	bfad_im_scsi_host_free(im_port->bfad, im_port);  	bfad_im_port_clean(im_port);  	kfree(im_port); @@ -830,6 +825,13 @@ bfad_im_module_init(void)  	if (!bfad_im_scsi_transport_template)  		return BFA_STATUS_ENOMEM; +	bfad_im_scsi_vport_transport_template = +		fc_attach_transport(&bfad_im_vport_fc_function_template); +	if (!bfad_im_scsi_vport_transport_template) { +		fc_release_transport(bfad_im_scsi_transport_template); +		return BFA_STATUS_ENOMEM; +	} +  	return BFA_STATUS_OK;  } @@ -838,6 +840,8 @@ bfad_im_module_exit(void)  {  	if (bfad_im_scsi_transport_template)  		fc_release_transport(bfad_im_scsi_transport_template); +	if (bfad_im_scsi_vport_transport_template) +		fc_release_transport(bfad_im_scsi_vport_transport_template);  }  void @@ -938,6 +942,7 @@ bfad_os_fc_host_init(struct bfad_im_port_s *im_port)  		bfa_os_htonll((bfa_fcs_port_get_nwwn(port->fcs_port)));  	fc_host_port_name(host) =  		bfa_os_htonll((bfa_fcs_port_get_pwwn(port->fcs_port))); +	fc_host_max_npiv_vports(host) = bfa_lps_get_max_vport(&bfad->bfa);  	fc_host_supported_classes(host) = FC_COS_CLASS3; diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h index 85ab2da2132..973cab4d09c 100644 --- a/drivers/scsi/bfa/bfad_im.h +++ b/drivers/scsi/bfa/bfad_im.h @@ -34,7 +34,7 @@ void bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port);  void bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port);  void bfad_im_port_clean(struct bfad_im_port_s *im_port);  int  bfad_im_scsi_host_alloc(struct bfad_s *bfad, -				struct bfad_im_port_s *im_port); +		struct bfad_im_port_s *im_port, struct device *dev);  void bfad_im_scsi_host_free(struct bfad_s *bfad,  				struct bfad_im_port_s *im_port); @@ -64,9 +64,11 @@ struct bfad_im_port_s {  	struct work_struct port_delete_work;  	int             idr_id;  	u16        cur_scsi_id; +	u16	   flags;  	struct list_head binding_list;  	struct Scsi_Host *shost;  	struct list_head itnim_mapped_list; +	struct fc_vport *fc_vport;  };  enum bfad_itnim_state { @@ -140,6 +142,8 @@ void bfad_im_itnim_unmap(struct bfad_im_port_s  *im_port,  extern struct scsi_host_template bfad_im_scsi_host_template;  extern struct scsi_host_template bfad_im_vport_template;  extern struct fc_function_template bfad_im_fc_function_template; +extern struct fc_function_template bfad_im_vport_fc_function_template;  extern struct scsi_transport_template *bfad_im_scsi_transport_template; +extern struct scsi_transport_template *bfad_im_scsi_vport_transport_template;  #endif diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 18352ff8210..3a66ca24c7b 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -347,6 +347,7 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,  	login_wqe->cmd_sn = be32_to_cpu(login_hdr->cmdsn);  	login_wqe->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn); +	login_wqe->flags = ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN;  	login_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;  	login_wqe->resp_bd_list_addr_hi = @@ -356,7 +357,6 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,  		 (bnx2i_conn->gen_pdu.resp_buf_size <<  		  ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT));  	login_wqe->resp_buffer = dword; -	login_wqe->flags = 0;  	login_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;  	login_wqe->bd_list_addr_hi =  		(u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32); diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index 5d9296c599f..af6a00a600f 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -17,8 +17,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);  static u32 adapter_count;  #define DRV_MODULE_NAME		"bnx2i" -#define DRV_MODULE_VERSION	"2.1.0" -#define DRV_MODULE_RELDATE	"Dec 06, 2009" +#define DRV_MODULE_VERSION	"2.1.1" +#define DRV_MODULE_RELDATE	"Mar 24, 2010"  static char version[] __devinitdata =  		"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ @@ -26,7 +26,8 @@ static char version[] __devinitdata =  MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com>"); -MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver"); +MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711" +		   " iSCSI Driver");  MODULE_LICENSE("GPL");  MODULE_VERSION(DRV_MODULE_VERSION); @@ -289,6 +290,7 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)  	int rc;  	mutex_lock(&bnx2i_dev_lock); +	hba->cnic = cnic;  	rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);  	if (!rc) {  		hba->age++; @@ -335,8 +337,7 @@ void bnx2i_ulp_init(struct cnic_dev *dev)  	if (bnx2i_init_one(hba, dev)) {  		printk(KERN_ERR "bnx2i - hba %p init failed\n", hba);  		bnx2i_free_hba(hba); -	} else -		hba->cnic = dev; +	}  } diff --git a/drivers/scsi/cxgb3i/cxgb3i_init.c b/drivers/scsi/cxgb3i/cxgb3i_init.c index d0ab23a5835..685af369851 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_init.c +++ b/drivers/scsi/cxgb3i/cxgb3i_init.c @@ -104,8 +104,10 @@ static int __init cxgb3i_init_module(void)  		return err;  	err = cxgb3i_pdu_init(); -	if (err < 0) +	if (err < 0) { +		cxgb3i_iscsi_cleanup();  		return err; +	}  	cxgb3_register_client(&t3c_client); diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index e8a0bc3efd4..6faf472f753 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -285,13 +285,11 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,  	switch (cmd) {  	case MODE_SELECT:  		len = sizeof(short_trespass); -		rq->cmd_flags |= REQ_RW;  		rq->cmd[1] = 0x10;  		rq->cmd[4] = len;  		break;  	case MODE_SELECT_10:  		len = sizeof(long_trespass); -		rq->cmd_flags |= REQ_RW;  		rq->cmd[1] = 0x10;  		rq->cmd[8] = len;  		break; diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index f01b9b44e8a..ba75a98c960 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -74,6 +74,7 @@ static int fcoe_rcv(struct sk_buff *, struct net_device *,  static int fcoe_percpu_receive_thread(void *);  static void fcoe_clean_pending_queue(struct fc_lport *);  static void fcoe_percpu_clean(struct fc_lport *); +static int fcoe_link_speed_update(struct fc_lport *);  static int fcoe_link_ok(struct fc_lport *);  static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); @@ -146,6 +147,7 @@ static int fcoe_vport_destroy(struct fc_vport *);  static int fcoe_vport_create(struct fc_vport *, bool disabled);  static int fcoe_vport_disable(struct fc_vport *, bool disable);  static void fcoe_set_vport_symbolic_name(struct fc_vport *); +static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *);  static struct libfc_function_template fcoe_libfc_fcn_templ = {  	.frame_send = fcoe_xmit, @@ -153,6 +155,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {  	.ddp_done = fcoe_ddp_done,  	.elsct_send = fcoe_elsct_send,  	.get_lesb = fcoe_get_lesb, +	.lport_set_port_id = fcoe_set_port_id,  };  struct fc_function_template fcoe_transport_function = { @@ -629,6 +632,8 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)  	port->fcoe_pending_queue_active = 0;  	setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport); +	fcoe_link_speed_update(lport); +  	if (!lport->vport) {  		/*  		 * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN: @@ -653,15 +658,13 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)  /**   * fcoe_shost_config() - Set up the SCSI host associated with a local port   * @lport: The local port - * @shost: The SCSI host to associate with the local port   * @dev:   The device associated with the SCSI host   *   * Must be called after fcoe_lport_config() and fcoe_netdev_config()   *   * Returns: 0 for success   */ -static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost, -			     struct device *dev) +static int fcoe_shost_config(struct fc_lport *lport, struct device *dev)  {  	int rc = 0; @@ -669,6 +672,8 @@ static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost,  	lport->host->max_lun = FCOE_MAX_LUN;  	lport->host->max_id = FCOE_MAX_FCP_TARGET;  	lport->host->max_channel = 0; +	lport->host->max_cmd_len = FCOE_MAX_CMD_LEN; +  	if (lport->vport)  		lport->host->transportt = fcoe_vport_transport_template;  	else @@ -796,6 +801,12 @@ skip_oem:  /**   * fcoe_if_destroy() - Tear down a SW FCoE instance   * @lport: The local port to be destroyed + * + * Locking: must be called with the RTNL mutex held and RTNL mutex + * needed to be dropped by this function since not dropping RTNL + * would cause circular locking warning on synchronous fip worker + * cancelling thru fcoe_interface_put invoked by this function. + *   */  static void fcoe_if_destroy(struct fc_lport *lport)  { @@ -818,7 +829,6 @@ static void fcoe_if_destroy(struct fc_lport *lport)  	/* Free existing transmit skbs */  	fcoe_clean_pending_queue(lport); -	rtnl_lock();  	if (!is_zero_ether_addr(port->data_src_addr))  		dev_unicast_delete(netdev, port->data_src_addr);  	rtnl_unlock(); @@ -841,6 +851,7 @@ static void fcoe_if_destroy(struct fc_lport *lport)  	/* Release the Scsi_Host */  	scsi_host_put(lport->host); +	module_put(THIS_MODULE);  }  /** @@ -897,7 +908,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,  	struct net_device *netdev = fcoe->netdev;  	struct fc_lport *lport = NULL;  	struct fcoe_port *port; -	struct Scsi_Host *shost;  	int rc;  	/*  	 * parent is only a vport if npiv is 1, @@ -919,7 +929,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,  		rc = -ENOMEM;  		goto out;  	} -	shost = lport->host;  	port = lport_priv(lport);  	port->lport = lport;  	port->fcoe = fcoe; @@ -934,7 +943,8 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,  	}  	if (npiv) { -		FCOE_NETDEV_DBG(netdev, "Setting vport names, 0x%llX 0x%llX\n", +		FCOE_NETDEV_DBG(netdev, "Setting vport names, " +				"%16.16llx %16.16llx\n",  				vport->node_name, vport->port_name);  		fc_set_wwnn(lport, vport->node_name);  		fc_set_wwpn(lport, vport->port_name); @@ -949,7 +959,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,  	}  	/* configure lport scsi host properties */ -	rc = fcoe_shost_config(lport, shost, parent); +	rc = fcoe_shost_config(lport, parent);  	if (rc) {  		FCOE_NETDEV_DBG(netdev, "Could not configure shost for the "  				"interface\n"); @@ -1073,7 +1083,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)  	struct sk_buff *skb;  #ifdef CONFIG_SMP  	struct fcoe_percpu_s *p0; -	unsigned targ_cpu = smp_processor_id(); +	unsigned targ_cpu = get_cpu();  #endif /* CONFIG_SMP */  	FCOE_DBG("Destroying receive thread for CPU %d\n", cpu); @@ -1129,6 +1139,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)  			kfree_skb(skb);  		spin_unlock_bh(&p->fcoe_rx_list.lock);  	} +	put_cpu();  #else  	/*  	 * This a non-SMP scenario where the singular Rx thread is @@ -1297,8 +1308,8 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,  	return 0;  err: -	fc_lport_get_stats(lport)->ErrorFrames++; - +	per_cpu_ptr(lport->dev_stats, get_cpu())->ErrorFrames++; +	put_cpu();  err2:  	kfree_skb(skb);  	return -1; @@ -1444,7 +1455,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)  		return 0;  	} -	if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) && +	if (unlikely(fh->fh_type == FC_TYPE_ELS) &&  	    fcoe_ctlr_els_send(&fcoe->ctlr, lport, skb))  		return 0; @@ -1527,9 +1538,10 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)  		skb_shinfo(skb)->gso_size = 0;  	}  	/* update tx stats: regardless if LLD fails */ -	stats = fc_lport_get_stats(lport); +	stats = per_cpu_ptr(lport->dev_stats, get_cpu());  	stats->TxFrames++;  	stats->TxWords += wlen; +	put_cpu();  	/* send down to lld */  	fr_dev(fp) = lport; @@ -1563,7 +1575,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)  	struct fc_frame_header *fh;  	struct fcoe_crc_eof crc_eof;  	struct fc_frame *fp; -	u8 *mac = NULL;  	struct fcoe_port *port;  	struct fcoe_hdr *hp; @@ -1583,13 +1594,9 @@ static void fcoe_recv_frame(struct sk_buff *skb)  			skb_end_pointer(skb), skb->csum,  			skb->dev ? skb->dev->name : "<NULL>"); -	/* -	 * Save source MAC address before discarding header. -	 */  	port = lport_priv(lport);  	if (skb_is_nonlinear(skb))  		skb_linearize(skb);	/* not ideal */ -	mac = eth_hdr(skb)->h_source;  	/*  	 * Frame length checks and setting up the header pointers @@ -1598,7 +1605,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)  	hp = (struct fcoe_hdr *) skb_network_header(skb);  	fh = (struct fc_frame_header *) skb_transport_header(skb); -	stats = fc_lport_get_stats(lport); +	stats = per_cpu_ptr(lport->dev_stats, get_cpu());  	if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {  		if (stats->ErrorFrames < 5)  			printk(KERN_WARNING "fcoe: FCoE version " @@ -1607,9 +1614,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)  			       "initiator supports version "  			       "%x\n", FC_FCOE_DECAPS_VER(hp),  			       FC_FCOE_VER); -		stats->ErrorFrames++; -		kfree_skb(skb); -		return; +		goto drop;  	}  	skb_pull(skb, sizeof(struct fcoe_hdr)); @@ -1624,16 +1629,12 @@ static void fcoe_recv_frame(struct sk_buff *skb)  	fr_sof(fp) = hp->fcoe_sof;  	/* Copy out the CRC and EOF trailer for access */ -	if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { -		kfree_skb(skb); -		return; -	} +	if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) +		goto drop;  	fr_eof(fp) = crc_eof.fcoe_eof;  	fr_crc(fp) = crc_eof.fcoe_crc32; -	if (pskb_trim(skb, fr_len)) { -		kfree_skb(skb); -		return; -	} +	if (pskb_trim(skb, fr_len)) +		goto drop;  	/*  	 * We only check CRC if no offload is available and if it is @@ -1647,25 +1648,27 @@ static void fcoe_recv_frame(struct sk_buff *skb)  		fr_flags(fp) |= FCPHF_CRC_UNCHECKED;  	fh = fc_frame_header_get(fp); -	if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && -	    fh->fh_type == FC_TYPE_FCP) { -		fc_exch_recv(lport, fp); -		return; -	} -	if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { +	if ((fh->fh_r_ctl != FC_RCTL_DD_SOL_DATA || +	    fh->fh_type != FC_TYPE_FCP) && +	    (fr_flags(fp) & FCPHF_CRC_UNCHECKED)) {  		if (le32_to_cpu(fr_crc(fp)) !=  		    ~crc32(~0, skb->data, fr_len)) {  			if (stats->InvalidCRCCount < 5)  				printk(KERN_WARNING "fcoe: dropping "  				       "frame with CRC error\n");  			stats->InvalidCRCCount++; -			stats->ErrorFrames++; -			fc_frame_free(fp); -			return; +			goto drop;  		}  		fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;  	} +	put_cpu();  	fc_exch_recv(lport, fp); +	return; + +drop: +	stats->ErrorFrames++; +	put_cpu(); +	kfree_skb(skb);  }  /** @@ -1835,11 +1838,15 @@ static int fcoe_device_notification(struct notifier_block *notifier,  		FCOE_NETDEV_DBG(netdev, "Unknown event %ld "  				"from netdev netlink\n", event);  	} + +	fcoe_link_speed_update(lport); +  	if (link_possible && !fcoe_link_ok(lport))  		fcoe_ctlr_link_up(&fcoe->ctlr);  	else if (fcoe_ctlr_link_down(&fcoe->ctlr)) { -		stats = fc_lport_get_stats(lport); +		stats = per_cpu_ptr(lport->dev_stats, get_cpu());  		stats->LinkFailureCount++; +		put_cpu();  		fcoe_clean_pending_queue(lport);  	}  out: @@ -1901,13 +1908,19 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp)  		goto out_nodev;  	} -	rtnl_lock(); +	if (!rtnl_trylock()) { +		dev_put(netdev); +		mutex_unlock(&fcoe_config_mutex); +		return restart_syscall(); +	} +  	fcoe = fcoe_hostlist_lookup_port(netdev);  	rtnl_unlock(); -	if (fcoe) +	if (fcoe) {  		fc_fabric_logoff(fcoe->ctlr.lp); -	else +		fcoe_ctlr_link_down(&fcoe->ctlr); +	} else  		rc = -ENODEV;  	dev_put(netdev); @@ -1950,13 +1963,20 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp)  		goto out_nodev;  	} -	rtnl_lock(); +	if (!rtnl_trylock()) { +		dev_put(netdev); +		mutex_unlock(&fcoe_config_mutex); +		return restart_syscall(); +	} +  	fcoe = fcoe_hostlist_lookup_port(netdev);  	rtnl_unlock(); -	if (fcoe) +	if (fcoe) { +		if (!fcoe_link_ok(fcoe->ctlr.lp)) +			fcoe_ctlr_link_up(&fcoe->ctlr);  		rc = fc_fabric_login(fcoe->ctlr.lp); -	else +	} else  		rc = -ENODEV;  	dev_put(netdev); @@ -1999,7 +2019,12 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)  		goto out_nodev;  	} -	rtnl_lock(); +	if (!rtnl_trylock()) { +		dev_put(netdev); +		mutex_unlock(&fcoe_config_mutex); +		return restart_syscall(); +	} +  	fcoe = fcoe_hostlist_lookup_port(netdev);  	if (!fcoe) {  		rtnl_unlock(); @@ -2008,9 +2033,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)  	}  	list_del(&fcoe->list);  	fcoe_interface_cleanup(fcoe); -	rtnl_unlock(); +	/* RTNL mutex is dropped by fcoe_if_destroy */  	fcoe_if_destroy(fcoe->ctlr.lp); -	module_put(THIS_MODULE);  out_putdev:  	dev_put(netdev); @@ -2029,6 +2053,8 @@ static void fcoe_destroy_work(struct work_struct *work)  	port = container_of(work, struct fcoe_port, destroy_work);  	mutex_lock(&fcoe_config_mutex); +	rtnl_lock(); +	/* RTNL mutex is dropped by fcoe_if_destroy */  	fcoe_if_destroy(port->lport);  	mutex_unlock(&fcoe_config_mutex);  } @@ -2050,6 +2076,12 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)  	struct net_device *netdev;  	mutex_lock(&fcoe_config_mutex); + +	if (!rtnl_trylock()) { +		mutex_unlock(&fcoe_config_mutex); +		return restart_syscall(); +	} +  #ifdef CONFIG_FCOE_MODULE  	/*  	 * Make sure the module has been initialized, and is not about to be @@ -2058,7 +2090,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)  	 */  	if (THIS_MODULE->state != MODULE_STATE_LIVE) {  		rc = -ENODEV; -		goto out_nodev; +		goto out_nomod;  	}  #endif @@ -2067,7 +2099,6 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)  		goto out_nomod;  	} -	rtnl_lock();  	netdev = fcoe_if_to_netdev(buffer);  	if (!netdev) {  		rc = -ENODEV; @@ -2122,35 +2153,27 @@ out_free:  out_putdev:  	dev_put(netdev);  out_nodev: -	rtnl_unlock();  	module_put(THIS_MODULE);  out_nomod: +	rtnl_unlock();  	mutex_unlock(&fcoe_config_mutex);  	return rc;  }  /** - * fcoe_link_ok() - Check if the link is OK for a local port - * @lport: The local port to check link on - * - * Any permanently-disqualifying conditions have been previously checked. - * This also updates the speed setting, which may change with link for 100/1000. - * - * This function should probably be checking for PAUSE support at some point - * in the future. Currently Per-priority-pause is not determinable using - * ethtool, so we shouldn't be restrictive until that problem is resolved. - * - * Returns: 0 if link is OK for use by FCoE. + * fcoe_link_speed_update() - Update the supported and actual link speeds + * @lport: The local port to update speeds for   * + * Returns: 0 if the ethtool query was successful + *          -1 if the ethtool query failed   */ -int fcoe_link_ok(struct fc_lport *lport) +int fcoe_link_speed_update(struct fc_lport *lport)  {  	struct fcoe_port *port = lport_priv(lport);  	struct net_device *netdev = port->fcoe->netdev;  	struct ethtool_cmd ecmd = { ETHTOOL_GSET }; -	if ((netdev->flags & IFF_UP) && netif_carrier_ok(netdev) && -	    (!dev_ethtool_get_settings(netdev, &ecmd))) { +	if (!dev_ethtool_get_settings(netdev, &ecmd)) {  		lport->link_supported_speeds &=  			~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);  		if (ecmd.supported & (SUPPORTED_1000baseT_Half | @@ -2170,6 +2193,23 @@ int fcoe_link_ok(struct fc_lport *lport)  }  /** + * fcoe_link_ok() - Check if the link is OK for a local port + * @lport: The local port to check link on + * + * Returns: 0 if link is UP and OK, -1 if not + * + */ +int fcoe_link_ok(struct fc_lport *lport) +{ +	struct fcoe_port *port = lport_priv(lport); +	struct net_device *netdev = port->fcoe->netdev; + +	if (netif_oper_up(netdev)) +		return 0; +	return -1; +} + +/**   * fcoe_percpu_clean() - Clear all pending skbs for an local port   * @lport: The local port whose skbs are to be cleared   * @@ -2631,3 +2671,25 @@ static void fcoe_get_lesb(struct fc_lport *lport,  	lesb->lesb_miss_fka = htonl(mdac);  	lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors);  } + +/** + * fcoe_set_port_id() - Callback from libfc when Port_ID is set. + * @lport: the local port + * @port_id: the port ID + * @fp: the received frame, if any, that caused the port_id to be set. + * + * This routine handles the case where we received a FLOGI and are + * entering point-to-point mode.  We need to call fcoe_ctlr_recv_flogi() + * so it can set the non-mapped mode and gateway address. + * + * The FLOGI LS_ACC is handled by fcoe_flogi_resp(). + */ +static void fcoe_set_port_id(struct fc_lport *lport, +			     u32 port_id, struct fc_frame *fp) +{ +	struct fcoe_port *port = lport_priv(lport); +	struct fcoe_interface *fcoe = port->fcoe; + +	if (fp && fc_frame_payload_op(fp) == ELS_FLOGI) +		fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp); +} diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 3440da48d16..50aaa4bcfc5 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -51,7 +51,7 @@ MODULE_LICENSE("GPL v2");  #define	FCOE_CTLR_DEF_FKA	FIP_DEF_FKA	/* default keep alive (mS) */  static void fcoe_ctlr_timeout(unsigned long); -static void fcoe_ctlr_link_work(struct work_struct *); +static void fcoe_ctlr_timer_work(struct work_struct *);  static void fcoe_ctlr_recv_work(struct work_struct *);  static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS; @@ -116,7 +116,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip)  	spin_lock_init(&fip->lock);  	fip->flogi_oxid = FC_XID_UNKNOWN;  	setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip); -	INIT_WORK(&fip->link_work, fcoe_ctlr_link_work); +	INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);  	INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work);  	skb_queue_head_init(&fip->fip_recv_list);  } @@ -164,7 +164,7 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)  	fcoe_ctlr_reset_fcfs(fip);  	spin_unlock_bh(&fip->lock);  	del_timer_sync(&fip->timer); -	cancel_work_sync(&fip->link_work); +	cancel_work_sync(&fip->timer_work);  }  EXPORT_SYMBOL(fcoe_ctlr_destroy); @@ -257,14 +257,10 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)  {  	spin_lock_bh(&fip->lock);  	if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) { -		fip->last_link = 1; -		fip->link = 1;  		spin_unlock_bh(&fip->lock);  		fc_linkup(fip->lp);  	} else if (fip->state == FIP_ST_LINK_WAIT) {  		fip->state = fip->mode; -		fip->last_link = 1; -		fip->link = 1;  		spin_unlock_bh(&fip->lock);  		if (fip->state == FIP_ST_AUTO)  			LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n"); @@ -306,9 +302,7 @@ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip)  	LIBFCOE_FIP_DBG(fip, "link down.\n");  	spin_lock_bh(&fip->lock);  	fcoe_ctlr_reset(fip); -	link_dropped = fip->link; -	fip->link = 0; -	fip->last_link = 0; +	link_dropped = fip->state != FIP_ST_LINK_WAIT;  	fip->state = FIP_ST_LINK_WAIT;  	spin_unlock_bh(&fip->lock); @@ -349,7 +343,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,  	fcf = fip->sel_fcf;  	lp = fip->lp; -	if (!fcf || !fc_host_port_id(lp->host)) +	if (!fcf || !lp->port_id)  		return;  	len = sizeof(*kal) + ports * sizeof(*vn); @@ -380,8 +374,8 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,  		vn->fd_desc.fip_dtype = FIP_DT_VN_ID;  		vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW;  		memcpy(vn->fd_mac, fip->get_src_addr(lport), ETH_ALEN); -		hton24(vn->fd_fc_id, fc_host_port_id(lp->host)); -		put_unaligned_be64(lp->wwpn, &vn->fd_wwpn); +		hton24(vn->fd_fc_id, lport->port_id); +		put_unaligned_be64(lport->wwpn, &vn->fd_wwpn);  	}  	skb_put(skb, len);  	skb->protocol = htons(ETH_P_FIP); @@ -445,13 +439,18 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,  	cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;  	mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac)); -	memset(mac, 0, sizeof(mac)); +	memset(mac, 0, sizeof(*mac));  	mac->fd_desc.fip_dtype = FIP_DT_MAC;  	mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW; -	if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) +	if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {  		memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN); -	else if (fip->spma) +	} else if (fip_flags & FIP_FL_SPMA) { +		LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");  		memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN); +	} else { +		LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n"); +		/* FPMA only FLOGI must leave the MAC desc set to all 0s */ +	}  	skb->protocol = htons(ETH_P_FIP);  	skb_reset_mac_header(skb); @@ -556,7 +555,7 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send);   * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller   * @fip: The FCoE controller to free FCFs on   * - * Called with lock held. + * Called with lock held and preemption disabled.   *   * An FCF is considered old if we have missed three advertisements.   * That is, there have been no valid advertisement from it for three @@ -573,17 +572,20 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)  	struct fcoe_fcf *next;  	unsigned long sel_time = 0;  	unsigned long mda_time = 0; +	struct fcoe_dev_stats *stats;  	list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {  		mda_time = fcf->fka_period + (fcf->fka_period >> 1);  		if ((fip->sel_fcf == fcf) &&  		    (time_after(jiffies, fcf->time + mda_time))) {  			mod_timer(&fip->timer, jiffies + mda_time); -			fc_lport_get_stats(fip->lp)->MissDiscAdvCount++; +			stats = per_cpu_ptr(fip->lp->dev_stats, +					    smp_processor_id()); +			stats->MissDiscAdvCount++;  			printk(KERN_INFO "libfcoe: host%d: Missing Discovery " -			       "Advertisement for fab %llx count %lld\n", +			       "Advertisement for fab %16.16llx count %lld\n",  			       fip->lp->host->host_no, fcf->fabric_name, -			       fc_lport_get_stats(fip->lp)->MissDiscAdvCount); +			       stats->MissDiscAdvCount);  		}  		if (time_after(jiffies, fcf->time + fcf->fka_period * 3 +  			       msecs_to_jiffies(FIP_FCF_FUZZ * 3))) { @@ -593,7 +595,9 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)  			WARN_ON(!fip->fcf_count);  			fip->fcf_count--;  			kfree(fcf); -			fc_lport_get_stats(fip->lp)->VLinkFailureCount++; +			stats = per_cpu_ptr(fip->lp->dev_stats, +					    smp_processor_id()); +			stats->VLinkFailureCount++;  		} else if (fcoe_ctlr_mtu_valid(fcf) &&  			   (!sel_time || time_before(sel_time, fcf->time))) {  			sel_time = fcf->time; @@ -776,7 +780,8 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)  	mtu_valid = fcoe_ctlr_mtu_valid(fcf);  	fcf->time = jiffies;  	if (!found) { -		LIBFCOE_FIP_DBG(fip, "New FCF for fab %llx map %x val %d\n", +		LIBFCOE_FIP_DBG(fip, "New FCF for fab %16.16llx " +				"map %x val %d\n",  				fcf->fabric_name, fcf->fc_map, mtu_valid);  	} @@ -906,9 +911,10 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)  	fr_eof(fp) = FC_EOF_T;  	fr_dev(fp) = lport; -	stats = fc_lport_get_stats(lport); +	stats = per_cpu_ptr(lport->dev_stats, get_cpu());  	stats->RxFrames++;  	stats->RxWords += skb->len / FIP_BPW; +	put_cpu();  	fc_exch_recv(lport, fp);  	return; @@ -942,9 +948,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,  	u32	desc_mask;  	LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n"); -	if (!fcf) -		return; -	if (!fcf || !fc_host_port_id(lport->host)) + +	if (!fcf || !lport->port_id)  		return;  	/* @@ -982,8 +987,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,  			if (compare_ether_addr(vp->fd_mac,  					       fip->get_src_addr(lport)) == 0 &&  			    get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn && -			    ntoh24(vp->fd_fc_id) == -			    fc_host_port_id(lport->host)) +			    ntoh24(vp->fd_fc_id) == lport->port_id)  				desc_mask &= ~BIT(FIP_DT_VN_ID);  			break;  		default: @@ -1006,7 +1010,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,  		LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");  		spin_lock_bh(&fip->lock); -		fc_lport_get_stats(lport)->VLinkFailureCount++; +		per_cpu_ptr(lport->dev_stats, +			    smp_processor_id())->VLinkFailureCount++;  		fcoe_ctlr_reset(fip);  		spin_unlock_bh(&fip->lock); @@ -1102,15 +1107,17 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)  	struct fcoe_fcf *best = NULL;  	list_for_each_entry(fcf, &fip->fcfs, list) { -		LIBFCOE_FIP_DBG(fip, "consider FCF for fab %llx VFID %d map %x " -				"val %d\n", fcf->fabric_name, fcf->vfid, +		LIBFCOE_FIP_DBG(fip, "consider FCF for fab %16.16llx " +				"VFID %d map %x val %d\n", +				fcf->fabric_name, fcf->vfid,  				fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));  		if (!fcoe_ctlr_fcf_usable(fcf)) { -			LIBFCOE_FIP_DBG(fip, "FCF for fab %llx map %x %svalid " -					"%savailable\n", fcf->fabric_name, -					fcf->fc_map, (fcf->flags & FIP_FL_SOL) -					? "" : "in", (fcf->flags & FIP_FL_AVAIL) -					? "" : "un"); +			LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx " +					"map %x %svalid %savailable\n", +					fcf->fabric_name, fcf->fc_map, +					(fcf->flags & FIP_FL_SOL) ? "" : "in", +					(fcf->flags & FIP_FL_AVAIL) ? +					"" : "un");  			continue;  		}  		if (!best) { @@ -1175,7 +1182,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)  			       "Starting FCF discovery.\n",  			       fip->lp->host->host_no);  			fip->reset_req = 1; -			schedule_work(&fip->link_work); +			schedule_work(&fip->timer_work);  		}  	} @@ -1201,43 +1208,31 @@ static void fcoe_ctlr_timeout(unsigned long arg)  		mod_timer(&fip->timer, next_timer);  	}  	if (fip->send_ctlr_ka || fip->send_port_ka) -		schedule_work(&fip->link_work); +		schedule_work(&fip->timer_work);  	spin_unlock_bh(&fip->lock);  }  /** - * fcoe_ctlr_link_work() - Worker thread function for link changes + * fcoe_ctlr_timer_work() - Worker thread function for timer work   * @work: Handle to a FCoE controller   * - * See if the link status has changed and if so, report it. - * - * This is here because fc_linkup() and fc_linkdown() must not + * Sends keep-alives and resets which must not   * be called from the timer directly, since they use a mutex.   */ -static void fcoe_ctlr_link_work(struct work_struct *work) +static void fcoe_ctlr_timer_work(struct work_struct *work)  {  	struct fcoe_ctlr *fip;  	struct fc_lport *vport;  	u8 *mac; -	int link; -	int last_link;  	int reset; -	fip = container_of(work, struct fcoe_ctlr, link_work); +	fip = container_of(work, struct fcoe_ctlr, timer_work);  	spin_lock_bh(&fip->lock); -	last_link = fip->last_link; -	link = fip->link; -	fip->last_link = link;  	reset = fip->reset_req;  	fip->reset_req = 0;  	spin_unlock_bh(&fip->lock); -	if (last_link != link) { -		if (link) -			fc_linkup(fip->lp); -		else -			fc_linkdown(fip->lp); -	} else if (reset && link) +	if (reset)  		fc_lport_reset(fip->lp);  	if (fip->send_ctlr_ka) { @@ -1334,9 +1329,9 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,  		if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) {  			memcpy(fip->dest_addr, sa, ETH_ALEN);  			fip->map_dest = 0; -			if (fip->state == FIP_ST_NON_FIP) -				LIBFCOE_FIP_DBG(fip, "received FLOGI REQ, " -						"using non-FIP mode\n"); +			if (fip->state == FIP_ST_AUTO) +				LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. " +						"Setting non-FIP mode\n");  			fip->state = FIP_ST_NON_FIP;  		}  		spin_unlock_bh(&fip->lock); diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 3966c71d009..19338e0ba2c 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -36,7 +36,7 @@  #define DRV_NAME		"fnic"  #define DRV_DESCRIPTION		"Cisco FCoE HBA Driver" -#define DRV_VERSION		"1.4.0.98" +#define DRV_VERSION		"1.4.0.145"  #define PFX			DRV_NAME ": "  #define DFX                     DRV_NAME "%d: " @@ -45,7 +45,7 @@  #define	FNIC_IO_LOCKS		64 /* IO locks: power of 2 */  #define FNIC_DFLT_QUEUE_DEPTH	32  #define	FNIC_STATS_RATE_LIMIT	4 /* limit rate at which stats are pulled up */ -#define FNIC_MAX_CMD_LEN        16 /* Supported CDB length */ +  /*   * Tag bits used for special requests.   */ diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 5259888fbfb..2b48d79bad9 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -617,7 +617,7 @@ void fnic_flush_tx(struct fnic *fnic)  	struct sk_buff *skb;  	struct fc_frame *fp; -	while ((skb = skb_dequeue(&fnic->frame_queue))) { +	while ((skb = skb_dequeue(&fnic->tx_queue))) {  		fp = (struct fc_frame *)skb;  		fnic_send_frame(fnic, fp);  	} diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 97b212570bc..265e73d9cd6 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -556,7 +556,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,  	}  	host->max_lun = fnic->config.luns_per_tgt;  	host->max_id = FNIC_MAX_FCP_TARGET; -	host->max_cmd_len = FNIC_MAX_CMD_LEN; +	host->max_cmd_len = FCOE_MAX_CMD_LEN;  	fnic_get_res_counts(fnic); diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 35a4b3073ec..a765fe7a55c 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -3842,7 +3842,7 @@ int __init option_setup(char *str)      TRACE2(("option_setup() str %s\n", str ? str:"NULL"));  -    while (cur && isdigit(*cur) && i <= MAXHA) { +    while (cur && isdigit(*cur) && i < MAXHA) {          ints[i++] = simple_strtoul(cur, NULL, 0);          if ((cur = strchr(cur, ',')) != NULL) cur++;      } diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index 48f406850c6..18b7102bb80 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -19,332 +19,334 @@  #include "wd33c93.h"  #include "gvp11.h" -#include<linux/stat.h> +#include <linux/stat.h> -#define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base)) -#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) -static irqreturn_t gvp11_intr (int irq, void *_instance) +#define DMA(ptr)	((gvp11_scsiregs *)((ptr)->base)) + +static irqreturn_t gvp11_intr(int irq, void *_instance)  { -    unsigned long flags; -    unsigned int status; -    struct Scsi_Host *instance = (struct Scsi_Host *)_instance; +	unsigned long flags; +	unsigned int status; +	struct Scsi_Host *instance = (struct Scsi_Host *)_instance; -    status = DMA(instance)->CNTR; -    if (!(status & GVP11_DMAC_INT_PENDING)) -	return IRQ_NONE; +	status = DMA(instance)->CNTR; +	if (!(status & GVP11_DMAC_INT_PENDING)) +		return IRQ_NONE; -    spin_lock_irqsave(instance->host_lock, flags); -    wd33c93_intr(instance); -    spin_unlock_irqrestore(instance->host_lock, flags); -    return IRQ_HANDLED; +	spin_lock_irqsave(instance->host_lock, flags); +	wd33c93_intr(instance); +	spin_unlock_irqrestore(instance->host_lock, flags); +	return IRQ_HANDLED;  }  static int gvp11_xfer_mask = 0; -void gvp11_setup (char *str, int *ints) +void gvp11_setup(char *str, int *ints)  { -    gvp11_xfer_mask = ints[1]; +	gvp11_xfer_mask = ints[1];  }  static int dma_setup(struct scsi_cmnd *cmd, int dir_in)  { -    unsigned short cntr = GVP11_DMAC_INT_ENABLE; -    unsigned long addr = virt_to_bus(cmd->SCp.ptr); -    int bank_mask; -    static int scsi_alloc_out_of_range = 0; +	struct Scsi_Host *instance = cmd->device->host; +	struct WD33C93_hostdata *hdata = shost_priv(instance); +	unsigned short cntr = GVP11_DMAC_INT_ENABLE; +	unsigned long addr = virt_to_bus(cmd->SCp.ptr); +	int bank_mask; +	static int scsi_alloc_out_of_range = 0; -    /* use bounce buffer if the physical address is bad */ -    if (addr & HDATA(cmd->device->host)->dma_xfer_mask) -    { -	HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511) -	    & ~0x1ff; +	/* use bounce buffer if the physical address is bad */ +	if (addr & hdata->dma_xfer_mask) { +		hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; - 	if( !scsi_alloc_out_of_range ) { -	    HDATA(cmd->device->host)->dma_bounce_buffer = -		kmalloc (HDATA(cmd->device->host)->dma_bounce_len, GFP_KERNEL); -	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_SCSI_ALLOCED; -	} +		if (!scsi_alloc_out_of_range) { +			hdata->dma_bounce_buffer = +				kmalloc(hdata->dma_bounce_len, GFP_KERNEL); +			hdata->dma_buffer_pool = BUF_SCSI_ALLOCED; +		} -	if (scsi_alloc_out_of_range || -	    !HDATA(cmd->device->host)->dma_bounce_buffer) { -	    HDATA(cmd->device->host)->dma_bounce_buffer = -		amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len, -				       "GVP II SCSI Bounce Buffer"); +		if (scsi_alloc_out_of_range || +		    !hdata->dma_bounce_buffer) { +			hdata->dma_bounce_buffer = +				amiga_chip_alloc(hdata->dma_bounce_len, +						 "GVP II SCSI Bounce Buffer"); -	    if(!HDATA(cmd->device->host)->dma_bounce_buffer) -	    { -		HDATA(cmd->device->host)->dma_bounce_len = 0; -		return 1; -	    } +			if (!hdata->dma_bounce_buffer) { +				hdata->dma_bounce_len = 0; +				return 1; +			} -	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED; -	} +			hdata->dma_buffer_pool = BUF_CHIP_ALLOCED; +		} -	/* check if the address of the bounce buffer is OK */ -	addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer); +		/* check if the address of the bounce buffer is OK */ +		addr = virt_to_bus(hdata->dma_bounce_buffer); -	if (addr & HDATA(cmd->device->host)->dma_xfer_mask) { -	    /* fall back to Chip RAM if address out of range */ -	    if( HDATA(cmd->device->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) { -		kfree (HDATA(cmd->device->host)->dma_bounce_buffer); -		scsi_alloc_out_of_range = 1; -	    } else { -		amiga_chip_free (HDATA(cmd->device->host)->dma_bounce_buffer); -            } -		 -	    HDATA(cmd->device->host)->dma_bounce_buffer = -		amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len, -				       "GVP II SCSI Bounce Buffer"); +		if (addr & hdata->dma_xfer_mask) { +			/* fall back to Chip RAM if address out of range */ +			if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED) { +				kfree(hdata->dma_bounce_buffer); +				scsi_alloc_out_of_range = 1; +			} else { +				amiga_chip_free(hdata->dma_bounce_buffer); +			} -	    if(!HDATA(cmd->device->host)->dma_bounce_buffer) -	    { -		HDATA(cmd->device->host)->dma_bounce_len = 0; -		return 1; -	    } +			hdata->dma_bounce_buffer = +				amiga_chip_alloc(hdata->dma_bounce_len, +						 "GVP II SCSI Bounce Buffer"); -	    addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer); -	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED; -	} -	     -	if (!dir_in) { -	    /* copy to bounce buffer for a write */ -	    memcpy (HDATA(cmd->device->host)->dma_bounce_buffer, -		    cmd->SCp.ptr, cmd->SCp.this_residual); +			if (!hdata->dma_bounce_buffer) { +				hdata->dma_bounce_len = 0; +				return 1; +			} + +			addr = virt_to_bus(hdata->dma_bounce_buffer); +			hdata->dma_buffer_pool = BUF_CHIP_ALLOCED; +		} + +		if (!dir_in) { +			/* copy to bounce buffer for a write */ +			memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr, +			       cmd->SCp.this_residual); +		}  	} -    } -    /* setup dma direction */ -    if (!dir_in) -	cntr |= GVP11_DMAC_DIR_WRITE; +	/* setup dma direction */ +	if (!dir_in) +		cntr |= GVP11_DMAC_DIR_WRITE; -    HDATA(cmd->device->host)->dma_dir = dir_in; -    DMA(cmd->device->host)->CNTR = cntr; +	hdata->dma_dir = dir_in; +	DMA(cmd->device->host)->CNTR = cntr; -    /* setup DMA *physical* address */ -    DMA(cmd->device->host)->ACR = addr; +	/* setup DMA *physical* address */ +	DMA(cmd->device->host)->ACR = addr; -    if (dir_in) -	/* invalidate any cache */ -	cache_clear (addr, cmd->SCp.this_residual); -    else -	/* push any dirty cache */ -	cache_push (addr, cmd->SCp.this_residual); +	if (dir_in) { +		/* invalidate any cache */ +		cache_clear(addr, cmd->SCp.this_residual); +	} else { +		/* push any dirty cache */ +		cache_push(addr, cmd->SCp.this_residual); +	} -    if ((bank_mask = (~HDATA(cmd->device->host)->dma_xfer_mask >> 18) & 0x01c0)) -	    DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18); +	bank_mask = (~hdata->dma_xfer_mask >> 18) & 0x01c0; +	if (bank_mask) +		DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18); -    /* start DMA */ -    DMA(cmd->device->host)->ST_DMA = 1; +	/* start DMA */ +	DMA(cmd->device->host)->ST_DMA = 1; -    /* return success */ -    return 0; +	/* return success */ +	return 0;  }  static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,  		     int status)  { -    /* stop DMA */ -    DMA(instance)->SP_DMA = 1; -    /* remove write bit from CONTROL bits */ -    DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE; +	struct WD33C93_hostdata *hdata = shost_priv(instance); + +	/* stop DMA */ +	DMA(instance)->SP_DMA = 1; +	/* remove write bit from CONTROL bits */ +	DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE; + +	/* copy from a bounce buffer, if necessary */ +	if (status && hdata->dma_bounce_buffer) { +		if (hdata->dma_dir && SCpnt) +			memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer, +			       SCpnt->SCp.this_residual); -    /* copy from a bounce buffer, if necessary */ -    if (status && HDATA(instance)->dma_bounce_buffer) { -	if (HDATA(instance)->dma_dir && SCpnt) -	    memcpy (SCpnt->SCp.ptr,  -		    HDATA(instance)->dma_bounce_buffer, -		    SCpnt->SCp.this_residual); -	 -	if (HDATA(instance)->dma_buffer_pool == BUF_SCSI_ALLOCED) -	    kfree (HDATA(instance)->dma_bounce_buffer); -	else -	    amiga_chip_free(HDATA(instance)->dma_bounce_buffer); -	 -	HDATA(instance)->dma_bounce_buffer = NULL; -	HDATA(instance)->dma_bounce_len = 0; -    } +		if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED) +			kfree(hdata->dma_bounce_buffer); +		else +			amiga_chip_free(hdata->dma_bounce_buffer); + +		hdata->dma_bounce_buffer = NULL; +		hdata->dma_bounce_len = 0; +	}  }  #define CHECK_WD33C93  int __init gvp11_detect(struct scsi_host_template *tpnt)  { -    static unsigned char called = 0; -    struct Scsi_Host *instance; -    unsigned long address; -    unsigned int epc; -    struct zorro_dev *z = NULL; -    unsigned int default_dma_xfer_mask; -    wd33c93_regs regs; -    int num_gvp11 = 0; +	static unsigned char called = 0; +	struct Scsi_Host *instance; +	unsigned long address; +	unsigned int epc; +	struct zorro_dev *z = NULL; +	unsigned int default_dma_xfer_mask; +	struct WD33C93_hostdata *hdata; +	wd33c93_regs regs; +	int num_gvp11 = 0;  #ifdef CHECK_WD33C93 -    volatile unsigned char *sasr_3393, *scmd_3393; -    unsigned char save_sasr; -    unsigned char q, qq; +	volatile unsigned char *sasr_3393, *scmd_3393; +	unsigned char save_sasr; +	unsigned char q, qq;  #endif -    if (!MACH_IS_AMIGA || called) -	return 0; -    called = 1; +	if (!MACH_IS_AMIGA || called) +		return 0; +	called = 1; -    tpnt->proc_name = "GVP11"; -    tpnt->proc_info = &wd33c93_proc_info; +	tpnt->proc_name = "GVP11"; +	tpnt->proc_info = &wd33c93_proc_info; -    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { -	/*  -	 * This should (hopefully) be the correct way to identify -	 * all the different GVP SCSI controllers (except for the -	 * SERIES I though). -	 */ +	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { +		/* +		 * This should (hopefully) be the correct way to identify +		 * all the different GVP SCSI controllers (except for the +		 * SERIES I though). +		 */ -	if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI || -	    z->id == ZORRO_PROD_GVP_SERIES_II) -	    default_dma_xfer_mask = ~0x00ffffff; -	else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI || -		 z->id == ZORRO_PROD_GVP_A530_SCSI || -		 z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI) -	    default_dma_xfer_mask = ~0x01ffffff; -	else if (z->id == ZORRO_PROD_GVP_A1291 || -		 z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1) -	    default_dma_xfer_mask = ~0x07ffffff; -	else -	    continue; +		if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI || +		    z->id == ZORRO_PROD_GVP_SERIES_II) +			default_dma_xfer_mask = ~0x00ffffff; +		else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI || +			 z->id == ZORRO_PROD_GVP_A530_SCSI || +			 z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI) +			default_dma_xfer_mask = ~0x01ffffff; +		else if (z->id == ZORRO_PROD_GVP_A1291 || +			 z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1) +			default_dma_xfer_mask = ~0x07ffffff; +		else +			continue; -	/* -	 * Rumors state that some GVP ram boards use the same product -	 * code as the SCSI controllers. Therefore if the board-size -	 * is not 64KB we asume it is a ram board and bail out. -	 */ -	if (z->resource.end-z->resource.start != 0xffff) -		continue; +		/* +		 * Rumors state that some GVP ram boards use the same product +		 * code as the SCSI controllers. Therefore if the board-size +		 * is not 64KB we asume it is a ram board and bail out. +		 */ +		if (z->resource.end - z->resource.start != 0xffff) +			continue; -	address = z->resource.start; -	if (!request_mem_region(address, 256, "wd33c93")) -	    continue; +		address = z->resource.start; +		if (!request_mem_region(address, 256, "wd33c93")) +			continue;  #ifdef CHECK_WD33C93 -	/* -	 * These darn GVP boards are a problem - it can be tough to tell -	 * whether or not they include a SCSI controller. This is the -	 * ultimate Yet-Another-GVP-Detection-Hack in that it actually -	 * probes for a WD33c93 chip: If we find one, it's extremely -	 * likely that this card supports SCSI, regardless of Product_ -	 * Code, Board_Size, etc.  -	 */ +		/* +		 * These darn GVP boards are a problem - it can be tough to tell +		 * whether or not they include a SCSI controller. This is the +		 * ultimate Yet-Another-GVP-Detection-Hack in that it actually +		 * probes for a WD33c93 chip: If we find one, it's extremely +		 * likely that this card supports SCSI, regardless of Product_ +		 * Code, Board_Size, etc. +		 */ -    /* Get pointers to the presumed register locations and save contents */ +		/* Get pointers to the presumed register locations and save contents */ -	sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR); -	scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD); -	save_sasr = *sasr_3393; +		sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR); +		scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD); +		save_sasr = *sasr_3393; -    /* First test the AuxStatus Reg */ +		/* First test the AuxStatus Reg */ -	q = *sasr_3393;		/* read it */ -	if (q & 0x08)		/* bit 3 should always be clear */ -		goto release; -	*sasr_3393 = WD_AUXILIARY_STATUS;	 /* setup indirect address */ -	if (*sasr_3393 == WD_AUXILIARY_STATUS) { /* shouldn't retain the write */ -		*sasr_3393 = save_sasr;	/* Oops - restore this byte */ -		goto release; +		q = *sasr_3393;	/* read it */ +		if (q & 0x08)	/* bit 3 should always be clear */ +			goto release; +		*sasr_3393 = WD_AUXILIARY_STATUS;	/* setup indirect address */ +		if (*sasr_3393 == WD_AUXILIARY_STATUS) {	/* shouldn't retain the write */ +			*sasr_3393 = save_sasr;	/* Oops - restore this byte */ +			goto release;  		} -	if (*sasr_3393 != q) {	/* should still read the same */ -		*sasr_3393 = save_sasr;	/* Oops - restore this byte */ -		goto release; +		if (*sasr_3393 != q) {	/* should still read the same */ +			*sasr_3393 = save_sasr;	/* Oops - restore this byte */ +			goto release;  		} -	if (*scmd_3393 != q)	/* and so should the image at 0x1f */ -		goto release; - +		if (*scmd_3393 != q)	/* and so should the image at 0x1f */ +			goto release; -    /* Ok, we probably have a wd33c93, but let's check a few other places -     * for good measure. Make sure that this works for both 'A and 'B     -     * chip versions. -     */ +		/* +		 * Ok, we probably have a wd33c93, but let's check a few other places +		 * for good measure. Make sure that this works for both 'A and 'B +		 * chip versions. +		 */ -	*sasr_3393 = WD_SCSI_STATUS; -	q = *scmd_3393; -	*sasr_3393 = WD_SCSI_STATUS; -	*scmd_3393 = ~q; -	*sasr_3393 = WD_SCSI_STATUS; -	qq = *scmd_3393; -	*sasr_3393 = WD_SCSI_STATUS; -	*scmd_3393 = q; -	if (qq != q)			/* should be read only */ -		goto release; -	*sasr_3393 = 0x1e;	/* this register is unimplemented */ -	q = *scmd_3393; -	*sasr_3393 = 0x1e; -	*scmd_3393 = ~q; -	*sasr_3393 = 0x1e; -	qq = *scmd_3393; -	*sasr_3393 = 0x1e; -	*scmd_3393 = q; -	if (qq != q || qq != 0xff)	/* should be read only, all 1's */ -		goto release; -	*sasr_3393 = WD_TIMEOUT_PERIOD; -	q = *scmd_3393; -	*sasr_3393 = WD_TIMEOUT_PERIOD; -	*scmd_3393 = ~q; -	*sasr_3393 = WD_TIMEOUT_PERIOD; -	qq = *scmd_3393; -	*sasr_3393 = WD_TIMEOUT_PERIOD; -	*scmd_3393 = q; -	if (qq != (~q & 0xff))		/* should be read/write */ -		goto release; +		*sasr_3393 = WD_SCSI_STATUS; +		q = *scmd_3393; +		*sasr_3393 = WD_SCSI_STATUS; +		*scmd_3393 = ~q; +		*sasr_3393 = WD_SCSI_STATUS; +		qq = *scmd_3393; +		*sasr_3393 = WD_SCSI_STATUS; +		*scmd_3393 = q; +		if (qq != q)	/* should be read only */ +			goto release; +		*sasr_3393 = 0x1e;	/* this register is unimplemented */ +		q = *scmd_3393; +		*sasr_3393 = 0x1e; +		*scmd_3393 = ~q; +		*sasr_3393 = 0x1e; +		qq = *scmd_3393; +		*sasr_3393 = 0x1e; +		*scmd_3393 = q; +		if (qq != q || qq != 0xff)	/* should be read only, all 1's */ +			goto release; +		*sasr_3393 = WD_TIMEOUT_PERIOD; +		q = *scmd_3393; +		*sasr_3393 = WD_TIMEOUT_PERIOD; +		*scmd_3393 = ~q; +		*sasr_3393 = WD_TIMEOUT_PERIOD; +		qq = *scmd_3393; +		*sasr_3393 = WD_TIMEOUT_PERIOD; +		*scmd_3393 = q; +		if (qq != (~q & 0xff))	/* should be read/write */ +			goto release;  #endif -	instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata)); -	if(instance == NULL) -		goto release; -	instance->base = ZTWO_VADDR(address); -	instance->irq = IRQ_AMIGA_PORTS; -	instance->unique_id = z->slotaddr; +		instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata)); +		if (instance == NULL) +			goto release; +		instance->base = ZTWO_VADDR(address); +		instance->irq = IRQ_AMIGA_PORTS; +		instance->unique_id = z->slotaddr; -	if (gvp11_xfer_mask) -		HDATA(instance)->dma_xfer_mask = gvp11_xfer_mask; -	else -		HDATA(instance)->dma_xfer_mask = default_dma_xfer_mask; +		hdata = shost_priv(instance); +		if (gvp11_xfer_mask) +			hdata->dma_xfer_mask = gvp11_xfer_mask; +		else +			hdata->dma_xfer_mask = default_dma_xfer_mask; +		DMA(instance)->secret2 = 1; +		DMA(instance)->secret1 = 0; +		DMA(instance)->secret3 = 15; +		while (DMA(instance)->CNTR & GVP11_DMAC_BUSY) +			; +		DMA(instance)->CNTR = 0; -	DMA(instance)->secret2 = 1; -	DMA(instance)->secret1 = 0; -	DMA(instance)->secret3 = 15; -	while (DMA(instance)->CNTR & GVP11_DMAC_BUSY) ; -	DMA(instance)->CNTR = 0; - -	DMA(instance)->BANK = 0; +		DMA(instance)->BANK = 0; -	epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000); +		epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000); -	/* -	 * Check for 14MHz SCSI clock -	 */ -	regs.SASR = &(DMA(instance)->SASR); -	regs.SCMD = &(DMA(instance)->SCMD); -	HDATA(instance)->no_sync = 0xff; -	HDATA(instance)->fast = 0; -	HDATA(instance)->dma_mode = CTRL_DMA; -	wd33c93_init(instance, regs, dma_setup, dma_stop, -		     (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10 -					     : WD33C93_FS_12_15); +		/* +		 * Check for 14MHz SCSI clock +		 */ +		regs.SASR = &(DMA(instance)->SASR); +		regs.SCMD = &(DMA(instance)->SCMD); +		hdata->no_sync = 0xff; +		hdata->fast = 0; +		hdata->dma_mode = CTRL_DMA; +		wd33c93_init(instance, regs, dma_setup, dma_stop, +			     (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10 +						     : WD33C93_FS_12_15); -	if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, "GVP11 SCSI", -			instance)) -		goto unregister; -	DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE; -	num_gvp11++; -	continue; +		if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, +				"GVP11 SCSI", instance)) +			goto unregister; +		DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE; +		num_gvp11++; +		continue;  unregister: -	scsi_unregister(instance); -	wd33c93_release(); +		scsi_unregister(instance);  release: -	release_mem_region(address, 256); -    } +		release_mem_region(address, 256); +	} -    return num_gvp11; +	return num_gvp11;  }  static int gvp11_bus_reset(struct scsi_cmnd *cmd) @@ -389,12 +391,11 @@ static struct scsi_host_template driver_template = {  int gvp11_release(struct Scsi_Host *instance)  {  #ifdef MODULE -    DMA(instance)->CNTR = 0; -    release_mem_region(ZTWO_PADDR(instance->base), 256); -    free_irq(IRQ_AMIGA_PORTS, instance); -    wd33c93_release(); +	DMA(instance)->CNTR = 0; +	release_mem_region(ZTWO_PADDR(instance->base), 256); +	free_irq(IRQ_AMIGA_PORTS, instance);  #endif -    return 1; +	return 1;  }  MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h index bf22859a503..e2efdf9601e 100644 --- a/drivers/scsi/gvp11.h +++ b/drivers/scsi/gvp11.h @@ -15,11 +15,11 @@ int gvp11_detect(struct scsi_host_template *);  int gvp11_release(struct Scsi_Host *);  #ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 +#define CMD_PER_LUN		2  #endif  #ifndef CAN_QUEUE -#define CAN_QUEUE 16 +#define CAN_QUEUE		16  #endif  #ifndef HOSTS_C @@ -28,24 +28,24 @@ int gvp11_release(struct Scsi_Host *);   * if the transfer address ANDed with this results in a non-zero   * result, then we can't use DMA.   */ -#define GVP11_XFER_MASK  (0xff000001) +#define GVP11_XFER_MASK		(0xff000001)  typedef struct { -             unsigned char      pad1[64]; -    volatile unsigned short     CNTR; -             unsigned char      pad2[31]; -    volatile unsigned char      SASR; -             unsigned char      pad3; -    volatile unsigned char      SCMD; -             unsigned char      pad4[4]; -    volatile unsigned short     BANK; -             unsigned char      pad5[6]; -    volatile unsigned long      ACR; -    volatile unsigned short     secret1; /* store 0 here */ -    volatile unsigned short     ST_DMA; -    volatile unsigned short     SP_DMA; -    volatile unsigned short     secret2; /* store 1 here */ -    volatile unsigned short     secret3; /* store 15 here */ +		 unsigned char	pad1[64]; +	volatile unsigned short	CNTR; +		 unsigned char	pad2[31]; +	volatile unsigned char	SASR; +		 unsigned char	pad3; +	volatile unsigned char	SCMD; +		 unsigned char	pad4[4]; +	volatile unsigned short	BANK; +		 unsigned char	pad5[6]; +	volatile unsigned long	ACR; +	volatile unsigned short	secret1; /* store 0 here */ +	volatile unsigned short	ST_DMA; +	volatile unsigned short	SP_DMA; +	volatile unsigned short	secret2; /* store 1 here */ +	volatile unsigned short	secret3; /* store 15 here */  } gvp11_scsiregs;  /* bits in CNTR */ diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 183d3a43c28..c016426b31b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2708,14 +2708,6 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,  			c->Request.CDB[8] = (size >> 8) & 0xFF;  			c->Request.CDB[9] = size & 0xFF;  			break; - -		case HPSA_READ_CAPACITY: -			c->Request.CDBLen = 10; -			c->Request.Type.Attribute = ATTR_SIMPLE; -			c->Request.Type.Direction = XFER_READ; -			c->Request.Timeout = 0; -			c->Request.CDB[0] = cmd; -			break;  		case HPSA_CACHE_FLUSH:  			c->Request.CDBLen = 12;  			c->Request.Type.Attribute = ATTR_SIMPLE; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 56fb9827681..78de9b6d1e0 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -152,21 +152,6 @@ struct SenseSubsystem_info {  	u8 reserved1[1108];  }; -#define HPSA_READ_CAPACITY 0x25 /* Read Capacity */ -struct ReadCapdata { -	u8 total_size[4];	/* Total size in blocks */ -	u8 block_size[4];	/* Size of blocks in bytes */ -}; - -#if 0 -/* 12 byte commands not implemented in firmware yet. */ -#define HPSA_READ 	0xa8 -#define HPSA_WRITE	0xaa -#endif - -#define HPSA_READ   0x28    /* Read(10) */ -#define HPSA_WRITE  0x2a    /* Write(10) */ -  /* BMIC commands */  #define BMIC_READ 0x26  #define BMIC_WRITE 0x27 diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index c2eea711a5c..d18f45c9563 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -2245,7 +2245,7 @@ static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device,  	DECLARE_COMPLETION_ONSTACK(comp);  	int wait;  	unsigned long flags; -	signed long timeout = init_timeout * HZ; +	signed long timeout = IBMVFC_ABORT_WAIT_TIMEOUT * HZ;  	ENTER;  	do { @@ -3013,6 +3013,7 @@ static struct ibmvfc_async_crq *ibmvfc_next_async_crq(struct ibmvfc_host *vhost)  	if (crq->valid & 0x80) {  		if (++async_crq->cur == async_crq->size)  			async_crq->cur = 0; +		rmb();  	} else  		crq = NULL; @@ -3035,6 +3036,7 @@ static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost)  	if (crq->valid & 0x80) {  		if (++queue->cur == queue->size)  			queue->cur = 0; +		rmb();  	} else  		crq = NULL; @@ -3083,12 +3085,14 @@ static void ibmvfc_tasklet(void *data)  		while ((async = ibmvfc_next_async_crq(vhost)) != NULL) {  			ibmvfc_handle_async(async, vhost);  			async->valid = 0; +			wmb();  		}  		/* Pull all the valid messages off the CRQ */  		while ((crq = ibmvfc_next_crq(vhost)) != NULL) {  			ibmvfc_handle_crq(crq, vhost);  			crq->valid = 0; +			wmb();  		}  		vio_enable_interrupts(vdev); @@ -3096,10 +3100,12 @@ static void ibmvfc_tasklet(void *data)  			vio_disable_interrupts(vdev);  			ibmvfc_handle_async(async, vhost);  			async->valid = 0; +			wmb();  		} else if ((crq = ibmvfc_next_crq(vhost)) != NULL) {  			vio_disable_interrupts(vdev);  			ibmvfc_handle_crq(crq, vhost);  			crq->valid = 0; +			wmb();  		} else  			done = 1;  	} diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index d25106a958d..7e9742764e4 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -38,6 +38,7 @@  #define IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT	\  		(IBMVFC_ADISC_TIMEOUT + IBMVFC_ADISC_CANCEL_TIMEOUT)  #define IBMVFC_INIT_TIMEOUT		120 +#define IBMVFC_ABORT_WAIT_TIMEOUT	40  #define IBMVFC_MAX_REQUESTS_DEFAULT	100  #define IBMVFC_DEBUG			0 diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 02143af7c1a..cdb4fd8cf23 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -206,8 +206,10 @@ static void iscsi_sw_tcp_conn_set_callbacks(struct iscsi_conn *conn)  }  static void -iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_sw_tcp_conn *tcp_sw_conn) +iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn)  { +	struct iscsi_tcp_conn *tcp_conn = conn->dd_data; +	struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;  	struct sock *sk = tcp_sw_conn->sock->sk;  	/* restore socket callbacks, see also: iscsi_conn_set_callbacks() */ @@ -555,7 +557,7 @@ static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn)  		return;  	sock_hold(sock->sk); -	iscsi_sw_tcp_conn_restore_callbacks(tcp_sw_conn); +	iscsi_sw_tcp_conn_restore_callbacks(conn);  	sock_put(sock->sk);  	spin_lock_bh(&session->lock); diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index ca6b7bc64de..94644bad0ed 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -36,7 +36,6 @@ struct iscsi_sw_tcp_send {  };  struct iscsi_sw_tcp_conn { -	struct iscsi_conn	*iscsi_conn;  	struct socket		*sock;  	struct iscsi_sw_tcp_send out; diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 1087a7f18e8..c7985da8809 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -132,7 +132,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,  		switch (fmt) {  		case ELS_ADDR_FMT_PORT:  			FC_DISC_DBG(disc, "Port address format for port " -				    "(%6x)\n", ntoh24(pp->rscn_fid)); +				    "(%6.6x)\n", ntoh24(pp->rscn_fid));  			dp = kzalloc(sizeof(*dp), GFP_KERNEL);  			if (!dp) {  				redisc = 1; @@ -440,7 +440,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)  		ids.port_id = ntoh24(np->fp_fid);  		ids.port_name = ntohll(np->fp_wwpn); -		if (ids.port_id != fc_host_port_id(lport->host) && +		if (ids.port_id != lport->port_id &&  		    ids.port_name != lport->wwpn) {  			rdata = lport->tt.rport_create(lport, ids.port_id);  			if (rdata) { @@ -449,7 +449,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)  			} else {  				printk(KERN_WARNING "libfc: Failed to allocate "  				       "memory for the newly discovered port " -				       "(%6x)\n", ids.port_id); +				       "(%6.6x)\n", ids.port_id);  				error = -ENOMEM;  			}  		} @@ -607,7 +607,7 @@ static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,  			rdata->ids.port_name = port_name;  		else if (rdata->ids.port_name != port_name) {  			FC_DISC_DBG(disc, "GPN_ID accepted.  WWPN changed. " -				    "Port-id %x wwpn %llx\n", +				    "Port-id %6.6x wwpn %16.16llx\n",  				    rdata->ids.port_id, port_name);  			lport->tt.rport_logoff(rdata); diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index 53748724f2c..e9412b710fa 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -63,7 +63,7 @@ struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did,  		return NULL;  	} -	fc_fill_fc_hdr(fp, r_ctl, did, fc_host_port_id(lport->host), fh_type, +	fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type,  		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);  	return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec); diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index e5df0d4db67..104e0fba7c4 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -488,7 +488,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,  	 */  	spin_lock_bh(&ep->ex_lock);  	ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ;	/* not first seq */ -	if (f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT)) +	if (f_ctl & FC_FC_SEQ_INIT)  		ep->esb_stat &= ~ESB_ST_SEQ_INIT;  	spin_unlock_bh(&ep->ex_lock);  	return error; @@ -676,9 +676,10 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,  	}  	memset(ep, 0, sizeof(*ep)); -	cpu = smp_processor_id(); +	cpu = get_cpu();  	pool = per_cpu_ptr(mp->pool, cpu);  	spin_lock_bh(&pool->lock); +	put_cpu();  	index = pool->next_index;  	/* allocate new exch from pool */  	while (fc_exch_ptr_get(pool, index)) { @@ -734,19 +735,14 @@ err:   * EM is selected when a NULL match function pointer is encountered   * or when a call to a match function returns true.   */ -static struct fc_exch *fc_exch_alloc(struct fc_lport *lport, -				     struct fc_frame *fp) +static inline struct fc_exch *fc_exch_alloc(struct fc_lport *lport, +					    struct fc_frame *fp)  {  	struct fc_exch_mgr_anchor *ema; -	struct fc_exch *ep; -	list_for_each_entry(ema, &lport->ema_list, ema_list) { -		if (!ema->match || ema->match(fp)) { -			ep = fc_exch_em_alloc(lport, ema->mp); -			if (ep) -				return ep; -		} -	} +	list_for_each_entry(ema, &lport->ema_list, ema_list) +		if (!ema->match || ema->match(fp)) +			return fc_exch_em_alloc(lport, ema->mp);  	return NULL;  } @@ -920,13 +916,9 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport,  	 * Find or create the sequence.  	 */  	if (fc_sof_is_init(fr_sof(fp))) { -		sp = fc_seq_start_next(&ep->seq); -		if (!sp) { -			reject = FC_RJT_SEQ_XS;	/* exchange shortage */ -			goto rel; -		} -		sp->id = fh->fh_seq_id; +		sp = &ep->seq;  		sp->ssb_stat |= SSB_ST_RESP; +		sp->id = fh->fh_seq_id;  	} else {  		sp = &ep->seq;  		if (sp->id != fh->fh_seq_id) { @@ -1250,9 +1242,6 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,  	struct fc_frame_header *fh = fc_frame_header_get(fp);  	struct fc_seq *sp = NULL;  	struct fc_exch *ep = NULL; -	enum fc_sof sof; -	enum fc_eof eof; -	u32 f_ctl;  	enum fc_pf_rjt_reason reject;  	/* We can have the wrong fc_lport at this point with NPIV, which is a @@ -1269,9 +1258,6 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,  	if (reject == FC_RJT_NONE) {  		sp = fr_seq(fp);	/* sequence will be held */  		ep = fc_seq_exch(sp); -		sof = fr_sof(fp); -		eof = fr_eof(fp); -		f_ctl = ntoh24(fh->fh_f_ctl);  		fc_seq_send_ack(sp, fp);  		/* @@ -1336,17 +1322,15 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)  		goto rel;  	}  	sof = fr_sof(fp); +	sp = &ep->seq;  	if (fc_sof_is_init(sof)) { -		sp = fc_seq_start_next(&ep->seq); -		sp->id = fh->fh_seq_id;  		sp->ssb_stat |= SSB_ST_RESP; -	} else { -		sp = &ep->seq; -		if (sp->id != fh->fh_seq_id) { -			atomic_inc(&mp->stats.seq_not_found); -			goto rel; -		} +		sp->id = fh->fh_seq_id; +	} else if (sp->id != fh->fh_seq_id) { +		atomic_inc(&mp->stats.seq_not_found); +		goto rel;  	} +  	f_ctl = ntoh24(fh->fh_f_ctl);  	fr_seq(fp) = sp;  	if (f_ctl & FC_FC_SEQ_INIT) @@ -1763,7 +1747,6 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)  		fc_exch_done(sp);  		goto out;  	} -	sp = fc_seq_start_next(sp);  	acc = fc_frame_payload_get(fp, sizeof(*acc));  	memset(acc, 0, sizeof(*acc));  	acc->reca_cmd = ELS_LS_ACC; @@ -1944,7 +1927,7 @@ static void fc_exch_rrq(struct fc_exch *ep)  		did = ep->sid;  	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, did, -		       fc_host_port_id(lport->host), FC_TYPE_ELS, +		       lport->port_id, FC_TYPE_ELS,  		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);  	if (fc_exch_seq_send(lport, fp, fc_exch_rrq_resp, NULL, ep, diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 17396c708b0..ec1f66c4a9d 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -97,7 +97,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *);  static void fc_fcp_complete_locked(struct fc_fcp_pkt *);  static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *);  static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *); -static void fc_timeout_error(struct fc_fcp_pkt *); +static void fc_fcp_recovery(struct fc_fcp_pkt *);  static void fc_fcp_timeout(unsigned long);  static void fc_fcp_rec(struct fc_fcp_pkt *);  static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *); @@ -121,7 +121,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *);  #define FC_DATA_UNDRUN		7  #define FC_ERROR		8  #define FC_HRD_ERROR		9 -#define FC_CMD_TIME_OUT		10 +#define FC_CMD_RECOVERY		10  /*   * Error recovery timeout values. @@ -446,9 +446,16 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)  	len = fr_len(fp) - sizeof(*fh);  	buf = fc_frame_payload_get(fp, 0); -	/* if this I/O is ddped, update xfer len */ -	fc_fcp_ddp_done(fsp); - +	/* +	 * if this I/O is ddped then clear it +	 * and initiate recovery since data +	 * frames are expected to be placed +	 * directly in that case. +	 */ +	if (fsp->xfer_ddp != FC_XID_UNKNOWN) { +		fc_fcp_ddp_done(fsp); +		goto err; +	}  	if (offset + len > fsp->data_len) {  		/* this should never happen */  		if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) && @@ -456,8 +463,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)  			goto crc_err;  		FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx "  			   "data_len %x\n", len, offset, fsp->data_len); -		fc_fcp_retry_cmd(fsp); -		return; +		goto err;  	}  	if (offset != fsp->xfer_len)  		fsp->state |= FC_SRB_DISCONTIG; @@ -478,13 +484,14 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)  		if (~crc != le32_to_cpu(fr_crc(fp))) {  crc_err: -			stats = fc_lport_get_stats(lport); +			stats = per_cpu_ptr(lport->dev_stats, get_cpu());  			stats->ErrorFrames++; -			/* FIXME - per cpu count, not total count! */ +			/* per cpu count, not total count, but OK for limit */  			if (stats->InvalidCRCCount++ < 5)  				printk(KERN_WARNING "libfc: CRC error on data " -				       "frame for port (%6x)\n", -				       fc_host_port_id(lport->host)); +				       "frame for port (%6.6x)\n", +				       lport->port_id); +			put_cpu();  			/*  			 * Assume the frame is total garbage.  			 * We may have copied it over the good part @@ -493,7 +500,7 @@ crc_err:  			 * Otherwise, ignore it.  			 */  			if (fsp->state & FC_SRB_DISCONTIG) -				fc_fcp_retry_cmd(fsp); +				goto err;  			return;  		}  	} @@ -509,6 +516,9 @@ crc_err:  	if (unlikely(fsp->state & FC_SRB_RCV_STATUS) &&  	    fsp->xfer_len == fsp->data_len - fsp->scsi_resid)  		fc_fcp_complete_locked(fsp); +	return; +err: +	fc_fcp_recovery(fsp);  }  /** @@ -834,8 +844,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)  					 * exit here  					 */  					return; -				} else -					goto err; +				}  			}  			if (flags & FCP_SNS_LEN_VAL) {  				snsl = ntohl(rp_ex->fr_sns_len); @@ -885,7 +894,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)  			return;  		}  		fsp->status_code = FC_DATA_OVRRUN; -		FC_FCP_DBG(fsp, "tgt %6x xfer len %zx greater than expected, " +		FC_FCP_DBG(fsp, "tgt %6.6x xfer len %zx greater than expected, "  			   "len %x, data len %x\n",  			   fsp->rport->port_id,  			   fsp->xfer_len, expected_len, fsp->data_len); @@ -1100,7 +1109,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,  	rpriv = rport->dd_data;  	fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id, -		       fc_host_port_id(rpriv->local_port->host), FC_TYPE_FCP, +		       rpriv->local_port->port_id, FC_TYPE_FCP,  		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);  	seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy, @@ -1341,7 +1350,7 @@ static void fc_fcp_timeout(unsigned long data)  	else if (fsp->state & FC_SRB_RCV_STATUS)  		fc_fcp_complete_locked(fsp);  	else -		fc_timeout_error(fsp); +		fc_fcp_recovery(fsp);  	fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO;  unlock:  	fc_fcp_unlock_pkt(fsp); @@ -1373,7 +1382,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)  	fr_seq(fp) = fsp->seq_ptr;  	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id, -		       fc_host_port_id(rpriv->local_port->host), FC_TYPE_ELS, +		       rpriv->local_port->port_id, FC_TYPE_ELS,  		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);  	if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC,  				 fc_fcp_rec_resp, fsp, @@ -1385,7 +1394,7 @@ retry:  	if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)  		fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);  	else -		fc_timeout_error(fsp); +		fc_fcp_recovery(fsp);  }  /** @@ -1454,7 +1463,7 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)  				fc_fcp_retry_cmd(fsp);  				break;  			} -			fc_timeout_error(fsp); +			fc_fcp_recovery(fsp);  			break;  		}  	} else if (opcode == ELS_LS_ACC) { @@ -1553,7 +1562,7 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)  		break;  	default: -		FC_FCP_DBG(fsp, "REC %p fid %x error unexpected error %d\n", +		FC_FCP_DBG(fsp, "REC %p fid %6.6x error unexpected error %d\n",  			   fsp, fsp->rport->port_id, error);  		fsp->status_code = FC_CMD_PLOGO;  		/* fall through */ @@ -1563,13 +1572,13 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)  		 * Assume REC or LS_ACC was lost.  		 * The exchange manager will have aborted REC, so retry.  		 */ -		FC_FCP_DBG(fsp, "REC fid %x error error %d retry %d/%d\n", +		FC_FCP_DBG(fsp, "REC fid %6.6x error error %d retry %d/%d\n",  			   fsp->rport->port_id, error, fsp->recov_retry,  			   FC_MAX_RECOV_RETRY);  		if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)  			fc_fcp_rec(fsp);  		else -			fc_timeout_error(fsp); +			fc_fcp_recovery(fsp);  		break;  	}  	fc_fcp_unlock_pkt(fsp); @@ -1578,12 +1587,12 @@ out:  }  /** - * fc_timeout_error() - Handler for fcp_pkt timeouts - * @fsp: The FCP packt that has timed out + * fc_fcp_recovery() - Handler for fcp_pkt recovery + * @fsp: The FCP pkt that needs to be aborted   */ -static void fc_timeout_error(struct fc_fcp_pkt *fsp) +static void fc_fcp_recovery(struct fc_fcp_pkt *fsp)  { -	fsp->status_code = FC_CMD_TIME_OUT; +	fsp->status_code = FC_CMD_RECOVERY;  	fsp->cdb_status = 0;  	fsp->io_status = 0;  	/* @@ -1631,7 +1640,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)  	srr->srr_rel_off = htonl(offset);  	fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id, -		       fc_host_port_id(rpriv->local_port->host), FC_TYPE_FCP, +		       rpriv->local_port->port_id, FC_TYPE_FCP,  		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);  	seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL, @@ -1689,7 +1698,7 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)  		break;  	case ELS_LS_RJT:  	default: -		fc_timeout_error(fsp); +		fc_fcp_recovery(fsp);  		break;  	}  	fc_fcp_unlock_pkt(fsp); @@ -1715,7 +1724,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)  		if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)  			fc_fcp_rec(fsp);  		else -			fc_timeout_error(fsp); +			fc_fcp_recovery(fsp);  		break;  	case -FC_EX_CLOSED:			/* e.g., link failure */  		/* fall through */ @@ -1810,7 +1819,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))  	/*  	 * setup the data direction  	 */ -	stats = fc_lport_get_stats(lport); +	stats = per_cpu_ptr(lport->dev_stats, get_cpu());  	if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {  		fsp->req_flags = FC_SRB_READ;  		stats->InputRequests++; @@ -1823,6 +1832,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))  		fsp->req_flags = 0;  		stats->ControlRequests++;  	} +	put_cpu();  	fsp->tgt_flags = rpriv->flags; @@ -1907,6 +1917,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)  		}  		break;  	case FC_ERROR: +		FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " +			   "due to FC_ERROR\n");  		sc_cmd->result = DID_ERROR << 16;  		break;  	case FC_DATA_UNDRUN: @@ -1915,12 +1927,19 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)  			 * scsi status is good but transport level  			 * underrun.  			 */ -			sc_cmd->result = (fsp->state & FC_SRB_RCV_STATUS ? -					  DID_OK : DID_ERROR) << 16; +			if (fsp->state & FC_SRB_RCV_STATUS) { +				sc_cmd->result = DID_OK << 16; +			} else { +				FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml" +					   " due to FC_DATA_UNDRUN (trans)\n"); +				sc_cmd->result = DID_ERROR << 16; +			}  		} else {  			/*  			 * scsi got underrun, this is an error  			 */ +			FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " +				   "due to FC_DATA_UNDRUN (scsi)\n");  			CMD_RESID_LEN(sc_cmd) = fsp->scsi_resid;  			sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status;  		} @@ -1929,12 +1948,16 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)  		/*  		 * overrun is an error  		 */ +		FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " +			   "due to FC_DATA_OVRRUN\n");  		sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status;  		break;  	case FC_CMD_ABORTED: +		FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " +			   "due to FC_CMD_ABORTED\n");  		sc_cmd->result = (DID_ERROR << 16) | fsp->io_status;  		break; -	case FC_CMD_TIME_OUT: +	case FC_CMD_RECOVERY:  		sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;  		break;  	case FC_CMD_RESET: @@ -1944,6 +1967,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)  		sc_cmd->result = (DID_NO_CONNECT << 16);  		break;  	default: +		FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " +			   "due to unknown error\n");  		sc_cmd->result = (DID_ERROR << 16);  		break;  	} @@ -2028,7 +2053,7 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)  	if (lport->state != LPORT_ST_READY)  		return rc; -	FC_SCSI_DBG(lport, "Resetting rport (%6x)\n", rport->port_id); +	FC_SCSI_DBG(lport, "Resetting rport (%6.6x)\n", rport->port_id);  	fsp = fc_fcp_pkt_alloc(lport, GFP_NOIO);  	if (fsp == NULL) { @@ -2076,12 +2101,12 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd)  	if (fc_fcp_lport_queue_ready(lport)) {  		shost_printk(KERN_INFO, shost, "libfc: Host reset succeeded " -			     "on port (%6x)\n", fc_host_port_id(lport->host)); +			     "on port (%6.6x)\n", lport->port_id);  		return SUCCESS;  	} else {  		shost_printk(KERN_INFO, shost, "libfc: Host reset failed, " -			     "port (%6x) is not ready.\n", -			     fc_host_port_id(lport->host)); +			     "port (%6.6x) is not ready.\n", +			     lport->port_id);  		return FAILED;  	}  } @@ -2166,7 +2191,7 @@ void fc_fcp_destroy(struct fc_lport *lport)  	if (!list_empty(&si->scsi_pkt_queue))  		printk(KERN_ERR "libfc: Leaked SCSI packets when destroying " -		       "port (%6x)\n", fc_host_port_id(lport->host)); +		       "port (%6.6x)\n", lport->port_id);  	mempool_destroy(si->scsi_pkt_pool);  	kfree(si); diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h index 741fd5c72e1..f5c0ca4b6ef 100644 --- a/drivers/scsi/libfc/fc_libfc.h +++ b/drivers/scsi/libfc/fc_libfc.h @@ -45,9 +45,9 @@ extern unsigned int fc_debug_logging;  #define FC_LPORT_DBG(lport, fmt, args...)				\  	FC_CHECK_LOGGING(FC_LPORT_LOGGING,				\ -			 printk(KERN_INFO "host%u: lport %6x: " fmt,	\ +			 printk(KERN_INFO "host%u: lport %6.6x: " fmt,	\  				(lport)->host->host_no,			\ -				fc_host_port_id((lport)->host), ##args)) +				(lport)->port_id, ##args))  #define FC_DISC_DBG(disc, fmt, args...)				\  	FC_CHECK_LOGGING(FC_DISC_LOGGING,			\ @@ -57,7 +57,7 @@ extern unsigned int fc_debug_logging;  #define FC_RPORT_ID_DBG(lport, port_id, fmt, args...)			\  	FC_CHECK_LOGGING(FC_RPORT_LOGGING,				\ -			 printk(KERN_INFO "host%u: rport %6x: " fmt,	\ +			 printk(KERN_INFO "host%u: rport %6.6x: " fmt,	\  				(lport)->host->host_no,			\  				(port_id), ##args)) @@ -66,7 +66,7 @@ extern unsigned int fc_debug_logging;  #define FC_FCP_DBG(pkt, fmt, args...)					\  	FC_CHECK_LOGGING(FC_FCP_LOGGING,				\ -			 printk(KERN_INFO "host%u: fcp: %6x: " fmt,	\ +			 printk(KERN_INFO "host%u: fcp: %6.6x: " fmt,	\  				(pkt)->lp->host->host_no,		\  				pkt->rport->port_id, ##args)) diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index d126ecfff70..79c9e3ccd34 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -172,7 +172,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,  				    struct fc_rport_priv *rdata,  				    enum fc_rport_event event)  { -	FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event, +	FC_LPORT_DBG(lport, "Received a %d event for port (%6.6x)\n", event,  		     rdata->ids.port_id);  	mutex_lock(&lport->lp_mutex); @@ -183,7 +183,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,  			fc_lport_enter_ns(lport, LPORT_ST_RNN_ID);  		} else {  			FC_LPORT_DBG(lport, "Received an READY event " -				     "on port (%6x) for the directory " +				     "on port (%6.6x) for the directory "  				     "server, but the lport is not "  				     "in the DNS state, it's in the "  				     "%d state", rdata->ids.port_id, @@ -228,9 +228,12 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,  			       u64 remote_wwnn)  {  	mutex_lock(&lport->disc.disc_mutex); -	if (lport->ptp_rdata) +	if (lport->ptp_rdata) {  		lport->tt.rport_logoff(lport->ptp_rdata); +		kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy); +	}  	lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid); +	kref_get(&lport->ptp_rdata->kref);  	lport->ptp_rdata->ids.port_name = remote_wwpn;  	lport->ptp_rdata->ids.node_name = remote_wwnn;  	mutex_unlock(&lport->disc.disc_mutex); @@ -241,17 +244,6 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,  }  /** - * fc_get_host_port_type() - Return the port type of the given Scsi_Host - * @shost: The SCSI host whose port type is to be determined - */ -void fc_get_host_port_type(struct Scsi_Host *shost) -{ -	/* TODO - currently just NPORT */ -	fc_host_port_type(shost) = FC_PORTTYPE_NPORT; -} -EXPORT_SYMBOL(fc_get_host_port_type); - -/**   * fc_get_host_port_state() - Return the port state of the given Scsi_Host   * @shost:  The SCSI host whose port state is to be determined   */ @@ -572,8 +564,8 @@ void __fc_linkup(struct fc_lport *lport)   */  void fc_linkup(struct fc_lport *lport)  { -	printk(KERN_INFO "host%d: libfc: Link up on port (%6x)\n", -	       lport->host->host_no, fc_host_port_id(lport->host)); +	printk(KERN_INFO "host%d: libfc: Link up on port (%6.6x)\n", +	       lport->host->host_no, lport->port_id);  	mutex_lock(&lport->lp_mutex);  	__fc_linkup(lport); @@ -602,8 +594,8 @@ void __fc_linkdown(struct fc_lport *lport)   */  void fc_linkdown(struct fc_lport *lport)  { -	printk(KERN_INFO "host%d: libfc: Link down on port (%6x)\n", -	       lport->host->host_no, fc_host_port_id(lport->host)); +	printk(KERN_INFO "host%d: libfc: Link down on port (%6.6x)\n", +	       lport->host->host_no, lport->port_id);  	mutex_lock(&lport->lp_mutex);  	__fc_linkdown(lport); @@ -704,8 +696,8 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)  		break;  	case DISC_EV_FAILED:  		printk(KERN_ERR "host%d: libfc: " -		       "Discovery failed for port (%6x)\n", -		       lport->host->host_no, fc_host_port_id(lport->host)); +		       "Discovery failed for port (%6.6x)\n", +		       lport->host->host_no, lport->port_id);  		mutex_lock(&lport->lp_mutex);  		fc_lport_enter_reset(lport);  		mutex_unlock(&lport->lp_mutex); @@ -750,10 +742,14 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id,  				 struct fc_frame *fp)  {  	if (port_id) -		printk(KERN_INFO "host%d: Assigned Port ID %6x\n", +		printk(KERN_INFO "host%d: Assigned Port ID %6.6x\n",  		       lport->host->host_no, port_id); +	lport->port_id = port_id; + +	/* Update the fc_host */  	fc_host_port_id(lport->host) = port_id; +  	if (lport->tt.lport_set_port_id)  		lport->tt.lport_set_port_id(lport, port_id, fp);  } @@ -797,11 +793,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,  	remote_wwpn = get_unaligned_be64(&flp->fl_wwpn);  	if (remote_wwpn == lport->wwpn) {  		printk(KERN_WARNING "host%d: libfc: Received FLOGI from port " -		       "with same WWPN %llx\n", +		       "with same WWPN %16.16llx\n",  		       lport->host->host_no, remote_wwpn);  		goto out;  	} -	FC_LPORT_DBG(lport, "FLOGI from port WWPN %llx\n", remote_wwpn); +	FC_LPORT_DBG(lport, "FLOGI from port WWPN %16.16llx\n", remote_wwpn);  	/*  	 * XXX what is the right thing to do for FIDs? @@ -832,7 +828,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,  		 */  		f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;  		ep = fc_seq_exch(sp); -		fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, +		fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, remote_fid, local_fid,  			       FC_TYPE_ELS, f_ctl, 0);  		lport->tt.seq_send(lport, sp, fp); @@ -947,14 +943,18 @@ static void fc_lport_reset_locked(struct fc_lport *lport)  	if (lport->dns_rdata)  		lport->tt.rport_logoff(lport->dns_rdata); -	lport->ptp_rdata = NULL; +	if (lport->ptp_rdata) { +		lport->tt.rport_logoff(lport->ptp_rdata); +		kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy); +		lport->ptp_rdata = NULL; +	}  	lport->tt.disc_stop(lport);  	lport->tt.exch_mgr_reset(lport, 0, 0);  	fc_host_fabric_name(lport->host) = 0; -	if (fc_host_port_id(lport->host)) +	if (lport->port_id)  		fc_lport_set_port_id(lport, 0, NULL);  } @@ -1492,7 +1492,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,  				lport->r_a_tov = 2 * e_d_tov;  				fc_lport_set_port_id(lport, did, fp);  				printk(KERN_INFO "host%d: libfc: " -				       "Port (%6x) entered " +				       "Port (%6.6x) entered "  				       "point-to-point mode\n",  				       lport->host->host_no, did);  				fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id), @@ -1699,7 +1699,7 @@ static int fc_lport_els_request(struct fc_bsg_job *job,  	fh = fc_frame_header_get(fp);  	fh->fh_r_ctl = FC_RCTL_ELS_REQ;  	hton24(fh->fh_d_id, did); -	hton24(fh->fh_s_id, fc_host_port_id(lport->host)); +	hton24(fh->fh_s_id, lport->port_id);  	fh->fh_type = FC_TYPE_ELS;  	hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |  	       FC_FC_END_SEQ | FC_FC_SEQ_INIT); @@ -1759,7 +1759,7 @@ static int fc_lport_ct_request(struct fc_bsg_job *job,  	fh = fc_frame_header_get(fp);  	fh->fh_r_ctl = FC_RCTL_DD_UNSOL_CTL;  	hton24(fh->fh_d_id, did); -	hton24(fh->fh_s_id, fc_host_port_id(lport->host)); +	hton24(fh->fh_s_id, lport->port_id);  	fh->fh_type = FC_TYPE_CT;  	hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |  	       FC_FC_END_SEQ | FC_FC_SEQ_INIT); diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c index c68f6c7341c..dd2b43bb1c7 100644 --- a/drivers/scsi/libfc/fc_npiv.c +++ b/drivers/scsi/libfc/fc_npiv.c @@ -69,12 +69,15 @@ struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id)  	struct fc_lport *lport = NULL;  	struct fc_lport *vn_port; -	if (fc_host_port_id(n_port->host) == port_id) +	if (n_port->port_id == port_id)  		return n_port; +	if (port_id == FC_FID_FLOGI) +		return n_port;		/* for point-to-point */ +  	mutex_lock(&n_port->lp_mutex);  	list_for_each_entry(vn_port, &n_port->vports, list) { -		if (fc_host_port_id(vn_port->host) == port_id) { +		if (vn_port->port_id == port_id) {  			lport = vn_port;  			break;  		} diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index b37d0ff28b3..39e440f0f54 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -1442,136 +1442,115 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,  	struct fc_els_spp *spp;	/* response spp */  	unsigned int len;  	unsigned int plen; -	enum fc_els_rjt_reason reason = ELS_RJT_UNAB; -	enum fc_els_rjt_explan explan = ELS_EXPL_NONE;  	enum fc_els_spp_resp resp;  	struct fc_seq_els_data rjt_data;  	u32 f_ctl;  	u32 fcp_parm;  	u32 roles = FC_RPORT_ROLE_UNKNOWN; -	rjt_data.fp = NULL; +	rjt_data.fp = NULL;  	fh = fc_frame_header_get(rx_fp);  	FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",  		     fc_rport_state(rdata)); -	switch (rdata->rp_state) { -	case RPORT_ST_PRLI: -	case RPORT_ST_RTV: -	case RPORT_ST_READY: -	case RPORT_ST_ADISC: -		reason = ELS_RJT_NONE; -		break; -	default: -		fc_frame_free(rx_fp); -		return; -		break; -	}  	len = fr_len(rx_fp) - sizeof(*fh);  	pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); -	if (pp == NULL) { -		reason = ELS_RJT_PROT; -		explan = ELS_EXPL_INV_LEN; -	} else { -		plen = ntohs(pp->prli.prli_len); -		if ((plen % 4) != 0 || plen > len) { -			reason = ELS_RJT_PROT; -			explan = ELS_EXPL_INV_LEN; -		} else if (plen < len) { -			len = plen; -		} -		plen = pp->prli.prli_spp_len; -		if ((plen % 4) != 0 || plen < sizeof(*spp) || -		    plen > len || len < sizeof(*pp)) { -			reason = ELS_RJT_PROT; -			explan = ELS_EXPL_INV_LEN; -		} -		rspp = &pp->spp; -	} -	if (reason != ELS_RJT_NONE || -	    (fp = fc_frame_alloc(lport, len)) == NULL) { -		rjt_data.reason = reason; -		rjt_data.explan = explan; -		lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); -	} else { -		sp = lport->tt.seq_start_next(sp); -		WARN_ON(!sp); -		pp = fc_frame_payload_get(fp, len); -		WARN_ON(!pp); -		memset(pp, 0, len); -		pp->prli.prli_cmd = ELS_LS_ACC; -		pp->prli.prli_spp_len = plen; -		pp->prli.prli_len = htons(len); -		len -= sizeof(struct fc_els_prli); - -		/* reinitialize remote port roles */ -		rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; +	if (!pp) +		goto reject_len; +	plen = ntohs(pp->prli.prli_len); +	if ((plen % 4) != 0 || plen > len || plen < 16) +		goto reject_len; +	if (plen < len) +		len = plen; +	plen = pp->prli.prli_spp_len; +	if ((plen % 4) != 0 || plen < sizeof(*spp) || +	    plen > len || len < sizeof(*pp) || plen < 12) +		goto reject_len; +	rspp = &pp->spp; -		/* -		 * Go through all the service parameter pages and build -		 * response.  If plen indicates longer SPP than standard, -		 * use that.  The entire response has been pre-cleared above. -		 */ -		spp = &pp->spp; -		while (len >= plen) { -			spp->spp_type = rspp->spp_type; -			spp->spp_type_ext = rspp->spp_type_ext; -			spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR; -			resp = FC_SPP_RESP_ACK; -			if (rspp->spp_flags & FC_SPP_RPA_VAL) -				resp = FC_SPP_RESP_NO_PA; -			switch (rspp->spp_type) { -			case 0:	/* common to all FC-4 types */ -				break; -			case FC_TYPE_FCP: -				fcp_parm = ntohl(rspp->spp_params); -				if (fcp_parm & FCP_SPPF_RETRY) -					rdata->flags |= FC_RP_FLAGS_RETRY; -				rdata->supported_classes = FC_COS_CLASS3; -				if (fcp_parm & FCP_SPPF_INIT_FCN) -					roles |= FC_RPORT_ROLE_FCP_INITIATOR; -				if (fcp_parm & FCP_SPPF_TARG_FCN) -					roles |= FC_RPORT_ROLE_FCP_TARGET; -				rdata->ids.roles = roles; +	fp = fc_frame_alloc(lport, len); +	if (!fp) { +		rjt_data.reason = ELS_RJT_UNAB; +		rjt_data.explan = ELS_EXPL_INSUF_RES; +		goto reject; +	} +	sp = lport->tt.seq_start_next(sp); +	WARN_ON(!sp); +	pp = fc_frame_payload_get(fp, len); +	WARN_ON(!pp); +	memset(pp, 0, len); +	pp->prli.prli_cmd = ELS_LS_ACC; +	pp->prli.prli_spp_len = plen; +	pp->prli.prli_len = htons(len); +	len -= sizeof(struct fc_els_prli); -				spp->spp_params = -					htonl(lport->service_params); -				break; -			default: -				resp = FC_SPP_RESP_INVL; -				break; -			} -			spp->spp_flags |= resp; -			len -= plen; -			rspp = (struct fc_els_spp *)((char *)rspp + plen); -			spp = (struct fc_els_spp *)((char *)spp + plen); -		} +	/* reinitialize remote port roles */ +	rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; -		/* -		 * Send LS_ACC.	 If this fails, the originator should retry. -		 */ -		f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; -		f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; -		ep = fc_seq_exch(sp); -		fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, -			       FC_TYPE_ELS, f_ctl, 0); -		lport->tt.seq_send(lport, sp, fp); +	/* +	 * Go through all the service parameter pages and build +	 * response.  If plen indicates longer SPP than standard, +	 * use that.  The entire response has been pre-cleared above. +	 */ +	spp = &pp->spp; +	while (len >= plen) { +		spp->spp_type = rspp->spp_type; +		spp->spp_type_ext = rspp->spp_type_ext; +		spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR; +		resp = FC_SPP_RESP_ACK; -		/* -		 * Get lock and re-check state. -		 */ -		switch (rdata->rp_state) { -		case RPORT_ST_PRLI: -			fc_rport_enter_ready(rdata); +		switch (rspp->spp_type) { +		case 0:	/* common to all FC-4 types */  			break; -		case RPORT_ST_READY: -		case RPORT_ST_ADISC: +		case FC_TYPE_FCP: +			fcp_parm = ntohl(rspp->spp_params); +			if (fcp_parm & FCP_SPPF_RETRY) +				rdata->flags |= FC_RP_FLAGS_RETRY; +			rdata->supported_classes = FC_COS_CLASS3; +			if (fcp_parm & FCP_SPPF_INIT_FCN) +				roles |= FC_RPORT_ROLE_FCP_INITIATOR; +			if (fcp_parm & FCP_SPPF_TARG_FCN) +				roles |= FC_RPORT_ROLE_FCP_TARGET; +			rdata->ids.roles = roles; + +			spp->spp_params = htonl(lport->service_params);  			break;  		default: +			resp = FC_SPP_RESP_INVL;  			break;  		} +		spp->spp_flags |= resp; +		len -= plen; +		rspp = (struct fc_els_spp *)((char *)rspp + plen); +		spp = (struct fc_els_spp *)((char *)spp + plen);  	} + +	/* +	 * Send LS_ACC.	 If this fails, the originator should retry. +	 */ +	f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; +	f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; +	ep = fc_seq_exch(sp); +	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, +		       FC_TYPE_ELS, f_ctl, 0); +	lport->tt.seq_send(lport, sp, fp); + +	switch (rdata->rp_state) { +	case RPORT_ST_PRLI: +		fc_rport_enter_ready(rdata); +		break; +	default: +		break; +	} +	goto drop; + +reject_len: +	rjt_data.reason = ELS_RJT_PROT; +	rjt_data.explan = ELS_EXPL_INV_LEN; +reject: +	lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); +drop:  	fc_frame_free(rx_fp);  } diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 5c92620292f..8eeb39ffa37 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -421,7 +421,7 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)  	struct iscsi_conn *conn = tcp_conn->iscsi_conn;  	struct hash_desc *rx_hash = NULL; -	if (conn->datadgst_en & +	if (conn->datadgst_en &&  	    !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))  		rx_hash = tcp_conn->rx_hash; diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 565e16dd74f..e35a4c71eb9 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -310,7 +310,9 @@ struct lpfc_vport {  #define FC_NLP_MORE             0x40	 /* More node to process in node tbl */  #define FC_OFFLINE_MODE         0x80	 /* Interface is offline for diag */  #define FC_FABRIC               0x100	 /* We are fabric attached */ +#define FC_VPORT_LOGO_RCVD      0x200    /* LOGO received on vport */  #define FC_RSCN_DISCOVERY       0x400	 /* Auth all devices after RSCN */ +#define FC_LOGO_RCVD_DID_CHNG   0x800    /* FDISC on phys port detect DID chng*/  #define FC_SCSI_SCAN_TMO        0x4000	 /* scsi scan timer running */  #define FC_ABORT_DISCOVERY      0x8000	 /* we want to abort discovery */  #define FC_NDISC_ACTIVE         0x10000	 /* NPort discovery active */ @@ -554,6 +556,7 @@ struct lpfc_hba {  	struct lpfc_dmabuf slim2p;  	MAILBOX_t *mbox; +	uint32_t *mbox_ext;  	uint32_t *inb_ha_copy;  	uint32_t *inb_counter;  	uint32_t inb_last_counter; @@ -622,6 +625,7 @@ struct lpfc_hba {  	uint32_t cfg_enable_hba_reset;  	uint32_t cfg_enable_hba_heartbeat;  	uint32_t cfg_enable_bg; +	uint32_t cfg_hostmem_hgp;  	uint32_t cfg_log_verbose;  	uint32_t cfg_aer_support;  	uint32_t cfg_suppress_link_up; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 1849e33e68f..2e5f376d9cc 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -869,6 +869,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba,  	LPFC_MBOXQ_t *pmboxq;  	MAILBOX_t *pmb;  	int rc = 0; +	uint32_t max_vpi;  	/*  	 * prevent udev from issuing mailbox commands until the port is @@ -916,11 +917,17 @@ lpfc_get_hba_info(struct lpfc_hba *phba,  		if (axri)  			*axri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config) -  					phba->sli4_hba.max_cfg_param.xri_used; + +		/* Account for differences with SLI-3.  Get vpi count from +		 * mailbox data and subtract one for max vpi value. +		 */ +		max_vpi = (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) > 0) ? +			(bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - 1) : 0; +  		if (mvpi) -			*mvpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config); +			*mvpi = max_vpi;  		if (avpi) -			*avpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - -					phba->sli4_hba.max_cfg_param.vpi_used; +			*avpi = max_vpi - phba->sli4_hba.max_cfg_param.vpi_used;  	} else {  		if (mrpi)  			*mrpi = pmb->un.varRdConfig.max_rpi; @@ -1925,13 +1932,12 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"  		 " 2 - select SLI-2 even on SLI-3 capable HBAs,"  		 " 3 - select SLI-3"); -int lpfc_enable_npiv = 0; +int lpfc_enable_npiv = 1;  module_param(lpfc_enable_npiv, int, 0);  MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");  lpfc_param_show(enable_npiv); -lpfc_param_init(enable_npiv, 0, 0, 1); -static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, -			 lpfc_enable_npiv_show, NULL); +lpfc_param_init(enable_npiv, 1, 0, 1); +static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);  /*  # lpfc_suppress_link_up:  Bring link up at initialization diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index d62b3e46792..dcf088262b2 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -79,6 +79,12 @@ struct lpfc_bsg_iocb {  struct lpfc_bsg_mbox {  	LPFC_MBOXQ_t *pmboxq;  	MAILBOX_t *mb; +	struct lpfc_dmabuf *rxbmp; /* for BIU diags */ +	struct lpfc_dmabufext *dmp; /* for BIU diags */ +	uint8_t *ext; /* extended mailbox data */ +	uint32_t mbOffset; /* from app */ +	uint32_t inExtWLen; /* from app */ +	uint32_t outExtWLen; /* from app */  	/* job waiting for this mbox command to finish */  	struct fc_bsg_job *set_job; @@ -1708,21 +1714,26 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,  	dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);  	if (dmabuf) {  		dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); -		INIT_LIST_HEAD(&dmabuf->list); -		bpl = (struct ulp_bde64 *) dmabuf->virt; -		memset(bpl, 0, sizeof(*bpl)); -		ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); -		bpl->addrHigh = -			le32_to_cpu(putPaddrHigh(dmabuf->phys + sizeof(*bpl))); -		bpl->addrLow = -			le32_to_cpu(putPaddrLow(dmabuf->phys + sizeof(*bpl))); -		bpl->tus.f.bdeFlags = 0; -		bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; -		bpl->tus.w = le32_to_cpu(bpl->tus.w); +		if (dmabuf->virt) { +			INIT_LIST_HEAD(&dmabuf->list); +			bpl = (struct ulp_bde64 *) dmabuf->virt; +			memset(bpl, 0, sizeof(*bpl)); +			ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); +			bpl->addrHigh = +				le32_to_cpu(putPaddrHigh(dmabuf->phys + +					sizeof(*bpl))); +			bpl->addrLow = +				le32_to_cpu(putPaddrLow(dmabuf->phys + +					sizeof(*bpl))); +			bpl->tus.f.bdeFlags = 0; +			bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; +			bpl->tus.w = le32_to_cpu(bpl->tus.w); +		}  	}  	if (cmdiocbq == NULL || rspiocbq == NULL || -	    dmabuf == NULL || bpl == NULL || ctreq == NULL) { +	    dmabuf == NULL || bpl == NULL || ctreq == NULL || +		dmabuf->virt == NULL) {  		ret_val = ENOMEM;  		goto err_get_xri_exit;  	} @@ -1918,9 +1929,11 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,  	rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);  	if (rxbmp != NULL) {  		rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); -		INIT_LIST_HEAD(&rxbmp->list); -		rxbpl = (struct ulp_bde64 *) rxbmp->virt; -		rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); +		if (rxbmp->virt) { +			INIT_LIST_HEAD(&rxbmp->list); +			rxbpl = (struct ulp_bde64 *) rxbmp->virt; +			rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); +		}  	}  	if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) { @@ -2174,14 +2187,16 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)  	if (txbmp) {  		txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); -		INIT_LIST_HEAD(&txbmp->list); -		txbpl = (struct ulp_bde64 *) txbmp->virt; -		if (txbpl) +		if (txbmp->virt) { +			INIT_LIST_HEAD(&txbmp->list); +			txbpl = (struct ulp_bde64 *) txbmp->virt;  			txbuffer = diag_cmd_data_alloc(phba,  							txbpl, full_size, 0); +		}  	} -	if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer) { +	if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer || +		!txbmp->virt) {  		rc = -ENOMEM;  		goto err_loopback_test_exit;  	} @@ -2377,35 +2392,90 @@ void  lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)  {  	struct bsg_job_data *dd_data; -	MAILBOX_t *pmb; -	MAILBOX_t *mb;  	struct fc_bsg_job *job;  	uint32_t size;  	unsigned long flags; +	uint8_t *to; +	uint8_t *from;  	spin_lock_irqsave(&phba->ct_ev_lock, flags);  	dd_data = pmboxq->context1; +	/* job already timed out? */  	if (!dd_data) {  		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);  		return;  	} -	pmb = &dd_data->context_un.mbox.pmboxq->u.mb; -	mb = dd_data->context_un.mbox.mb; +	/* build the outgoing buffer to do an sg copy +	 * the format is the response mailbox followed by any extended +	 * mailbox data +	 */ +	from = (uint8_t *)&pmboxq->u.mb; +	to = (uint8_t *)dd_data->context_un.mbox.mb; +	memcpy(to, from, sizeof(MAILBOX_t)); +	if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS) { +		/* copy the extended data if any, count is in words */ +		if (dd_data->context_un.mbox.outExtWLen) { +			from = (uint8_t *)dd_data->context_un.mbox.ext; +			to += sizeof(MAILBOX_t); +			size = dd_data->context_un.mbox.outExtWLen * +					sizeof(uint32_t); +			memcpy(to, from, size); +		} else if (pmboxq->u.mb.mbxCommand == MBX_RUN_BIU_DIAG64) { +			from = (uint8_t *)dd_data->context_un.mbox. +						dmp->dma.virt; +			to += sizeof(MAILBOX_t); +			size = dd_data->context_un.mbox.dmp->size; +			memcpy(to, from, size); +		} else if ((phba->sli_rev == LPFC_SLI_REV4) && +			(pmboxq->u.mb.mbxCommand == MBX_DUMP_MEMORY)) { +			from = (uint8_t *)dd_data->context_un.mbox.dmp->dma. +						virt; +			to += sizeof(MAILBOX_t); +			size = pmboxq->u.mb.un.varWords[5]; +			memcpy(to, from, size); +		} else if (pmboxq->u.mb.mbxCommand == MBX_READ_EVENT_LOG) { +			from = (uint8_t *)dd_data->context_un. +						mbox.dmp->dma.virt; +			to += sizeof(MAILBOX_t); +			size = dd_data->context_un.mbox.dmp->size; +			memcpy(to, from, size); +		} +	} + +	from = (uint8_t *)dd_data->context_un.mbox.mb;  	job = dd_data->context_un.mbox.set_job; -	memcpy(mb, pmb, sizeof(*pmb)); -	size = job->request_payload.payload_len; +	size = job->reply_payload.payload_len;  	job->reply->reply_payload_rcv_len =  		sg_copy_from_buffer(job->reply_payload.sg_list,  				job->reply_payload.sg_cnt, -				mb, size); +				from, size);  	job->reply->result = 0; +  	dd_data->context_un.mbox.set_job = NULL;  	job->dd_data = NULL;  	job->job_done(job); +	/* need to hold the lock until we call job done to hold off +	 * the timeout handler returning to the midlayer while +	 * we are stillprocessing the job +	 */  	spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + +	kfree(dd_data->context_un.mbox.mb);  	mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); -	kfree(mb); +	kfree(dd_data->context_un.mbox.ext); +	if (dd_data->context_un.mbox.dmp) { +		dma_free_coherent(&phba->pcidev->dev, +			dd_data->context_un.mbox.dmp->size, +			dd_data->context_un.mbox.dmp->dma.virt, +			dd_data->context_un.mbox.dmp->dma.phys); +		kfree(dd_data->context_un.mbox.dmp); +	} +	if (dd_data->context_un.mbox.rxbmp) { +		lpfc_mbuf_free(phba, dd_data->context_un.mbox.rxbmp->virt, +			dd_data->context_un.mbox.rxbmp->phys); +		kfree(dd_data->context_un.mbox.rxbmp); +	}  	kfree(dd_data);  	return;  } @@ -2464,10 +2534,12 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,  	case MBX_SET_DEBUG:  	case MBX_WRITE_WWN:  	case MBX_SLI4_CONFIG: +	case MBX_READ_EVENT_LOG:  	case MBX_READ_EVENT_LOG_STATUS:  	case MBX_WRITE_EVENT_LOG:  	case MBX_PORT_CAPABILITIES:  	case MBX_PORT_IOV_CONTROL: +	case MBX_RUN_BIU_DIAG64:  		break;  	case MBX_SET_VARIABLE:  		lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -2482,8 +2554,6 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,  			phba->fc_topology = TOPOLOGY_PT_PT;  		}  		break; -	case MBX_RUN_BIU_DIAG64: -	case MBX_READ_EVENT_LOG:  	case MBX_READ_SPARM64:  	case MBX_READ_LA:  	case MBX_READ_LA64: @@ -2518,97 +2588,365 @@ static uint32_t  lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,  	struct lpfc_vport *vport)  { -	LPFC_MBOXQ_t *pmboxq; -	MAILBOX_t *pmb; -	MAILBOX_t *mb; -	struct bsg_job_data *dd_data; +	LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */ +	MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */ +	/* a 4k buffer to hold the mb and extended data from/to the bsg */ +	MAILBOX_t *mb = NULL; +	struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */  	uint32_t size; +	struct lpfc_dmabuf *rxbmp = NULL; /* for biu diag */ +	struct lpfc_dmabufext *dmp = NULL; /* for biu diag */ +	struct ulp_bde64 *rxbpl = NULL; +	struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *) +		job->request->rqst_data.h_vendor.vendor_cmd; +	uint8_t *ext = NULL;  	int rc = 0; +	uint8_t *from; + +	/* in case no data is transferred */ +	job->reply->reply_payload_rcv_len = 0; + +	/* check if requested extended data lengths are valid */ +	if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) || +		(mbox_req->outExtWLen > MAILBOX_EXT_SIZE)) { +		rc = -ERANGE; +		goto job_done; +	}  	/* allocate our bsg tracking structure */  	dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);  	if (!dd_data) {  		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,  				"2727 Failed allocation of dd_data\n"); -		return -ENOMEM; +		rc = -ENOMEM; +		goto job_done;  	} -	mb = kzalloc(PAGE_SIZE, GFP_KERNEL); +	mb = kzalloc(BSG_MBOX_SIZE, GFP_KERNEL);  	if (!mb) { -		kfree(dd_data); -		return -ENOMEM; +		rc = -ENOMEM; +		goto job_done;  	}  	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);  	if (!pmboxq) { -		kfree(dd_data); -		kfree(mb); -		return -ENOMEM; +		rc = -ENOMEM; +		goto job_done;  	} +	memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));  	size = job->request_payload.payload_len; -	job->reply->reply_payload_rcv_len = -		sg_copy_to_buffer(job->request_payload.sg_list, -				job->request_payload.sg_cnt, -				mb, size); +	sg_copy_to_buffer(job->request_payload.sg_list, +			job->request_payload.sg_cnt, +			mb, size);  	rc = lpfc_bsg_check_cmd_access(phba, mb, vport); -	if (rc != 0) { -		kfree(dd_data); -		kfree(mb); -		mempool_free(pmboxq, phba->mbox_mem_pool); -		return rc; /* must be negative */ -	} +	if (rc != 0) +		goto job_done; /* must be negative */ -	memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));  	pmb = &pmboxq->u.mb;  	memcpy(pmb, mb, sizeof(*pmb));  	pmb->mbxOwner = OWN_HOST; -	pmboxq->context1 = NULL;  	pmboxq->vport = vport; -	if ((vport->fc_flag & FC_OFFLINE_MODE) || -	    (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { -		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); -		if (rc != MBX_SUCCESS) { -			if (rc != MBX_TIMEOUT) { -				kfree(dd_data); -				kfree(mb); -				mempool_free(pmboxq, phba->mbox_mem_pool); +	/* If HBA encountered an error attention, allow only DUMP +	 * or RESTART mailbox commands until the HBA is restarted. +	 */ +	if (phba->pport->stopped && +	    pmb->mbxCommand != MBX_DUMP_MEMORY && +	    pmb->mbxCommand != MBX_RESTART && +	    pmb->mbxCommand != MBX_WRITE_VPARMS && +	    pmb->mbxCommand != MBX_WRITE_WWN) +		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, +				"2797 mbox: Issued mailbox cmd " +				"0x%x while in stopped state.\n", +				pmb->mbxCommand); + +	/* Don't allow mailbox commands to be sent when blocked +	 * or when in the middle of discovery +	 */ +	if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { +		rc = -EAGAIN; +		goto job_done; +	} + +	/* extended mailbox commands will need an extended buffer */ +	if (mbox_req->inExtWLen || mbox_req->outExtWLen) { +		ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL); +		if (!ext) { +			rc = -ENOMEM; +			goto job_done; +		} + +		/* any data for the device? */ +		if (mbox_req->inExtWLen) { +			from = (uint8_t *)mb; +			from += sizeof(MAILBOX_t); +			memcpy((uint8_t *)ext, from, +				mbox_req->inExtWLen * sizeof(uint32_t)); +		} + +		pmboxq->context2 = ext; +		pmboxq->in_ext_byte_len = +			mbox_req->inExtWLen * +			sizeof(uint32_t); +		pmboxq->out_ext_byte_len = +			mbox_req->outExtWLen * +			sizeof(uint32_t); +		pmboxq->mbox_offset_word = +			mbox_req->mbOffset; +		pmboxq->context2 = ext; +		pmboxq->in_ext_byte_len = +			mbox_req->inExtWLen * sizeof(uint32_t); +		pmboxq->out_ext_byte_len = +			mbox_req->outExtWLen * sizeof(uint32_t); +		pmboxq->mbox_offset_word = mbox_req->mbOffset; +	} + +	/* biu diag will need a kernel buffer to transfer the data +	 * allocate our own buffer and setup the mailbox command to +	 * use ours +	 */ +	if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { +		uint32_t transmit_length = pmb->un.varWords[1]; +		uint32_t receive_length = pmb->un.varWords[4]; +		/* transmit length cannot be greater than receive length or +		 * mailbox extension size +		 */ +		if ((transmit_length > receive_length) || +			(transmit_length > MAILBOX_EXT_SIZE)) { +			rc = -ERANGE; +			goto job_done; +		} + +		rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); +		if (!rxbmp) { +			rc = -ENOMEM; +			goto job_done; +		} + +		rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); +		if (!rxbmp->virt) { +			rc = -ENOMEM; +			goto job_done; +		} + +		INIT_LIST_HEAD(&rxbmp->list); +		rxbpl = (struct ulp_bde64 *) rxbmp->virt; +		dmp = diag_cmd_data_alloc(phba, rxbpl, transmit_length, 0); +		if (!dmp) { +			rc = -ENOMEM; +			goto job_done; +		} + +		INIT_LIST_HEAD(&dmp->dma.list); +		pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = +			putPaddrHigh(dmp->dma.phys); +		pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = +			putPaddrLow(dmp->dma.phys); + +		pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = +			putPaddrHigh(dmp->dma.phys + +				pmb->un.varBIUdiag.un.s2. +					xmit_bde64.tus.f.bdeSize); +		pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = +			putPaddrLow(dmp->dma.phys + +				pmb->un.varBIUdiag.un.s2. +					xmit_bde64.tus.f.bdeSize); + +		/* copy the transmit data found in the mailbox extension area */ +		from = (uint8_t *)mb; +		from += sizeof(MAILBOX_t); +		memcpy((uint8_t *)dmp->dma.virt, from, transmit_length); +	} else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { +		struct READ_EVENT_LOG_VAR *rdEventLog = +			&pmb->un.varRdEventLog ; +		uint32_t receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; +		uint32_t mode =	 bf_get(lpfc_event_log, rdEventLog); + +		/* receive length cannot be greater than mailbox +		 * extension size +		 */ +		if (receive_length > MAILBOX_EXT_SIZE) { +			rc = -ERANGE; +			goto job_done; +		} + +		/* mode zero uses a bde like biu diags command */ +		if (mode == 0) { + +			/* rebuild the command for sli4 using our own buffers +			* like we do for biu diags +			*/ + +			rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); +			if (!rxbmp) { +				rc = -ENOMEM; +				goto job_done;  			} -			return  (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; + +			rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); +			rxbpl = (struct ulp_bde64 *) rxbmp->virt; +			if (rxbpl) { +				INIT_LIST_HEAD(&rxbmp->list); +				dmp = diag_cmd_data_alloc(phba, rxbpl, +					receive_length, 0); +			} + +			if (!dmp) { +				rc = -ENOMEM; +				goto job_done; +			} + +			INIT_LIST_HEAD(&dmp->dma.list); +			pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys); +			pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys);  		} +	} else if (phba->sli_rev == LPFC_SLI_REV4) { +		if (pmb->mbxCommand == MBX_DUMP_MEMORY) { +			/* rebuild the command for sli4 using our own buffers +			* like we do for biu diags +			*/ +			uint32_t receive_length = pmb->un.varWords[2]; +			/* receive length cannot be greater than mailbox +			 * extension size +			 */ +			if ((receive_length == 0) || +				(receive_length > MAILBOX_EXT_SIZE)) { +				rc = -ERANGE; +				goto job_done; +			} -		memcpy(mb, pmb, sizeof(*pmb)); -		job->reply->reply_payload_rcv_len = -			sg_copy_from_buffer(job->reply_payload.sg_list, -					job->reply_payload.sg_cnt, -					mb, size); -		kfree(dd_data); -		kfree(mb); -		mempool_free(pmboxq, phba->mbox_mem_pool); -		/* not waiting mbox already done */ -		return 0; +			rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); +			if (!rxbmp) { +				rc = -ENOMEM; +				goto job_done; +			} + +			rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); +			if (!rxbmp->virt) { +				rc = -ENOMEM; +				goto job_done; +			} + +			INIT_LIST_HEAD(&rxbmp->list); +			rxbpl = (struct ulp_bde64 *) rxbmp->virt; +			dmp = diag_cmd_data_alloc(phba, rxbpl, receive_length, +						0); +			if (!dmp) { +				rc = -ENOMEM; +				goto job_done; +			} + +			INIT_LIST_HEAD(&dmp->dma.list); +			pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys); +			pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys); +		} else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && +			pmb->un.varUpdateCfg.co) { +			struct ulp_bde64 *bde = +				(struct ulp_bde64 *)&pmb->un.varWords[4]; + +			/* bde size cannot be greater than mailbox ext size */ +			if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) { +				rc = -ERANGE; +				goto job_done; +			} + +			rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); +			if (!rxbmp) { +				rc = -ENOMEM; +				goto job_done; +			} + +			rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); +			if (!rxbmp->virt) { +				rc = -ENOMEM; +				goto job_done; +			} + +			INIT_LIST_HEAD(&rxbmp->list); +			rxbpl = (struct ulp_bde64 *) rxbmp->virt; +			dmp = diag_cmd_data_alloc(phba, rxbpl, +					bde->tus.f.bdeSize, 0); +			if (!dmp) { +				rc = -ENOMEM; +				goto job_done; +			} + +			INIT_LIST_HEAD(&dmp->dma.list); +			bde->addrHigh = putPaddrHigh(dmp->dma.phys); +			bde->addrLow = putPaddrLow(dmp->dma.phys); + +			/* copy the transmit data found in the mailbox +			 * extension area +			 */ +			from = (uint8_t *)mb; +			from += sizeof(MAILBOX_t); +			memcpy((uint8_t *)dmp->dma.virt, from, +				bde->tus.f.bdeSize); +		}  	} +	dd_data->context_un.mbox.rxbmp = rxbmp; +	dd_data->context_un.mbox.dmp = dmp; +  	/* setup wake call as IOCB callback */  	pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait; +  	/* setup context field to pass wait_queue pointer to wake function */  	pmboxq->context1 = dd_data;  	dd_data->type = TYPE_MBOX;  	dd_data->context_un.mbox.pmboxq = pmboxq;  	dd_data->context_un.mbox.mb = mb;  	dd_data->context_un.mbox.set_job = job; +	dd_data->context_un.mbox.ext = ext; +	dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset; +	dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen; +	dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen;  	job->dd_data = dd_data; + +	if ((vport->fc_flag & FC_OFFLINE_MODE) || +	    (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { +		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); +		if (rc != MBX_SUCCESS) { +			rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; +			goto job_done; +		} + +		/* job finished, copy the data */ +		memcpy(mb, pmb, sizeof(*pmb)); +		job->reply->reply_payload_rcv_len = +			sg_copy_from_buffer(job->reply_payload.sg_list, +					job->reply_payload.sg_cnt, +					mb, size); +		/* not waiting mbox already done */ +		rc = 0; +		goto job_done; +	} +  	rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); -	if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { -		kfree(dd_data); -		kfree(mb); +	if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) +		return 1; /* job started */ + +job_done: +	/* common exit for error or job completed inline */ +	kfree(mb); +	if (pmboxq)  		mempool_free(pmboxq, phba->mbox_mem_pool); -		return -EIO; +	kfree(ext); +	if (dmp) { +		dma_free_coherent(&phba->pcidev->dev, +			dmp->size, dmp->dma.virt, +				dmp->dma.phys); +		kfree(dmp);  	} +	if (rxbmp) { +		lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); +		kfree(rxbmp); +	} +	kfree(dd_data); -	return 1; +	return rc;  }  /** @@ -2633,7 +2971,12 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job)  		goto job_error;  	} -	if (job->request_payload.payload_len != PAGE_SIZE) { +	if (job->request_payload.payload_len != BSG_MBOX_SIZE) { +		rc = -EINVAL; +		goto job_error; +	} + +	if (job->reply_payload.payload_len != BSG_MBOX_SIZE) {  		rc = -EINVAL;  		goto job_error;  	} @@ -3094,6 +3437,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)  		job->dd_data = NULL;  		job->reply->reply_payload_rcv_len = 0;  		job->reply->result = -EAGAIN; +		/* the mbox completion handler can now be run */  		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);  		job->job_done(job);  		break; diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index 5bc630819b9..a2c33e7c915 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -91,11 +91,12 @@ struct get_mgmt_rev_reply {  	struct MgmtRevInfo info;  }; +#define BSG_MBOX_SIZE 4096 /* mailbox command plus extended data */  struct dfc_mbox_req {  	uint32_t command; +	uint32_t mbOffset;  	uint32_t inExtWLen;  	uint32_t outExtWLen; -	uint8_t mbOffset;  };  /* Used for menlo command or menlo data. The xri is only used for menlo data */ diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 5087c4211b4..fbc9baeb604 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -65,6 +65,7 @@ void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);  void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);  void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);  void lpfc_retry_pport_discovery(struct lpfc_hba *); +void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);  void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);  void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 2851d75ffc6..36257a68550 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -38,6 +38,7 @@ enum lpfc_work_type {  	LPFC_EVT_ELS_RETRY,  	LPFC_EVT_DEV_LOSS,  	LPFC_EVT_FASTPATH_MGMT_EVT, +	LPFC_EVT_RESET_HBA,  };  /* structure used to queue event to the discovery tasklet */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 5fbdb22c189..c4c7f0ad746 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -584,6 +584,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,  			spin_unlock_irq(shost->host_lock);  			lpfc_unreg_rpi(vport, np);  		} +		lpfc_cleanup_pending_mbox(vport);  		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {  			lpfc_mbx_unreg_vpi(vport);  			spin_lock_irq(shost->host_lock); @@ -864,6 +865,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,  	}  	spin_lock_irq(shost->host_lock);  	vport->fc_flag &= ~FC_VPORT_CVL_RCVD; +	vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;  	spin_unlock_irq(shost->host_lock);  	/* @@ -893,11 +895,14 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,  		if (!rc) {  			/* Mark the FCF discovery process done */ -			lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | LOG_ELS, -					 "2769 FLOGI successful on FCF record: " -					 "current_fcf_index:x%x, terminate FCF " -					 "round robin failover process\n", -					 phba->fcf.current_rec.fcf_indx); +			if (phba->hba_flag & HBA_FIP_SUPPORT) +				lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | +						LOG_ELS, +						"2769 FLOGI successful on FCF " +						"record: current_fcf_index:" +						"x%x, terminate FCF round " +						"robin failover process\n", +						phba->fcf.current_rec.fcf_indx);  			spin_lock_irq(&phba->hbalock);  			phba->fcf.fcf_flag &= ~FCF_DISCOVERY;  			spin_unlock_irq(&phba->hbalock); @@ -5366,7 +5371,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba,  			sizeof(struct lpfc_name));  		pcmd = (uint32_t *) (((struct lpfc_dmabuf *)  			cmdiocbp->context2)->virt); -		lsrjt_event.command = *pcmd; +		lsrjt_event.command = (pcmd != NULL) ? *pcmd : 0;  		stat.un.lsRjtError = be32_to_cpu(rspiocbp->iocb.un.ulpWord[4]);  		lsrjt_event.reason_code = stat.un.b.lsRjtRsnCode;  		lsrjt_event.explanation = stat.un.b.lsRjtRsnCodeExp; @@ -6050,7 +6055,8 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)  			spin_lock_irq(shost->host_lock);  			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;  			spin_unlock_irq(shost->host_lock); -			if (vport->port_type == LPFC_PHYSICAL_PORT) +			if (vport->port_type == LPFC_PHYSICAL_PORT +				&& !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))  				lpfc_initial_flogi(vport);  			else  				lpfc_initial_fdisc(vport); @@ -6286,6 +6292,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,  	}  	spin_lock_irq(shost->host_lock);  	vport->fc_flag &= ~FC_VPORT_CVL_RCVD; +	vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;  	vport->fc_flag |= FC_FABRIC;  	if (vport->phba->fc_topology == TOPOLOGY_LOOP)  		vport->fc_flag |=  FC_PUBLIC_LOOP; @@ -6310,11 +6317,14 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,  			spin_unlock_irq(shost->host_lock);  			lpfc_unreg_rpi(vport, np);  		} +		lpfc_cleanup_pending_mbox(vport);  		lpfc_mbx_unreg_vpi(vport);  		spin_lock_irq(shost->host_lock);  		vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;  		if (phba->sli_rev == LPFC_SLI_REV4)  			vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; +		else +			vport->fc_flag |= FC_LOGO_RCVD_DID_CHNG;  		spin_unlock_irq(shost->host_lock);  	} diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index e1466eec56b..1f87b4fb8b5 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -475,6 +475,10 @@ lpfc_work_list_done(struct lpfc_hba *phba)  			lpfc_send_fastpath_evt(phba, evtp);  			free_evt = 0;  			break; +		case LPFC_EVT_RESET_HBA: +			if (!(phba->pport->load_flag & FC_UNLOADING)) +				lpfc_reset_hba(phba); +			break;  		}  		if (free_evt)  			kfree(evtp); @@ -1531,7 +1535,37 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)  }  /** - * lpfc_sli4_fcf_rec_mbox_parse - parse non-embedded fcf record mailbox command + * lpfc_sli4_new_fcf_random_select - Randomly select an eligible new fcf record + * @phba: pointer to lpfc hba data structure. + * @fcf_cnt: number of eligible fcf record seen so far. + * + * This function makes an running random selection decision on FCF record to + * use through a sequence of @fcf_cnt eligible FCF records with equal + * probability. To perform integer manunipulation of random numbers with + * size unit32_t, the lower 16 bits of the 32-bit random number returned + * from random32() are taken as the random random number generated. + * + * Returns true when outcome is for the newly read FCF record should be + * chosen; otherwise, return false when outcome is for keeping the previously + * chosen FCF record. + **/ +static bool +lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt) +{ +	uint32_t rand_num; + +	/* Get 16-bit uniform random number */ +	rand_num = (0xFFFF & random32()); + +	/* Decision with probability 1/fcf_cnt */ +	if ((fcf_cnt * rand_num) < 0xFFFF) +		return true; +	else +		return false; +} + +/** + * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.   * @phba: pointer to lpfc hba data structure.   * @mboxq: pointer to mailbox object.   * @next_fcf_index: pointer to holder of next fcf index. @@ -1592,7 +1626,9 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,  	new_fcf_record = (struct fcf_record *)(virt_addr +  			  sizeof(struct lpfc_mbx_read_fcf_tbl));  	lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record, -			      sizeof(struct fcf_record)); +				offsetof(struct fcf_record, vlan_bitmap)); +	new_fcf_record->word137 = le32_to_cpu(new_fcf_record->word137); +	new_fcf_record->word138 = le32_to_cpu(new_fcf_record->word138);  	return new_fcf_record;  } @@ -1679,6 +1715,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  	uint16_t fcf_index, next_fcf_index;  	struct lpfc_fcf_rec *fcf_rec = NULL;  	uint16_t vlan_id; +	uint32_t seed; +	bool select_new_fcf;  	int rc;  	/* If there is pending FCoE event restart FCF table scan */ @@ -1809,9 +1847,21 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  		 * than the driver FCF record, use the new record.  		 */  		if (new_fcf_record->fip_priority < fcf_rec->priority) { -			/* Choose this FCF record */ +			/* Choose the new FCF record with lower priority */  			__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,  					addr_mode, vlan_id, 0); +			/* Reset running random FCF selection count */ +			phba->fcf.eligible_fcf_cnt = 1; +		} else if (new_fcf_record->fip_priority == fcf_rec->priority) { +			/* Update running random FCF selection count */ +			phba->fcf.eligible_fcf_cnt++; +			select_new_fcf = lpfc_sli4_new_fcf_random_select(phba, +						phba->fcf.eligible_fcf_cnt); +			if (select_new_fcf) +				/* Choose the new FCF by random selection */ +				__lpfc_update_fcf_record(phba, fcf_rec, +							 new_fcf_record, +							 addr_mode, vlan_id, 0);  		}  		spin_unlock_irq(&phba->hbalock);  		goto read_next_fcf; @@ -1825,6 +1875,11 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  					 addr_mode, vlan_id, (boot_flag ?  					 BOOT_ENABLE : 0));  		phba->fcf.fcf_flag |= FCF_AVAILABLE; +		/* Setup initial running random FCF selection count */ +		phba->fcf.eligible_fcf_cnt = 1; +		/* Seeding the random number generator for random selection */ +		seed = (uint32_t)(0xFFFFFFFF & jiffies); +		srandom32(seed);  	}  	spin_unlock_irq(&phba->hbalock);  	goto read_next_fcf; @@ -2686,11 +2741,18 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)  	switch (mb->mbxStatus) {  	case 0x0011:  	case 0x0020: -	case 0x9700:  		lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,  				 "0911 cmpl_unreg_vpi, mb status = 0x%x\n",  				 mb->mbxStatus);  		break; +	/* If VPI is busy, reset the HBA */ +	case 0x9700: +		lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, +			"2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n", +			vport->vpi, mb->mbxStatus); +		if (!(phba->pport->load_flag & FC_UNLOADING)) +			lpfc_workq_post_event(phba, NULL, NULL, +				LPFC_EVT_RESET_HBA);  	}  	spin_lock_irq(shost->host_lock);  	vport->vpi_state &= ~LPFC_VPI_REGISTERED; @@ -2965,7 +3027,12 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)  	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);  	if (vport->port_state == LPFC_FABRIC_CFG_LINK) { -		lpfc_start_fdiscs(phba); +		/* when physical port receive logo donot start +		 * vport discovery */ +		if (!(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) +			lpfc_start_fdiscs(phba); +		else +			vport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG ;  		lpfc_do_scr_ns_plogi(phba, vport);  	} @@ -3177,7 +3244,6 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,  	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);  	if (new_state == NLP_STE_UNMAPPED_NODE) { -		ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);  		ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;  		ndlp->nlp_type |= NLP_FC_NODE;  	} @@ -4935,6 +5001,7 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba)  			ndlp = lpfc_findnode_did(vports[i], Fabric_DID);  			if (ndlp)  				lpfc_cancel_retry_delay_tmo(vports[i], ndlp); +			lpfc_cleanup_pending_mbox(vports[i]);  			lpfc_mbx_unreg_vpi(vports[i]);  			shost = lpfc_shost_from_vport(vports[i]);  			spin_lock_irq(shost->host_lock); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 89ff7c09e29..e654d01dad2 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1565,94 +1565,82 @@ enum lpfc_protgrp_type {  };  /* PDE Descriptors */ -#define LPFC_PDE1_DESCRIPTOR		0x81 -#define LPFC_PDE2_DESCRIPTOR		0x82 -#define LPFC_PDE3_DESCRIPTOR		0x83 +#define LPFC_PDE5_DESCRIPTOR		0x85 +#define LPFC_PDE6_DESCRIPTOR		0x86 +#define LPFC_PDE7_DESCRIPTOR		0x87 -/* BlockGuard Profiles */ -enum lpfc_bg_prof_codes { -	LPFC_PROF_INVALID, -	LPFC_PROF_A1	= 128,	/* Full Protection			      */ -	LPFC_PROF_A2,		/* Disabled Protection Checks:A2~A4           */ -	LPFC_PROF_A3, -	LPFC_PROF_A4, -	LPFC_PROF_B1,		/* Embedded DIFs: B1~B3	                      */ -	LPFC_PROF_B2, -	LPFC_PROF_B3, -	LPFC_PROF_C1,		/* Separate DIFs: C1~C3                       */ -	LPFC_PROF_C2, -	LPFC_PROF_C3, -	LPFC_PROF_D1,		/* Full Protection                            */ -	LPFC_PROF_D2,		/* Partial Protection & Check Disabling       */ -	LPFC_PROF_D3, -	LPFC_PROF_E1,		/* E1~E4:out - check-only, in - update apptag */ -	LPFC_PROF_E2, -	LPFC_PROF_E3, -	LPFC_PROF_E4, -	LPFC_PROF_F1,		/* Full Translation - F1 Prot Descriptor      */ -				/* F1 Translation BDE                         */ -	LPFC_PROF_ANT1,		/* TCP checksum, DIF inline with data buffers */ -	LPFC_PROF_AST1,		/* TCP checksum, DIF split from data buffer   */ -	LPFC_PROF_ANT2, -	LPFC_PROF_AST2 -}; - -/* BlockGuard error-control defines */ -#define BG_EC_STOP_ERR			0x00 -#define BG_EC_CONT_ERR			0x01 -#define BG_EC_IGN_UNINIT_STOP_ERR	0x10 -#define BG_EC_IGN_UNINIT_CONT_ERR	0x11 +/* BlockGuard Opcodes */ +#define BG_OP_IN_NODIF_OUT_CRC		0x0 +#define	BG_OP_IN_CRC_OUT_NODIF		0x1 +#define	BG_OP_IN_NODIF_OUT_CSUM		0x2 +#define	BG_OP_IN_CSUM_OUT_NODIF		0x3 +#define	BG_OP_IN_CRC_OUT_CRC		0x4 +#define	BG_OP_IN_CSUM_OUT_CSUM		0x5 +#define	BG_OP_IN_CRC_OUT_CSUM		0x6 +#define	BG_OP_IN_CSUM_OUT_CRC		0x7 -/* PDE (Protection Descriptor Entry) word 0 bit masks and shifts */ -#define PDE_DESC_TYPE_MASK		0xff000000 -#define PDE_DESC_TYPE_SHIFT		24 -#define PDE_BG_PROFILE_MASK		0x00ff0000 -#define PDE_BG_PROFILE_SHIFT		16 -#define PDE_BLOCK_LEN_MASK		0x0000fffc -#define PDE_BLOCK_LEN_SHIFT		2 -#define PDE_ERR_CTRL_MASK		0x00000003 -#define PDE_ERR_CTRL_SHIFT		0 -/* PDE word 1 bit masks and shifts */ -#define PDE_APPTAG_MASK_MASK		0xffff0000 -#define PDE_APPTAG_MASK_SHIFT		16 -#define PDE_APPTAG_VAL_MASK		0x0000ffff -#define PDE_APPTAG_VAL_SHIFT		0 -struct lpfc_pde { -	uint32_t parms;     /* bitfields of descriptor, prof, len, and ec */ -	uint32_t apptag;    /* bitfields of app tag maskand app tag value */ -	uint32_t reftag;    /* reference tag occupying all 32 bits        */ +struct lpfc_pde5 { +	uint32_t word0; +#define pde5_type_SHIFT		24 +#define pde5_type_MASK		0x000000ff +#define pde5_type_WORD		word0 +#define pde5_rsvd0_SHIFT	0 +#define pde5_rsvd0_MASK		0x00ffffff +#define pde5_rsvd0_WORD		word0 +	uint32_t reftag;	/* Reference Tag Value			*/ +	uint32_t reftagtr;	/* Reference Tag Translation Value 	*/  }; -/* inline function to set fields in parms of PDE */ -static inline void -lpfc_pde_set_bg_parms(struct lpfc_pde *p, u8 desc, u8 prof, u16 len, u8 ec) -{ -	uint32_t *wp = &p->parms; - -	/* spec indicates that adapter appends two 0's to length field */ -	len = len >> 2; - -	*wp &= 0; -	*wp |= ((desc << PDE_DESC_TYPE_SHIFT) & PDE_DESC_TYPE_MASK); -	*wp |= ((prof << PDE_BG_PROFILE_SHIFT) & PDE_BG_PROFILE_MASK); -	*wp |= ((len << PDE_BLOCK_LEN_SHIFT) & PDE_BLOCK_LEN_MASK); -	*wp |= ((ec << PDE_ERR_CTRL_SHIFT) & PDE_ERR_CTRL_MASK); -	*wp = le32_to_cpu(*wp); -} - -/* inline function to set apptag and reftag fields of PDE */ -static inline void -lpfc_pde_set_dif_parms(struct lpfc_pde *p, u16 apptagmask, u16 apptagval, -		u32 reftag) -{ -	uint32_t *wp = &p->apptag; -	*wp &= 0; -	*wp |= ((apptagmask << PDE_APPTAG_MASK_SHIFT) & PDE_APPTAG_MASK_MASK); -	*wp |= ((apptagval << PDE_APPTAG_VAL_SHIFT) & PDE_APPTAG_VAL_MASK); -	*wp = le32_to_cpu(*wp); -	wp = &p->reftag; -	*wp = le32_to_cpu(reftag); -} +struct lpfc_pde6 { +	uint32_t word0; +#define pde6_type_SHIFT		24 +#define pde6_type_MASK		0x000000ff +#define pde6_type_WORD		word0 +#define pde6_rsvd0_SHIFT	0 +#define pde6_rsvd0_MASK		0x00ffffff +#define pde6_rsvd0_WORD		word0 +	uint32_t word1; +#define pde6_rsvd1_SHIFT	26 +#define pde6_rsvd1_MASK		0x0000003f +#define pde6_rsvd1_WORD		word1 +#define pde6_na_SHIFT		25 +#define pde6_na_MASK		0x00000001 +#define pde6_na_WORD		word1 +#define pde6_rsvd2_SHIFT	16 +#define pde6_rsvd2_MASK		0x000001FF +#define pde6_rsvd2_WORD		word1 +#define pde6_apptagtr_SHIFT	0 +#define pde6_apptagtr_MASK	0x0000ffff +#define pde6_apptagtr_WORD	word1 +	uint32_t word2; +#define pde6_optx_SHIFT		28 +#define pde6_optx_MASK		0x0000000f +#define pde6_optx_WORD		word2 +#define pde6_oprx_SHIFT		24 +#define pde6_oprx_MASK		0x0000000f +#define pde6_oprx_WORD		word2 +#define pde6_nr_SHIFT		23 +#define pde6_nr_MASK		0x00000001 +#define pde6_nr_WORD		word2 +#define pde6_ce_SHIFT		22 +#define pde6_ce_MASK		0x00000001 +#define pde6_ce_WORD		word2 +#define pde6_re_SHIFT		21 +#define pde6_re_MASK		0x00000001 +#define pde6_re_WORD		word2 +#define pde6_ae_SHIFT		20 +#define pde6_ae_MASK		0x00000001 +#define pde6_ae_WORD		word2 +#define pde6_ai_SHIFT		19 +#define pde6_ai_MASK		0x00000001 +#define pde6_ai_WORD		word2 +#define pde6_bs_SHIFT		16 +#define pde6_bs_MASK		0x00000007 +#define pde6_bs_WORD		word2 +#define pde6_apptagval_SHIFT	0 +#define pde6_apptagval_MASK	0x0000ffff +#define pde6_apptagval_WORD	word2 +};  /* Structure for MB Command LOAD_SM and DOWN_LOAD */ @@ -1744,6 +1732,17 @@ typedef struct {  	} un;  } BIU_DIAG_VAR; +/* Structure for MB command READ_EVENT_LOG (0x38) */ +struct READ_EVENT_LOG_VAR { +	uint32_t word1; +#define lpfc_event_log_SHIFT	29 +#define lpfc_event_log_MASK	0x00000001 +#define lpfc_event_log_WORD	word1 +#define USE_MAILBOX_RESPONSE	1 +	uint32_t offset; +	struct ulp_bde64 rcv_bde64; +}; +  /* Structure for MB Command INIT_LINK (05) */  typedef struct { @@ -2487,8 +2486,8 @@ typedef struct {  #define  DMP_VPORT_REGION_SIZE	 0x200  #define  DMP_MBOX_OFFSET_WORD	 0x5 -#define  DMP_REGION_23	 	 0x17   /* fcoe param  and port state region */ -#define  DMP_RGN23_SIZE	 	 0x400 +#define  DMP_REGION_23		 0x17   /* fcoe param  and port state region */ +#define  DMP_RGN23_SIZE		 0x400  #define  WAKE_UP_PARMS_REGION_ID    4  #define  WAKE_UP_PARMS_WORD_SIZE   15 @@ -2503,9 +2502,9 @@ struct vport_rec {  #define VPORT_INFO_REV 0x1  #define MAX_STATIC_VPORT_COUNT 16  struct static_vport_info { -	uint32_t 		signature; +	uint32_t		signature;  	uint32_t		rev; -	struct vport_rec 	vport_list[MAX_STATIC_VPORT_COUNT]; +	struct vport_rec	vport_list[MAX_STATIC_VPORT_COUNT];  	uint32_t		resvd[66];  }; @@ -2934,6 +2933,12 @@ typedef struct {  /* Union of all Mailbox Command types */  #define MAILBOX_CMD_WSIZE	32  #define MAILBOX_CMD_SIZE	(MAILBOX_CMD_WSIZE * sizeof(uint32_t)) +/* ext_wsize times 4 bytes should not be greater than max xmit size */ +#define MAILBOX_EXT_WSIZE	512 +#define MAILBOX_EXT_SIZE	(MAILBOX_EXT_WSIZE * sizeof(uint32_t)) +#define MAILBOX_HBA_EXT_OFFSET  0x100 +/* max mbox xmit size is a page size for sysfs IO operations */ +#define MAILBOX_MAX_XMIT_SIZE   PAGE_SIZE  typedef union {  	uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/ @@ -2972,6 +2977,9 @@ typedef union {  	REG_VPI_VAR varRegVpi;		/* cmd = 0x96 (REG_VPI) */  	UNREG_VPI_VAR varUnregVpi;	/* cmd = 0x97 (UNREG_VPI) */  	ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */ +	struct READ_EVENT_LOG_VAR varRdEventLog;	/* cmd = 0x38 +							 * (READ_EVENT_LOG) +							 */  	struct config_msi_var varCfgMSI;/* cmd = x30 (CONFIG_MSI)     */  } MAILVARIANTS; @@ -3652,7 +3660,8 @@ typedef struct _IOCB {	/* IOCB structure */  /* Maximum IOCBs that will fit in SLI2 slim */  #define MAX_SLI2_IOCB    498  #define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \ -			    (sizeof(MAILBOX_t) + sizeof(PCB_t))) +			    (sizeof(MAILBOX_t) + sizeof(PCB_t) + \ +			    sizeof(uint32_t) * MAILBOX_EXT_WSIZE))  /* HBQ entries are 4 words each = 4k */  #define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) *  \ @@ -3660,6 +3669,7 @@ typedef struct _IOCB {	/* IOCB structure */  struct lpfc_sli2_slim {  	MAILBOX_t mbx; +	uint32_t  mbx_ext_words[MAILBOX_EXT_WSIZE];  	PCB_t pcb;  	IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE];  }; diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 820015fbc4d..bbdcf96800f 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -41,8 +41,14 @@   * Or clear that bit field:   *	bf_set(example_bit_field, &t1, 0);   */ +#define bf_get_le32(name, ptr) \ +	((le32_to_cpu((ptr)->name##_WORD) >> name##_SHIFT) & name##_MASK)  #define bf_get(name, ptr) \  	(((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK) +#define bf_set_le32(name, ptr, value) \ +	((ptr)->name##_WORD = cpu_to_le32(((((value) & \ +	name##_MASK) << name##_SHIFT) | (le32_to_cpu((ptr)->name##_WORD) & \ +	~(name##_MASK << name##_SHIFT)))))  #define bf_set(name, ptr, value) \  	((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \  		 ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT)))) @@ -781,6 +787,7 @@ struct mbox_header {  #define LPFC_MBOX_OPCODE_EQ_DESTROY		0x37  #define LPFC_MBOX_OPCODE_QUERY_FW_CFG		0x3A  #define LPFC_MBOX_OPCODE_FUNCTION_RESET		0x3D +#define LPFC_MBOX_OPCODE_MQ_CREATE_EXT		0x5A  /* FCoE Opcodes */  #define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE			0x01 @@ -1102,6 +1109,39 @@ struct lpfc_mbx_mq_create {  	} u;  }; +struct lpfc_mbx_mq_create_ext { +	struct mbox_header header; +	union { +		struct { +			uint32_t word0; +#define lpfc_mbx_mq_create_ext_num_pages_SHIFT		0 +#define lpfc_mbx_mq_create_ext_num_pages_MASK		0x0000FFFF +#define lpfc_mbx_mq_create_ext_num_pages_WORD		word0 +			uint32_t async_evt_bmap; +#define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT	LPFC_TRAILER_CODE_LINK +#define lpfc_mbx_mq_create_ext_async_evt_link_MASK	0x00000001 +#define lpfc_mbx_mq_create_ext_async_evt_link_WORD	async_evt_bmap +#define lpfc_mbx_mq_create_ext_async_evt_fcfste_SHIFT	LPFC_TRAILER_CODE_FCOE +#define lpfc_mbx_mq_create_ext_async_evt_fcfste_MASK	0x00000001 +#define lpfc_mbx_mq_create_ext_async_evt_fcfste_WORD	async_evt_bmap +#define lpfc_mbx_mq_create_ext_async_evt_group5_SHIFT	LPFC_TRAILER_CODE_GRP5 +#define lpfc_mbx_mq_create_ext_async_evt_group5_MASK	0x00000001 +#define lpfc_mbx_mq_create_ext_async_evt_group5_WORD	async_evt_bmap +			struct mq_context context; +			struct dma_address page[LPFC_MAX_MQ_PAGE]; +		} request; +		struct { +			uint32_t word0; +#define lpfc_mbx_mq_create_q_id_SHIFT	0 +#define lpfc_mbx_mq_create_q_id_MASK	0x0000FFFF +#define lpfc_mbx_mq_create_q_id_WORD	word0 +		} response; +	} u; +#define LPFC_ASYNC_EVENT_LINK_STATE	0x2 +#define LPFC_ASYNC_EVENT_FCF_STATE	0x4 +#define LPFC_ASYNC_EVENT_GROUP5		0x20 +}; +  struct lpfc_mbx_mq_destroy {  	struct mbox_header header;  	union { @@ -1428,8 +1468,8 @@ struct lpfc_mbx_reg_vfi {  #define lpfc_reg_vfi_fcfi_WORD		word2  	uint32_t wwn[2];  	struct ulp_bde64 bde; -	uint32_t word8_rsvd; -	uint32_t word9_rsvd; +	uint32_t e_d_tov; +	uint32_t r_a_tov;  	uint32_t word10;  #define lpfc_reg_vfi_nport_id_SHIFT		0  #define lpfc_reg_vfi_nport_id_MASK		0x00FFFFFF @@ -1940,6 +1980,7 @@ struct lpfc_mbx_sli4_params {  #define rdma_MASK				0x00000001  #define rdma_WORD				word3  	uint32_t sge_supp_len; +#define SLI4_PAGE_SIZE 4096  	uint32_t word5;  #define if_page_sz_SHIFT			0  #define if_page_sz_MASK				0x0000ffff @@ -2041,6 +2082,7 @@ struct lpfc_mqe {  		struct lpfc_mbx_reg_fcfi reg_fcfi;  		struct lpfc_mbx_unreg_fcfi unreg_fcfi;  		struct lpfc_mbx_mq_create mq_create; +		struct lpfc_mbx_mq_create_ext mq_create_ext;  		struct lpfc_mbx_eq_create eq_create;  		struct lpfc_mbx_cq_create cq_create;  		struct lpfc_mbx_wq_create wq_create; @@ -2099,6 +2141,7 @@ struct lpfc_mcqe {  #define LPFC_TRAILER_CODE_LINK	0x1  #define LPFC_TRAILER_CODE_FCOE	0x2  #define LPFC_TRAILER_CODE_DCBX	0x3 +#define LPFC_TRAILER_CODE_GRP5	0x5  };  struct lpfc_acqe_link { @@ -2168,6 +2211,19 @@ struct lpfc_acqe_dcbx {  	uint32_t trailer;  }; +struct lpfc_acqe_grp5 { +	uint32_t word0; +#define lpfc_acqe_grp5_pport_SHIFT	0 +#define lpfc_acqe_grp5_pport_MASK	0x000000FF +#define lpfc_acqe_grp5_pport_WORD	word0 +	uint32_t word1; +#define lpfc_acqe_grp5_llink_spd_SHIFT	16 +#define lpfc_acqe_grp5_llink_spd_MASK	0x0000FFFF +#define lpfc_acqe_grp5_llink_spd_WORD	word1 +	uint32_t event_tag; +	uint32_t trailer; +}; +  /*   * Define the bootstrap mailbox (bmbx) region used to communicate   * mailbox command between the host and port. The mailbox consists diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 774663e8e1f..cd9697edf86 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2566,7 +2566,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)  	shost->max_cmd_len = 16;  	if (phba->sli_rev == LPFC_SLI_REV4) {  		shost->dma_boundary = -			phba->sli4_hba.pc_sli4_params.sge_supp_len; +			phba->sli4_hba.pc_sli4_params.sge_supp_len-1;  		shost->sg_tablesize = phba->cfg_sg_seg_cnt;  	} @@ -2600,15 +2600,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)  	init_timer(&vport->els_tmofunc);  	vport->els_tmofunc.function = lpfc_els_timeout;  	vport->els_tmofunc.data = (unsigned long)vport; -	if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) { -		phba->menlo_flag |= HBA_MENLO_SUPPORT; -		/* check for menlo minimum sg count */ -		if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT) { -			phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT; -			shost->sg_tablesize = phba->cfg_sg_seg_cnt; -		} -	} -  	error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);  	if (error)  		goto out_put_shost; @@ -3236,12 +3227,26 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport)  	if (!vport)  		return NULL; -	ndlp = lpfc_findnode_did(vport, Fabric_DID); -	if (!ndlp) -		return NULL;  	phba = vport->phba;  	if (!phba)  		return NULL; +	ndlp = lpfc_findnode_did(vport, Fabric_DID); +	if (!ndlp) { +		/* Cannot find existing Fabric ndlp, so allocate a new one */ +		ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); +		if (!ndlp) +			return 0; +		lpfc_nlp_init(vport, ndlp, Fabric_DID); +		/* Set the node type */ +		ndlp->nlp_type |= NLP_FABRIC; +		/* Put ndlp onto node list */ +		lpfc_enqueue_node(vport, ndlp); +	} else if (!NLP_CHK_NODE_ACT(ndlp)) { +		/* re-setup ndlp without removing from node list */ +		ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); +		if (!ndlp) +			return 0; +	}  	if (phba->pport->port_state <= LPFC_FLOGI)  		return NULL;  	/* If virtual link is not yet instantiated ignore CVL */ @@ -3304,11 +3309,20 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,  	switch (event_type) {  	case LPFC_FCOE_EVENT_TYPE_NEW_FCF:  	case LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD: -		lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, -			"2546 New FCF found/FCF parameter modified event: " -			"evt_tag:x%x, fcf_index:x%x\n", -			acqe_fcoe->event_tag, acqe_fcoe->index); - +		if (event_type == LPFC_FCOE_EVENT_TYPE_NEW_FCF) +			lpfc_printf_log(phba, KERN_ERR, LOG_FIP | +					LOG_DISCOVERY, +					"2546 New FCF found event: " +					"evt_tag:x%x, fcf_index:x%x\n", +					acqe_fcoe->event_tag, +					acqe_fcoe->index); +		else +			lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | +					LOG_DISCOVERY, +					"2788 FCF parameter modified event: " +					"evt_tag:x%x, fcf_index:x%x\n", +					acqe_fcoe->event_tag, +					acqe_fcoe->index);  		spin_lock_irq(&phba->hbalock);  		if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) ||  		    (phba->hba_flag & FCF_DISC_INPROGRESS)) { @@ -3517,6 +3531,32 @@ lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba,  }  /** + * lpfc_sli4_async_grp5_evt - Process the asynchronous group5 event + * @phba: pointer to lpfc hba data structure. + * @acqe_link: pointer to the async grp5 completion queue entry. + * + * This routine is to handle the SLI4 asynchronous grp5 event. A grp5 event + * is an asynchronous notified of a logical link speed change.  The Port + * reports the logical link speed in units of 10Mbps. + **/ +static void +lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba, +			 struct lpfc_acqe_grp5 *acqe_grp5) +{ +	uint16_t prev_ll_spd; + +	phba->fc_eventTag = acqe_grp5->event_tag; +	phba->fcoe_eventtag = acqe_grp5->event_tag; +	prev_ll_spd = phba->sli4_hba.link_state.logical_speed; +	phba->sli4_hba.link_state.logical_speed = +		(bf_get(lpfc_acqe_grp5_llink_spd, acqe_grp5)); +	lpfc_printf_log(phba, KERN_INFO, LOG_SLI, +			"2789 GRP5 Async Event: Updating logical link speed " +			"from %dMbps to %dMbps\n", (prev_ll_spd * 10), +			(phba->sli4_hba.link_state.logical_speed*10)); +} + +/**   * lpfc_sli4_async_event_proc - Process all the pending asynchronous event   * @phba: pointer to lpfc hba data structure.   * @@ -3552,6 +3592,10 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba)  			lpfc_sli4_async_dcbx_evt(phba,  						 &cq_event->cqe.acqe_dcbx);  			break; +		case LPFC_TRAILER_CODE_GRP5: +			lpfc_sli4_async_grp5_evt(phba, +						 &cq_event->cqe.acqe_grp5); +			break;  		default:  			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,  					"1804 Invalid asynchrous event code: " @@ -3813,6 +3857,13 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)  	/* Get all the module params for configuring this host */  	lpfc_get_cfgparam(phba); +	if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) { +		phba->menlo_flag |= HBA_MENLO_SUPPORT; +		/* check for menlo minimum sg count */ +		if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT) +			phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT; +	} +  	/*  	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size  	 * used to create the sg_dma_buf_pool must be dynamically calculated. @@ -4030,6 +4081,43 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)  	if (unlikely(rc))  		goto out_free_bsmbx; +	mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, +						       GFP_KERNEL); +	if (!mboxq) { +		rc = -ENOMEM; +		goto out_free_bsmbx; +	} + +	/* Get the Supported Pages. It is always available. */ +	lpfc_supported_pages(mboxq); +	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); +	if (unlikely(rc)) { +		rc = -EIO; +		mempool_free(mboxq, phba->mbox_mem_pool); +		goto out_free_bsmbx; +	} + +	mqe = &mboxq->u.mqe; +	memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3), +	       LPFC_MAX_SUPPORTED_PAGES); +	for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) { +		switch (pn_page[i]) { +		case LPFC_SLI4_PARAMETERS: +			phba->sli4_hba.pc_sli4_params.supported = 1; +			break; +		default: +			break; +		} +	} + +	/* Read the port's SLI4 Parameters capabilities if supported. */ +	if (phba->sli4_hba.pc_sli4_params.supported) +		rc = lpfc_pc_sli4_params_get(phba, mboxq); +	mempool_free(mboxq, phba->mbox_mem_pool); +	if (rc) { +		rc = -EIO; +		goto out_free_bsmbx; +	}  	/* Create all the SLI4 queues */  	rc = lpfc_sli4_queue_create(phba);  	if (rc) @@ -4090,43 +4178,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)  		goto out_free_fcp_eq_hdl;  	} -	mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, -						       GFP_KERNEL); -	if (!mboxq) { -		rc = -ENOMEM; -		goto out_free_fcp_eq_hdl; -	} - -	/* Get the Supported Pages. It is always available. */ -	lpfc_supported_pages(mboxq); -	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); -	if (unlikely(rc)) { -		rc = -EIO; -		mempool_free(mboxq, phba->mbox_mem_pool); -		goto out_free_fcp_eq_hdl; -	} - -	mqe = &mboxq->u.mqe; -	memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3), -	       LPFC_MAX_SUPPORTED_PAGES); -	for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) { -		switch (pn_page[i]) { -		case LPFC_SLI4_PARAMETERS: -			phba->sli4_hba.pc_sli4_params.supported = 1; -			break; -		default: -			break; -		} -	} - -	/* Read the port's SLI4 Parameters capabilities if supported. */ -	if (phba->sli4_hba.pc_sli4_params.supported) -		rc = lpfc_pc_sli4_params_get(phba, mboxq); -	mempool_free(mboxq, phba->mbox_mem_pool); -	if (rc) { -		rc = -EIO; -		goto out_free_fcp_eq_hdl; -	}  	return rc;  out_free_fcp_eq_hdl: @@ -5050,6 +5101,8 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba)  	memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE);  	phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx); +	phba->mbox_ext = (phba->slim2p.virt + +		offsetof(struct lpfc_sli2_slim, mbx_ext_words));  	phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb));  	phba->IOCBs = (phba->slim2p.virt +  		       offsetof(struct lpfc_sli2_slim, IOCBs)); @@ -7753,21 +7806,23 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)   * @phba: pointer to lpfc hba data structure.   *   * This routine is called to prepare the SLI3 device for PCI slot recover. It - * aborts and stops all the on-going I/Os on the pci device. + * aborts all the outstanding SCSI I/Os to the pci device.   **/  static void  lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)  { +	struct lpfc_sli *psli = &phba->sli; +	struct lpfc_sli_ring  *pring; +  	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  			"2723 PCI channel I/O abort preparing for recovery\n"); -	/* Prepare for bringing HBA offline */ -	lpfc_offline_prep(phba); -	/* Clear sli active flag to prevent sysfs access to HBA */ -	spin_lock_irq(&phba->hbalock); -	phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE; -	spin_unlock_irq(&phba->hbalock); -	/* Stop and flush all I/Os and bring HBA offline */ -	lpfc_offline(phba); + +	/* +	 * There may be errored I/Os through HBA, abort all I/Os on txcmplq +	 * and let the SCSI mid-layer to retry them to recover. +	 */ +	pring = &psli->ring[psli->fcp_ring]; +	lpfc_sli_abort_iocb_ring(phba, pring);  }  /** @@ -7781,21 +7836,20 @@ lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)  static void  lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)  { -	struct lpfc_sli *psli = &phba->sli; -	struct lpfc_sli_ring  *pring; -  	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  			"2710 PCI channel disable preparing for reset\n"); + +	/* Block all SCSI devices' I/Os on the host */ +	lpfc_scsi_dev_block(phba); + +	/* stop all timers */ +	lpfc_stop_hba_timers(phba); +  	/* Disable interrupt and pci device */  	lpfc_sli_disable_intr(phba);  	pci_disable_device(phba->pcidev); -	/* -	 * There may be I/Os dropped by the firmware. -	 * Error iocb (I/O) on txcmplq and let the SCSI layer -	 * retry it after re-establishing link. -	 */ -	pring = &psli->ring[psli->fcp_ring]; -	lpfc_sli_abort_iocb_ring(phba, pring); +	/* Flush all driver's outstanding SCSI I/Os as we are to reset */ +	lpfc_sli_flush_fcp_rings(phba);  }  /** @@ -7811,6 +7865,12 @@ lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba)  {  	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  			"2711 PCI channel permanent disable for failure\n"); +	/* Block all SCSI devices' I/Os on the host */ +	lpfc_scsi_dev_block(phba); + +	/* stop all timers */ +	lpfc_stop_hba_timers(phba); +  	/* Clean up all driver's outstanding SCSI I/Os */  	lpfc_sli_flush_fcp_rings(phba);  } @@ -7839,9 +7899,6 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)  	struct Scsi_Host *shost = pci_get_drvdata(pdev);  	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; -	/* Block all SCSI devices' I/Os on the host */ -	lpfc_scsi_dev_block(phba); -  	switch (state) {  	case pci_channel_io_normal:  		/* Non-fatal error, prepare for recovery */ @@ -7948,7 +8005,7 @@ lpfc_io_resume_s3(struct pci_dev *pdev)  	struct Scsi_Host *shost = pci_get_drvdata(pdev);  	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; -	/* Bring the device online */ +	/* Bring device online, it will be no-op for non-fatal error resume */  	lpfc_online(phba);  	/* Clean up Advanced Error Reporting (AER) if needed */ diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 72e6adb0643..e84dc33ca20 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1216,7 +1216,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)  	phba->pcb->feature = FEATURE_INITIAL_SLI2;  	/* Setup Mailbox pointers */ -	phba->pcb->mailBoxSize = sizeof(MAILBOX_t); +	phba->pcb->mailBoxSize = sizeof(MAILBOX_t) + MAILBOX_EXT_SIZE;  	offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt;  	pdma_addr = phba->slim2p.phys + offset;  	phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr); @@ -1272,28 +1272,41 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)  	 *  	 */ -	if (phba->sli_rev == 3) { -		phba->host_gp = &mb_slim->us.s3.host[0]; -		phba->hbq_put = &mb_slim->us.s3.hbq_put[0]; -	} else { -		phba->host_gp = &mb_slim->us.s2.host[0]; +	if (phba->cfg_hostmem_hgp && phba->sli_rev != 3) { +		phba->host_gp = &phba->mbox->us.s2.host[0];  		phba->hbq_put = NULL; -	} +		offset = (uint8_t *)&phba->mbox->us.s2.host - +			(uint8_t *)phba->slim2p.virt; +		pdma_addr = phba->slim2p.phys + offset; +		phba->pcb->hgpAddrHigh = putPaddrHigh(pdma_addr); +		phba->pcb->hgpAddrLow = putPaddrLow(pdma_addr); +	} else { +		/* Always Host Group Pointer is in SLIM */ +		mb->un.varCfgPort.hps = 1; -	/* mask off BAR0's flag bits 0 - 3 */ -	phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + -		(void __iomem *)phba->host_gp - -		(void __iomem *)phba->MBslimaddr; -	if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) -		phba->pcb->hgpAddrHigh = bar_high; -	else -		phba->pcb->hgpAddrHigh = 0; -	/* write HGP data to SLIM at the required longword offset */ -	memset(&hgp, 0, sizeof(struct lpfc_hgp)); +		if (phba->sli_rev == 3) { +			phba->host_gp = &mb_slim->us.s3.host[0]; +			phba->hbq_put = &mb_slim->us.s3.hbq_put[0]; +		} else { +			phba->host_gp = &mb_slim->us.s2.host[0]; +			phba->hbq_put = NULL; +		} -	for (i=0; i < phba->sli.num_rings; i++) { -		lpfc_memcpy_to_slim(phba->host_gp + i, &hgp, +		/* mask off BAR0's flag bits 0 - 3 */ +		phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + +			(void __iomem *)phba->host_gp - +			(void __iomem *)phba->MBslimaddr; +		if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) +			phba->pcb->hgpAddrHigh = bar_high; +		else +			phba->pcb->hgpAddrHigh = 0; +		/* write HGP data to SLIM at the required longword offset */ +		memset(&hgp, 0, sizeof(struct lpfc_hgp)); + +		for (i = 0; i < phba->sli.num_rings; i++) { +			lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,  				    sizeof(*phba->host_gp)); +		}  	}  	/* Setup Port Group offset */ @@ -1598,7 +1611,7 @@ lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox)  	for (sgentry = 0; sgentry < sgecount; sgentry++) {  		lpfc_sli4_mbx_sge_get(mbox, sgentry, &sge);  		phyaddr = getPaddr(sge.pa_hi, sge.pa_lo); -		dma_free_coherent(&phba->pcidev->dev, PAGE_SIZE, +		dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE,  				  mbox->sge_array->addr[sgentry], phyaddr);  	}  	/* Free the sge address array memory */ @@ -1656,7 +1669,7 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,  	}  	/* Setup for the none-embedded mbox command */ -	pcount = (PAGE_ALIGN(length))/PAGE_SIZE; +	pcount = (PAGE_ALIGN(length))/SLI4_PAGE_SIZE;  	pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ?  				LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount;  	/* Allocate record for keeping SGE virtual addresses */ @@ -1671,24 +1684,24 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,  	for (pagen = 0, alloc_len = 0; pagen < pcount; pagen++) {  		/* The DMA memory is always allocated in the length of a  		 * page even though the last SGE might not fill up to a -		 * page, this is used as a priori size of PAGE_SIZE for +		 * page, this is used as a priori size of SLI4_PAGE_SIZE for  		 * the later DMA memory free.  		 */ -		viraddr = dma_alloc_coherent(&phba->pcidev->dev, PAGE_SIZE, +		viraddr = dma_alloc_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE,  					     &phyaddr, GFP_KERNEL);  		/* In case of malloc fails, proceed with whatever we have */  		if (!viraddr)  			break; -		memset(viraddr, 0, PAGE_SIZE); +		memset(viraddr, 0, SLI4_PAGE_SIZE);  		mbox->sge_array->addr[pagen] = viraddr;  		/* Keep the first page for later sub-header construction */  		if (pagen == 0)  			cfg_shdr = (union lpfc_sli4_cfg_shdr *)viraddr;  		resid_len = length - alloc_len; -		if (resid_len > PAGE_SIZE) { +		if (resid_len > SLI4_PAGE_SIZE) {  			lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr, -					      PAGE_SIZE); -			alloc_len += PAGE_SIZE; +					      SLI4_PAGE_SIZE); +			alloc_len += SLI4_PAGE_SIZE;  		} else {  			lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,  					      resid_len); @@ -1886,6 +1899,8 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)  	memcpy(reg_vfi->wwn, &vport->fc_portname, sizeof(struct lpfc_name));  	reg_vfi->wwn[0] = cpu_to_le32(reg_vfi->wwn[0]);  	reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]); +	reg_vfi->e_d_tov = vport->phba->fc_edtov; +	reg_vfi->r_a_tov = vport->phba->fc_ratov;  	reg_vfi->bde.addrHigh = putPaddrHigh(phys);  	reg_vfi->bde.addrLow = putPaddrLow(phys);  	reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam); diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index e331204a4d5..b90820a699f 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -493,6 +493,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,  	      struct lpfc_iocbq *cmdiocb, uint32_t els_cmd)  {  	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); +	struct lpfc_hba    *phba = vport->phba; +	struct lpfc_vport **vports; +	int i, active_vlink_present = 0 ;  	/* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */  	/* Only call LOGO ACC for first LOGO, this avoids sending unnecessary @@ -505,15 +508,44 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,  		lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);  	else  		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); -	if ((ndlp->nlp_DID == Fabric_DID) && -		vport->port_type == LPFC_NPIV_PORT) { +	if (ndlp->nlp_DID == Fabric_DID) { +		if (vport->port_state <= LPFC_FDISC) +			goto out;  		lpfc_linkdown_port(vport); -		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);  		spin_lock_irq(shost->host_lock); -		ndlp->nlp_flag |= NLP_DELAY_TMO; +		vport->fc_flag |= FC_VPORT_LOGO_RCVD;  		spin_unlock_irq(shost->host_lock); +		vports = lpfc_create_vport_work_array(phba); +		if (vports) { +			for (i = 0; i <= phba->max_vports && vports[i] != NULL; +					i++) { +				if ((!(vports[i]->fc_flag & +					FC_VPORT_LOGO_RCVD)) && +					(vports[i]->port_state > LPFC_FDISC)) { +					active_vlink_present = 1; +					break; +				} +			} +			lpfc_destroy_vport_work_array(phba, vports); +		} -		ndlp->nlp_last_elscmd = ELS_CMD_FDISC; +		if (active_vlink_present) { +			/* +			 * If there are other active VLinks present, +			 * re-instantiate the Vlink using FDISC. +			 */ +			mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); +			spin_lock_irq(shost->host_lock); +			ndlp->nlp_flag |= NLP_DELAY_TMO; +			spin_unlock_irq(shost->host_lock); +			ndlp->nlp_last_elscmd = ELS_CMD_FDISC; +			vport->port_state = LPFC_FDISC; +		} else { +			spin_lock_irq(shost->host_lock); +			phba->pport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG; +			spin_unlock_irq(shost->host_lock); +			lpfc_retry_pport_discovery(phba); +		}  	} else if ((!(ndlp->nlp_type & NLP_FABRIC) &&  		((ndlp->nlp_type & NLP_FCP_TARGET) ||  		!(ndlp->nlp_type & NLP_FCP_INITIATOR))) || @@ -526,6 +558,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,  		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;  	} +out:  	ndlp->nlp_prev_state = ndlp->nlp_state;  	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); @@ -604,11 +637,55 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)  	lpfc_unreg_rpi(vport, ndlp);  	return 0;  } +/** + * lpfc_release_rpi - Release a RPI by issueing unreg_login mailbox cmd. + * @phba : Pointer to lpfc_hba structure. + * @vport: Pointer to lpfc_vport structure. + * @rpi  : rpi to be release. + * + * This function will send a unreg_login mailbox command to the firmware + * to release a rpi. + **/ +void +lpfc_release_rpi(struct lpfc_hba *phba, +		struct lpfc_vport *vport, +		uint16_t rpi) +{ +	LPFC_MBOXQ_t *pmb; +	int rc; + +	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, +			GFP_KERNEL); +	if (!pmb) +		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, +			"2796 mailbox memory allocation failed \n"); +	else { +		lpfc_unreg_login(phba, vport->vpi, rpi, pmb); +		pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; +		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); +		if (rc == MBX_NOT_FINISHED) +			mempool_free(pmb, phba->mbox_mem_pool); +	} +}  static uint32_t  lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,  		  void *arg, uint32_t evt)  { +	struct lpfc_hba *phba; +	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; +	MAILBOX_t *mb; +	uint16_t rpi; + +	phba = vport->phba; +	/* Release the RPI if reglogin completing */ +	if (!(phba->pport->load_flag & FC_UNLOADING) && +		(evt == NLP_EVT_CMPL_REG_LOGIN) && +		(!pmb->u.mb.mbxStatus)) { +		mb = &pmb->u.mb; +		rpi = pmb->u.mb.un.varWords[0]; +		lpfc_release_rpi(phba, vport, rpi); +	}  	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,  			 "0271 Illegal State Transition: node x%x "  			 "event x%x, state x%x Data: x%x x%x\n", @@ -944,6 +1021,18 @@ static uint32_t  lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,  	struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)  { +	struct lpfc_hba *phba; +	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; +	MAILBOX_t *mb = &pmb->u.mb; +	uint16_t rpi; + +	phba = vport->phba; +	/* Release the RPI */ +	if (!(phba->pport->load_flag & FC_UNLOADING) && +		!mb->mbxStatus) { +		rpi = pmb->u.mb.un.varWords[0]; +		lpfc_release_rpi(phba, vport, rpi); +	}  	return ndlp->nlp_state;  } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index dccdb822328..f4a3b2e79ee 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1141,37 +1141,47 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)  }  /* - * Given a scsi cmnd, determine the BlockGuard profile to be used - * with the cmd + * Given a scsi cmnd, determine the BlockGuard opcodes to be used with it + * @sc: The SCSI command to examine + * @txopt: (out) BlockGuard operation for transmitted data + * @rxopt: (out) BlockGuard operation for received data + * + * Returns: zero on success; non-zero if tx and/or rx op cannot be determined + *   */  static int -lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc) +lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, +		uint8_t *txop, uint8_t *rxop)  {  	uint8_t guard_type = scsi_host_get_guard(sc->device->host); -	uint8_t ret_prof = LPFC_PROF_INVALID; +	uint8_t ret = 0;  	if (guard_type == SHOST_DIX_GUARD_IP) {  		switch (scsi_get_prot_op(sc)) {  		case SCSI_PROT_READ_INSERT:  		case SCSI_PROT_WRITE_STRIP: -			ret_prof = LPFC_PROF_AST2; +			*txop = BG_OP_IN_CSUM_OUT_NODIF; +			*rxop = BG_OP_IN_NODIF_OUT_CSUM;  			break;  		case SCSI_PROT_READ_STRIP:  		case SCSI_PROT_WRITE_INSERT: -			ret_prof = LPFC_PROF_A1; +			*txop = BG_OP_IN_NODIF_OUT_CRC; +			*rxop = BG_OP_IN_CRC_OUT_NODIF;  			break;  		case SCSI_PROT_READ_PASS:  		case SCSI_PROT_WRITE_PASS: -			ret_prof = LPFC_PROF_AST1; +			*txop = BG_OP_IN_CSUM_OUT_CRC; +			*rxop = BG_OP_IN_CRC_OUT_CSUM;  			break;  		case SCSI_PROT_NORMAL:  		default:  			lpfc_printf_log(phba, KERN_ERR, LOG_BG, -				"9063 BLKGRD:Bad op/guard:%d/%d combination\n", +				"9063 BLKGRD: Bad op/guard:%d/%d combination\n",  					scsi_get_prot_op(sc), guard_type); +			ret = 1;  			break;  		} @@ -1179,12 +1189,14 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)  		switch (scsi_get_prot_op(sc)) {  		case SCSI_PROT_READ_STRIP:  		case SCSI_PROT_WRITE_INSERT: -			ret_prof = LPFC_PROF_A1; +			*txop = BG_OP_IN_NODIF_OUT_CRC; +			*rxop = BG_OP_IN_CRC_OUT_NODIF;  			break;  		case SCSI_PROT_READ_PASS:  		case SCSI_PROT_WRITE_PASS: -			ret_prof = LPFC_PROF_C1; +			*txop = BG_OP_IN_CRC_OUT_CRC; +			*rxop = BG_OP_IN_CRC_OUT_CRC;  			break;  		case SCSI_PROT_READ_INSERT: @@ -1194,6 +1206,7 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)  			lpfc_printf_log(phba, KERN_ERR, LOG_BG,  				"9075 BLKGRD: Bad op/guard:%d/%d combination\n",  					scsi_get_prot_op(sc), guard_type); +			ret = 1;  			break;  		}  	} else { @@ -1201,7 +1214,7 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)  		BUG();  	} -	return ret_prof; +	return ret;  }  struct scsi_dif_tuple { @@ -1266,7 +1279,9 @@ lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask,   * The buffer list consists of just one protection group described   * below:   *                                +-------------------------+ - *   start of prot group  -->     |          PDE_1          | + *   start of prot group  -->     |          PDE_5          | + *                                +-------------------------+ + *                                |          PDE_6          |   *                                +-------------------------+   *                                |         Data BDE        |   *                                +-------------------------+ @@ -1284,30 +1299,49 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,  		struct ulp_bde64 *bpl, int datasegcnt)  {  	struct scatterlist *sgde = NULL; /* s/g data entry */ -	struct lpfc_pde *pde1 = NULL; +	struct lpfc_pde5 *pde5 = NULL; +	struct lpfc_pde6 *pde6 = NULL;  	dma_addr_t physaddr; -	int i = 0, num_bde = 0; +	int i = 0, num_bde = 0, status;  	int datadir = sc->sc_data_direction; -	int prof = LPFC_PROF_INVALID;  	unsigned blksize;  	uint32_t reftag;  	uint16_t apptagmask, apptagval; +	uint8_t txop, rxop; -	pde1 = (struct lpfc_pde *) bpl; -	prof = lpfc_sc_to_sli_prof(phba, sc); - -	if (prof == LPFC_PROF_INVALID) +	status  = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); +	if (status)  		goto out; -	/* extract some info from the scsi command for PDE1*/ +	/* extract some info from the scsi command for pde*/  	blksize = lpfc_cmd_blksize(sc);  	lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag); -	/* setup PDE1 with what we have */ -	lpfc_pde_set_bg_parms(pde1, LPFC_PDE1_DESCRIPTOR, prof, blksize, -			BG_EC_STOP_ERR); -	lpfc_pde_set_dif_parms(pde1, apptagmask, apptagval, reftag); +	/* setup PDE5 with what we have */ +	pde5 = (struct lpfc_pde5 *) bpl; +	memset(pde5, 0, sizeof(struct lpfc_pde5)); +	bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); +	pde5->reftag = reftag; + +	/* advance bpl and increment bde count */ +	num_bde++; +	bpl++; +	pde6 = (struct lpfc_pde6 *) bpl; + +	/* setup PDE6 with the rest of the info */ +	memset(pde6, 0, sizeof(struct lpfc_pde6)); +	bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR); +	bf_set(pde6_optx, pde6, txop); +	bf_set(pde6_oprx, pde6, rxop); +	if (datadir == DMA_FROM_DEVICE) { +		bf_set(pde6_ce, pde6, 1); +		bf_set(pde6_re, pde6, 1); +		bf_set(pde6_ae, pde6, 1); +	} +	bf_set(pde6_ai, pde6, 1); +	bf_set(pde6_apptagval, pde6, apptagval); +	/* advance bpl and increment bde count */  	num_bde++;  	bpl++; @@ -1342,15 +1376,17 @@ out:   * The buffer list for this type consists of one or more of the   * protection groups described below:   *                                    +-------------------------+ - *   start of first prot group  -->   |          PDE_1          | + *   start of first prot group  -->   |          PDE_5          |   *                                    +-------------------------+ - *                                    |      PDE_3 (Prot BDE)   | + *                                    |          PDE_6          | + *                                    +-------------------------+ + *                                    |      PDE_7 (Prot BDE)   |   *                                    +-------------------------+   *                                    |        Data BDE         |   *                                    +-------------------------+   *                                    |more Data BDE's ... (opt)|   *                                    +-------------------------+ - *   start of new  prot group  -->    |          PDE_1          | + *   start of new  prot group  -->    |          PDE_5          |   *                                    +-------------------------+   *                                    |          ...            |   *                                    +-------------------------+ @@ -1369,19 +1405,21 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  {  	struct scatterlist *sgde = NULL; /* s/g data entry */  	struct scatterlist *sgpe = NULL; /* s/g prot entry */ -	struct lpfc_pde *pde1 = NULL; +	struct lpfc_pde5 *pde5 = NULL; +	struct lpfc_pde6 *pde6 = NULL;  	struct ulp_bde64 *prot_bde = NULL;  	dma_addr_t dataphysaddr, protphysaddr;  	unsigned short curr_data = 0, curr_prot = 0;  	unsigned int split_offset, protgroup_len;  	unsigned int protgrp_blks, protgrp_bytes;  	unsigned int remainder, subtotal; -	int prof = LPFC_PROF_INVALID; +	int status;  	int datadir = sc->sc_data_direction;  	unsigned char pgdone = 0, alldone = 0;  	unsigned blksize;  	uint32_t reftag;  	uint16_t apptagmask, apptagval; +	uint8_t txop, rxop;  	int num_bde = 0;  	sgpe = scsi_prot_sglist(sc); @@ -1394,31 +1432,47 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  		return 0;  	} -	prof = lpfc_sc_to_sli_prof(phba, sc); -	if (prof == LPFC_PROF_INVALID) +	status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); +	if (status)  		goto out; -	/* extract some info from the scsi command for PDE1*/ +	/* extract some info from the scsi command */  	blksize = lpfc_cmd_blksize(sc);  	lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);  	split_offset = 0;  	do { -		/* setup the first PDE_1 */ -		pde1 = (struct lpfc_pde *) bpl; +		/* setup PDE5 with what we have */ +		pde5 = (struct lpfc_pde5 *) bpl; +		memset(pde5, 0, sizeof(struct lpfc_pde5)); +		bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); +		pde5->reftag = reftag; + +		/* advance bpl and increment bde count */ +		num_bde++; +		bpl++; +		pde6 = (struct lpfc_pde6 *) bpl; -		lpfc_pde_set_bg_parms(pde1, LPFC_PDE1_DESCRIPTOR, prof, blksize, -				BG_EC_STOP_ERR); -		lpfc_pde_set_dif_parms(pde1, apptagmask, apptagval, reftag); +		/* setup PDE6 with the rest of the info */ +		memset(pde6, 0, sizeof(struct lpfc_pde6)); +		bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR); +		bf_set(pde6_optx, pde6, txop); +		bf_set(pde6_oprx, pde6, rxop); +		bf_set(pde6_ce, pde6, 1); +		bf_set(pde6_re, pde6, 1); +		bf_set(pde6_ae, pde6, 1); +		bf_set(pde6_ai, pde6, 1); +		bf_set(pde6_apptagval, pde6, apptagval); +		/* advance bpl and increment bde count */  		num_bde++;  		bpl++;  		/* setup the first BDE that points to protection buffer */  		prot_bde = (struct ulp_bde64 *) bpl;  		protphysaddr = sg_dma_address(sgpe); -		prot_bde->addrLow = le32_to_cpu(putPaddrLow(protphysaddr)); -		prot_bde->addrHigh = le32_to_cpu(putPaddrHigh(protphysaddr)); +		prot_bde->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr)); +		prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));  		protgroup_len = sg_dma_len(sgpe); @@ -1429,10 +1483,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  		protgrp_bytes = protgrp_blks * blksize;  		prot_bde->tus.f.bdeSize = protgroup_len; -		if (datadir == DMA_TO_DEVICE) -			prot_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; -		else -			prot_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; +		prot_bde->tus.f.bdeFlags = LPFC_PDE7_DESCRIPTOR;  		prot_bde->tus.w = le32_to_cpu(bpl->tus.w);  		curr_prot++; @@ -1484,6 +1535,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  			/* Move to the next s/g segment if possible */  			sgde = sg_next(sgde); +  		}  		/* are we done ? */ @@ -1506,7 +1558,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  out: -  	return num_bde;  }  /* @@ -1828,8 +1879,8 @@ out:   * field of @lpfc_cmd for device with SLI-4 interface spec.   *   * Return codes: - * 	1 - Error - * 	0 - Success + *	1 - Error + *	0 - Success   **/  static int  lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) @@ -1937,8 +1988,8 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)   * lpfc_hba struct.   *   * Return codes: - * 	1 - Error - * 	0 - Success + *	1 - Error + *	0 - Success   **/  static inline int  lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 049fb9a17b3..7a61455140b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -212,7 +212,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)  	struct lpfc_eqe *eqe = q->qe[q->hba_index].eqe;  	/* If the next EQE is not valid then we are done */ -	if (!bf_get(lpfc_eqe_valid, eqe)) +	if (!bf_get_le32(lpfc_eqe_valid, eqe))  		return NULL;  	/* If the host has not yet processed the next entry then we are done */  	if (((q->hba_index + 1) % q->entry_count) == q->host_index) @@ -247,7 +247,7 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)  	/* while there are valid entries */  	while (q->hba_index != q->host_index) {  		temp_eqe = q->qe[q->host_index].eqe; -		bf_set(lpfc_eqe_valid, temp_eqe, 0); +		bf_set_le32(lpfc_eqe_valid, temp_eqe, 0);  		released++;  		q->host_index = ((q->host_index + 1) % q->entry_count);  	} @@ -285,7 +285,7 @@ lpfc_sli4_cq_get(struct lpfc_queue *q)  	struct lpfc_cqe *cqe;  	/* If the next CQE is not valid then we are done */ -	if (!bf_get(lpfc_cqe_valid, q->qe[q->hba_index].cqe)) +	if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe))  		return NULL;  	/* If the host has not yet processed the next entry then we are done */  	if (((q->hba_index + 1) % q->entry_count) == q->host_index) @@ -321,7 +321,7 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)  	/* while there are valid entries */  	while (q->hba_index != q->host_index) {  		temp_qe = q->qe[q->host_index].cqe; -		bf_set(lpfc_cqe_valid, temp_qe, 0); +		bf_set_le32(lpfc_cqe_valid, temp_qe, 0);  		released++;  		q->host_index = ((q->host_index + 1) % q->entry_count);  	} @@ -1659,6 +1659,8 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)  	case MBX_INIT_VPI:  	case MBX_INIT_VFI:  	case MBX_RESUME_RPI: +	case MBX_READ_EVENT_LOG_STATUS: +	case MBX_READ_EVENT_LOG:  		ret = mbxCommand;  		break;  	default: @@ -4296,7 +4298,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)  			"2570 Failed to read FCoE parameters\n");  	/* Issue READ_REV to collect vpd and FW information. */ -	vpd_size = PAGE_SIZE; +	vpd_size = SLI4_PAGE_SIZE;  	vpd = kzalloc(vpd_size, GFP_KERNEL);  	if (!vpd) {  		rc = -ENOMEM; @@ -4891,9 +4893,34 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,  	mb->mbxOwner = OWN_CHIP;  	if (psli->sli_flag & LPFC_SLI_ACTIVE) { -		/* First copy command data to host SLIM area */ +		/* Populate mbox extension offset word. */ +		if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) { +			*(((uint32_t *)mb) + pmbox->mbox_offset_word) +				= (uint8_t *)phba->mbox_ext +				  - (uint8_t *)phba->mbox; +		} + +		/* Copy the mailbox extension data */ +		if (pmbox->in_ext_byte_len && pmbox->context2) { +			lpfc_sli_pcimem_bcopy(pmbox->context2, +				(uint8_t *)phba->mbox_ext, +				pmbox->in_ext_byte_len); +		} +		/* Copy command data to host SLIM area */  		lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);  	} else { +		/* Populate mbox extension offset word. */ +		if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) +			*(((uint32_t *)mb) + pmbox->mbox_offset_word) +				= MAILBOX_HBA_EXT_OFFSET; + +		/* Copy the mailbox extension data */ +		if (pmbox->in_ext_byte_len && pmbox->context2) { +			lpfc_memcpy_to_slim(phba->MBslimaddr + +				MAILBOX_HBA_EXT_OFFSET, +				pmbox->context2, pmbox->in_ext_byte_len); + +		}  		if (mb->mbxCommand == MBX_CONFIG_PORT) {  			/* copy command data into host mbox for cmpl */  			lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); @@ -5003,15 +5030,22 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,  		if (psli->sli_flag & LPFC_SLI_ACTIVE) {  			/* copy results back to user */  			lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE); +			/* Copy the mailbox extension data */ +			if (pmbox->out_ext_byte_len && pmbox->context2) { +				lpfc_sli_pcimem_bcopy(phba->mbox_ext, +						      pmbox->context2, +						      pmbox->out_ext_byte_len); +			}  		} else {  			/* First copy command data */  			lpfc_memcpy_from_slim(mb, phba->MBslimaddr,  							MAILBOX_CMD_SIZE); -			if ((mb->mbxCommand == MBX_DUMP_MEMORY) && -				pmbox->context2) { -				lpfc_memcpy_from_slim((void *)pmbox->context2, -				      phba->MBslimaddr + DMP_RSP_OFFSET, -						      mb->un.varDmp.word_cnt); +			/* Copy the mailbox extension data */ +			if (pmbox->out_ext_byte_len && pmbox->context2) { +				lpfc_memcpy_from_slim(pmbox->context2, +					phba->MBslimaddr + +					MAILBOX_HBA_EXT_OFFSET, +					pmbox->out_ext_byte_len);  			}  		} @@ -7104,13 +7138,11 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,  			 */  			list_del_init(&abort_iocb->list);  			pring->txcmplq_cnt--; -			spin_unlock_irq(&phba->hbalock);  			/* Firmware could still be in progress of DMAing  			 * payload, so don't free data buffer till after  			 * a hbeat.  			 */ -			spin_lock_irq(&phba->hbalock);  			abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;  			abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;  			spin_unlock_irq(&phba->hbalock); @@ -7118,7 +7150,8 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,  			abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;  			abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED;  			(abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb); -		} +		} else +			spin_unlock_irq(&phba->hbalock);  	}  	lpfc_sli_release_iocbq(phba, cmdiocb); @@ -8133,6 +8166,12 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id)  				if (pmb->mbox_cmpl) {  					lpfc_sli_pcimem_bcopy(mbox, pmbox,  							MAILBOX_CMD_SIZE); +					if (pmb->out_ext_byte_len && +						pmb->context2) +						lpfc_sli_pcimem_bcopy( +						phba->mbox_ext, +						pmb->context2, +						pmb->out_ext_byte_len);  				}  				if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {  					pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; @@ -8983,17 +9022,17 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)  	int ecount = 0;  	uint16_t cqid; -	if (bf_get(lpfc_eqe_major_code, eqe) != 0) { +	if (bf_get_le32(lpfc_eqe_major_code, eqe) != 0) {  		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,  				"0359 Not a valid slow-path completion "  				"event: majorcode=x%x, minorcode=x%x\n", -				bf_get(lpfc_eqe_major_code, eqe), -				bf_get(lpfc_eqe_minor_code, eqe)); +				bf_get_le32(lpfc_eqe_major_code, eqe), +				bf_get_le32(lpfc_eqe_minor_code, eqe));  		return;  	}  	/* Get the reference to the corresponding CQ */ -	cqid = bf_get(lpfc_eqe_resource_id, eqe); +	cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);  	/* Search for completion queue pointer matching this cqid */  	speq = phba->sli4_hba.sp_eq; @@ -9221,12 +9260,12 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,  	uint16_t cqid;  	int ecount = 0; -	if (unlikely(bf_get(lpfc_eqe_major_code, eqe) != 0)) { +	if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) {  		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,  				"0366 Not a valid fast-path completion "  				"event: majorcode=x%x, minorcode=x%x\n", -				bf_get(lpfc_eqe_major_code, eqe), -				bf_get(lpfc_eqe_minor_code, eqe)); +				bf_get_le32(lpfc_eqe_major_code, eqe), +				bf_get_le32(lpfc_eqe_minor_code, eqe));  		return;  	} @@ -9239,7 +9278,7 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,  	}  	/* Get the reference to the corresponding CQ */ -	cqid = bf_get(lpfc_eqe_resource_id, eqe); +	cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);  	if (unlikely(cqid != cq->queue_id)) {  		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,  				"0368 Miss-matched fast-path completion " @@ -9506,7 +9545,7 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)  	while (!list_empty(&queue->page_list)) {  		list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf,  				 list); -		dma_free_coherent(&queue->phba->pcidev->dev, PAGE_SIZE, +		dma_free_coherent(&queue->phba->pcidev->dev, SLI4_PAGE_SIZE,  				  dmabuf->virt, dmabuf->phys);  		kfree(dmabuf);  	} @@ -9532,13 +9571,17 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,  	struct lpfc_dmabuf *dmabuf;  	int x, total_qe_count;  	void *dma_pointer; +	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; +	if (!phba->sli4_hba.pc_sli4_params.supported) +		hw_page_size = SLI4_PAGE_SIZE;  	queue = kzalloc(sizeof(struct lpfc_queue) +  			(sizeof(union sli4_qe) * entry_count), GFP_KERNEL);  	if (!queue)  		return NULL; -	queue->page_count = (PAGE_ALIGN(entry_size * entry_count))/PAGE_SIZE; +	queue->page_count = (ALIGN(entry_size * entry_count, +			hw_page_size))/hw_page_size;  	INIT_LIST_HEAD(&queue->list);  	INIT_LIST_HEAD(&queue->page_list);  	INIT_LIST_HEAD(&queue->child_list); @@ -9547,19 +9590,19 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,  		if (!dmabuf)  			goto out_fail;  		dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, -						  PAGE_SIZE, &dmabuf->phys, +						  hw_page_size, &dmabuf->phys,  						  GFP_KERNEL);  		if (!dmabuf->virt) {  			kfree(dmabuf);  			goto out_fail;  		} -		memset(dmabuf->virt, 0, PAGE_SIZE); +		memset(dmabuf->virt, 0, hw_page_size);  		dmabuf->buffer_tag = x;  		list_add_tail(&dmabuf->list, &queue->page_list);  		/* initialize queue's entry array */  		dma_pointer = dmabuf->virt;  		for (; total_qe_count < entry_count && -		     dma_pointer < (PAGE_SIZE + dmabuf->virt); +		     dma_pointer < (hw_page_size + dmabuf->virt);  		     total_qe_count++, dma_pointer += entry_size) {  			queue->qe[total_qe_count].address = dma_pointer;  		} @@ -9604,6 +9647,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)  	uint32_t shdr_status, shdr_add_status;  	union lpfc_sli4_cfg_shdr *shdr;  	uint16_t dmult; +	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + +	if (!phba->sli4_hba.pc_sli4_params.supported) +		hw_page_size = SLI4_PAGE_SIZE;  	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);  	if (!mbox) @@ -9653,6 +9700,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)  		break;  	}  	list_for_each_entry(dmabuf, &eq->page_list, list) { +		memset(dmabuf->virt, 0, hw_page_size);  		eq_create->u.request.page[dmabuf->buffer_tag].addr_lo =  					putPaddrLow(dmabuf->phys);  		eq_create->u.request.page[dmabuf->buffer_tag].addr_hi = @@ -9715,6 +9763,11 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,  	int rc, length, status = 0;  	uint32_t shdr_status, shdr_add_status;  	union lpfc_sli4_cfg_shdr *shdr; +	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + +	if (!phba->sli4_hba.pc_sli4_params.supported) +		hw_page_size = SLI4_PAGE_SIZE; +  	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);  	if (!mbox) @@ -9752,6 +9805,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,  		break;  	}  	list_for_each_entry(dmabuf, &cq->page_list, list) { +		memset(dmabuf->virt, 0, hw_page_size);  		cq_create->u.request.page[dmabuf->buffer_tag].addr_lo =  					putPaddrLow(dmabuf->phys);  		cq_create->u.request.page[dmabuf->buffer_tag].addr_hi = @@ -9791,9 +9845,70 @@ out:  }  /** + * lpfc_mq_create_fb_init - Send MCC_CREATE without async events registration + * @phba: HBA structure that indicates port to create a queue on. + * @mq: The queue structure to use to create the mailbox queue. + * @mbox: An allocated pointer to type LPFC_MBOXQ_t + * @cq: The completion queue to associate with this cq. + * + * This function provides failback (fb) functionality when the + * mq_create_ext fails on older FW generations.  It's purpose is identical + * to mq_create_ext otherwise. + * + * This routine cannot fail as all attributes were previously accessed and + * initialized in mq_create_ext. + **/ +static void +lpfc_mq_create_fb_init(struct lpfc_hba *phba, struct lpfc_queue *mq, +		       LPFC_MBOXQ_t *mbox, struct lpfc_queue *cq) +{ +	struct lpfc_mbx_mq_create *mq_create; +	struct lpfc_dmabuf *dmabuf; +	int length; + +	length = (sizeof(struct lpfc_mbx_mq_create) - +		  sizeof(struct lpfc_sli4_cfg_mhdr)); +	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, +			 LPFC_MBOX_OPCODE_MQ_CREATE, +			 length, LPFC_SLI4_MBX_EMBED); +	mq_create = &mbox->u.mqe.un.mq_create; +	bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request, +	       mq->page_count); +	bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context, +	       cq->queue_id); +	bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1); +	switch (mq->entry_count) { +	case 16: +		bf_set(lpfc_mq_context_count, &mq_create->u.request.context, +		       LPFC_MQ_CNT_16); +		break; +	case 32: +		bf_set(lpfc_mq_context_count, &mq_create->u.request.context, +		       LPFC_MQ_CNT_32); +		break; +	case 64: +		bf_set(lpfc_mq_context_count, &mq_create->u.request.context, +		       LPFC_MQ_CNT_64); +		break; +	case 128: +		bf_set(lpfc_mq_context_count, &mq_create->u.request.context, +		       LPFC_MQ_CNT_128); +		break; +	} +	list_for_each_entry(dmabuf, &mq->page_list, list) { +		mq_create->u.request.page[dmabuf->buffer_tag].addr_lo = +			putPaddrLow(dmabuf->phys); +		mq_create->u.request.page[dmabuf->buffer_tag].addr_hi = +			putPaddrHigh(dmabuf->phys); +	} +} + +/**   * lpfc_mq_create - Create a mailbox Queue on the HBA   * @phba: HBA structure that indicates port to create a queue on.   * @mq: The queue structure to use to create the mailbox queue. + * @cq: The completion queue to associate with this cq. + * @subtype: The queue's subtype.   *   * This function creates a mailbox queue, as detailed in @mq, on a port,   * described by @phba by sending a MQ_CREATE mailbox command to the HBA. @@ -9809,31 +9924,43 @@ out:   * memory this function will return ENOMEM. If the queue create mailbox command   * fails this function will return ENXIO.   **/ -uint32_t +int32_t  lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,  	       struct lpfc_queue *cq, uint32_t subtype)  {  	struct lpfc_mbx_mq_create *mq_create; +	struct lpfc_mbx_mq_create_ext *mq_create_ext;  	struct lpfc_dmabuf *dmabuf;  	LPFC_MBOXQ_t *mbox;  	int rc, length, status = 0;  	uint32_t shdr_status, shdr_add_status;  	union lpfc_sli4_cfg_shdr *shdr; +	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + +	if (!phba->sli4_hba.pc_sli4_params.supported) +		hw_page_size = SLI4_PAGE_SIZE;  	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);  	if (!mbox)  		return -ENOMEM; -	length = (sizeof(struct lpfc_mbx_mq_create) - +	length = (sizeof(struct lpfc_mbx_mq_create_ext) -  		  sizeof(struct lpfc_sli4_cfg_mhdr));  	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, -			 LPFC_MBOX_OPCODE_MQ_CREATE, +			 LPFC_MBOX_OPCODE_MQ_CREATE_EXT,  			 length, LPFC_SLI4_MBX_EMBED); -	mq_create = &mbox->u.mqe.un.mq_create; -	bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request, + +	mq_create_ext = &mbox->u.mqe.un.mq_create_ext; +	bf_set(lpfc_mbx_mq_create_ext_num_pages, &mq_create_ext->u.request,  		    mq->page_count); -	bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context, -		    cq->queue_id); -	bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1); +	bf_set(lpfc_mbx_mq_create_ext_async_evt_link, &mq_create_ext->u.request, +	       1); +	bf_set(lpfc_mbx_mq_create_ext_async_evt_fcfste, +	       &mq_create_ext->u.request, 1); +	bf_set(lpfc_mbx_mq_create_ext_async_evt_group5, +	       &mq_create_ext->u.request, 1); +	bf_set(lpfc_mq_context_cq_id, &mq_create_ext->u.request.context, +	       cq->queue_id); +	bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1);  	switch (mq->entry_count) {  	default:  		lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -9843,31 +9970,47 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,  			return -EINVAL;  		/* otherwise default to smallest count (drop through) */  	case 16: -		bf_set(lpfc_mq_context_count, &mq_create->u.request.context, +		bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,  		       LPFC_MQ_CNT_16);  		break;  	case 32: -		bf_set(lpfc_mq_context_count, &mq_create->u.request.context, +		bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,  		       LPFC_MQ_CNT_32);  		break;  	case 64: -		bf_set(lpfc_mq_context_count, &mq_create->u.request.context, +		bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,  		       LPFC_MQ_CNT_64);  		break;  	case 128: -		bf_set(lpfc_mq_context_count, &mq_create->u.request.context, +		bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,  		       LPFC_MQ_CNT_128);  		break;  	}  	list_for_each_entry(dmabuf, &mq->page_list, list) { -		mq_create->u.request.page[dmabuf->buffer_tag].addr_lo = +		memset(dmabuf->virt, 0, hw_page_size); +		mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_lo =  					putPaddrLow(dmabuf->phys); -		mq_create->u.request.page[dmabuf->buffer_tag].addr_hi = +		mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_hi =  					putPaddrHigh(dmabuf->phys);  	}  	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); +	shdr = (union lpfc_sli4_cfg_shdr *) &mq_create_ext->header.cfg_shdr; +	mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, +			      &mq_create_ext->u.response); +	if (rc != MBX_SUCCESS) { +		lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +				"2795 MQ_CREATE_EXT failed with " +				"status x%x. Failback to MQ_CREATE.\n", +				rc); +		lpfc_mq_create_fb_init(phba, mq, mbox, cq); +		mq_create = &mbox->u.mqe.un.mq_create; +		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); +		shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr; +		mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, +				      &mq_create->u.response); +	} +  	/* The IOCTL status is embedded in the mailbox subheader. */ -	shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr;  	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);  	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);  	if (shdr_status || shdr_add_status || rc) { @@ -9878,7 +10021,6 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,  		status = -ENXIO;  		goto out;  	} -	mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, &mq_create->u.response);  	if (mq->queue_id == 0xFFFF) {  		status = -ENXIO;  		goto out; @@ -9927,6 +10069,10 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,  	int rc, length, status = 0;  	uint32_t shdr_status, shdr_add_status;  	union lpfc_sli4_cfg_shdr *shdr; +	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + +	if (!phba->sli4_hba.pc_sli4_params.supported) +		hw_page_size = SLI4_PAGE_SIZE;  	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);  	if (!mbox) @@ -9942,6 +10088,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,  	bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request,  		    cq->queue_id);  	list_for_each_entry(dmabuf, &wq->page_list, list) { +		memset(dmabuf->virt, 0, hw_page_size);  		wq_create->u.request.page[dmabuf->buffer_tag].addr_lo =  					putPaddrLow(dmabuf->phys);  		wq_create->u.request.page[dmabuf->buffer_tag].addr_hi = @@ -10010,6 +10157,10 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,  	int rc, length, status = 0;  	uint32_t shdr_status, shdr_add_status;  	union lpfc_sli4_cfg_shdr *shdr; +	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + +	if (!phba->sli4_hba.pc_sli4_params.supported) +		hw_page_size = SLI4_PAGE_SIZE;  	if (hrq->entry_count != drq->entry_count)  		return -EINVAL; @@ -10054,6 +10205,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,  	bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context,  	       LPFC_HDR_BUF_SIZE);  	list_for_each_entry(dmabuf, &hrq->page_list, list) { +		memset(dmabuf->virt, 0, hw_page_size);  		rq_create->u.request.page[dmabuf->buffer_tag].addr_lo =  					putPaddrLow(dmabuf->phys);  		rq_create->u.request.page[dmabuf->buffer_tag].addr_hi = @@ -10626,7 +10778,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)  	reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +  		 sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); -	if (reqlen > PAGE_SIZE) { +	if (reqlen > SLI4_PAGE_SIZE) {  		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,  				"2559 Block sgl registration required DMA "  				"size (%d) great than a page\n", reqlen); @@ -10732,7 +10884,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,  	/* Calculate the requested length of the dma memory */  	reqlen = cnt * sizeof(struct sgl_page_pairs) +  		 sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); -	if (reqlen > PAGE_SIZE) { +	if (reqlen > SLI4_PAGE_SIZE) {  		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,  				"0217 Block sgl registration required DMA "  				"size (%d) great than a page\n", reqlen); @@ -11568,8 +11720,8 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,   *   * This routine is invoked to post rpi header templates to the   * HBA consistent with the SLI-4 interface spec.  This routine - * posts a PAGE_SIZE memory region to the port to hold up to - * PAGE_SIZE modulo 64 rpi context headers. + * posts a SLI4_PAGE_SIZE memory region to the port to hold up to + * SLI4_PAGE_SIZE modulo 64 rpi context headers.   *   * This routine does not require any locks.  It's usage is expected   * to be driver load or reset recovery when the driver is @@ -11672,8 +11824,8 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)   *   * This routine is invoked to post rpi header templates to the   * HBA consistent with the SLI-4 interface spec.  This routine - * posts a PAGE_SIZE memory region to the port to hold up to - * PAGE_SIZE modulo 64 rpi context headers. + * posts a SLI4_PAGE_SIZE memory region to the port to hold up to + * SLI4_PAGE_SIZE modulo 64 rpi context headers.   *   * Returns   * 	A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful @@ -12040,9 +12192,11 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)  		phba->hba_flag |= FCF_DISC_INPROGRESS;  		spin_unlock_irq(&phba->hbalock);  		/* Reset FCF round robin index bmask for new scan */ -		if (fcf_index == LPFC_FCOE_FCF_GET_FIRST) +		if (fcf_index == LPFC_FCOE_FCF_GET_FIRST) {  			memset(phba->fcf.fcf_rr_bmask, 0,  			       sizeof(*phba->fcf.fcf_rr_bmask)); +			phba->fcf.eligible_fcf_cnt = 0; +		}  		error = 0;  	}  fail_fcf_scan: @@ -12507,6 +12661,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)  	struct lpfc_hba *phba = vport->phba;  	LPFC_MBOXQ_t *mb, *nextmb;  	struct lpfc_dmabuf *mp; +	struct lpfc_nodelist *ndlp;  	spin_lock_irq(&phba->hbalock);  	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { @@ -12523,6 +12678,11 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)  				__lpfc_mbuf_free(phba, mp->virt, mp->phys);  				kfree(mp);  			} +			ndlp = (struct lpfc_nodelist *) mb->context2; +			if (ndlp) { +				lpfc_nlp_put(ndlp); +				mb->context2 = NULL; +			}  		}  		list_del(&mb->list);  		mempool_free(mb, phba->mbox_mem_pool); @@ -12532,6 +12692,15 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)  		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) ||  			(mb->u.mb.mbxCommand == MBX_REG_VPI))  			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; +		if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { +			ndlp = (struct lpfc_nodelist *) mb->context2; +			if (ndlp) { +				lpfc_nlp_put(ndlp); +				mb->context2 = NULL; +			} +			/* Unregister the RPI when mailbox complete */ +			mb->mbox_flag |= LPFC_MBX_IMED_UNREG; +		}  	}  	spin_unlock_irq(&phba->hbalock);  } diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index b4a639c4761..e3792151ca0 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -36,6 +36,7 @@ struct lpfc_cq_event {  		struct lpfc_acqe_link		acqe_link;  		struct lpfc_acqe_fcoe		acqe_fcoe;  		struct lpfc_acqe_dcbx		acqe_dcbx; +		struct lpfc_acqe_grp5		acqe_grp5;  		struct lpfc_rcqe		rcqe_cmpl;  		struct sli4_wcqe_xri_aborted	wcqe_axri;  		struct lpfc_wcqe_complete	wcqe_cmpl; @@ -110,6 +111,9 @@ typedef struct lpfcMboxq {  	void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);  	uint8_t mbox_flag; +	uint16_t in_ext_byte_len; +	uint16_t out_ext_byte_len; +	uint8_t  mbox_offset_word;  	struct lpfc_mcqe mcqe;  	struct lpfc_mbx_nembed_sge_virt *sge_array;  } LPFC_MBOXQ_t; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 4a35e7b9bc5..58bb4c81b54 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -162,6 +162,7 @@ struct lpfc_fcf {  #define FCF_REDISC_FOV	0x200 /* Post FCF rediscovery fast failover */  	uint32_t addr_mode;  	uint16_t fcf_rr_init_indx; +	uint32_t eligible_fcf_cnt;  	struct lpfc_fcf_rec current_rec;  	struct lpfc_fcf_rec failover_rec;  	struct timer_list redisc_wait; @@ -492,8 +493,8 @@ void lpfc_sli4_queue_free(struct lpfc_queue *);  uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t);  uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *,  			struct lpfc_queue *, uint32_t, uint32_t); -uint32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *, -			struct lpfc_queue *, uint32_t); +int32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *, +		       struct lpfc_queue *, uint32_t);  uint32_t lpfc_wq_create(struct lpfc_hba *, struct lpfc_queue *,  			struct lpfc_queue *, uint32_t);  uint32_t lpfc_rq_create(struct lpfc_hba *, struct lpfc_queue *, diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 013deec5dae..5294c3a515a 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@   * included with this package.                                     *   *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.10" +#define LPFC_DRIVER_VERSION "8.3.12"  #define LPFC_DRIVER_NAME		"lpfc"  #define LPFC_SP_DRIVER_HANDLER_NAME	"lpfc:sp"  #define LPFC_FP_DRIVER_HANDLER_NAME	"lpfc:fp" diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index ffd575c379f..ab91359bde2 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -763,7 +763,9 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)  	spin_lock_irq(&phba->hbalock);  	list_for_each_entry(port_iterator, &phba->port_list, listentry) {  		if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) { -			lpfc_printf_vlog(port_iterator, KERN_WARNING, LOG_VPORT, +			if (!(port_iterator->load_flag & FC_UNLOADING)) +				lpfc_printf_vlog(port_iterator, KERN_ERR, +					 LOG_VPORT,  					 "1801 Create vport work array FAILED: "  					 "cannot do scsi_host_get\n");  			continue; diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig index ba8e128de23..bbb7e4bf30a 100644 --- a/drivers/scsi/mpt2sas/Kconfig +++ b/drivers/scsi/mpt2sas/Kconfig @@ -2,7 +2,7 @@  # Kernel configuration file for the MPT2SAS  #  # This code is based on drivers/scsi/mpt2sas/Kconfig -# Copyright (C) 2007-2009  LSI Corporation +# Copyright (C) 2007-2010  LSI Corporation  #  (mailto:DL-MPTFusionLinux@lsi.com)  # This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 9958d847a88..dada0a13223 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2009 LSI Corporation. + *  Copyright (c) 2000-2010 LSI Corporation.   *   *   *           Name:  mpi2.h diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index cf0ac9f40c9..d4e9d6f8452 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2009 LSI Corporation. + *  Copyright (c) 2000-2010 LSI Corporation.   *   *   *           Name:  mpi2_cnfg.h diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt index c4adf76b49d..bd6c92b5fae 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt +++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt @@ -2,7 +2,7 @@   Fusion-MPT MPI 2.0 Header File Change History   ============================== - Copyright (c) 2000-2009 LSI Corporation. + Copyright (c) 2000-2010 LSI Corporation.   ---------------------------------------   Header Set Release Version:    02.00.14 diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h index 6541945e97c..220bf65a921 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2009 LSI Corporation. + *  Copyright (c) 2000-2010 LSI Corporation.   *   *   *           Name:  mpi2_init.h diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 754938422f6..f18f114922b 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2009 LSI Corporation. + *  Copyright (c) 2000-2010 LSI Corporation.   *   *   *           Name:  mpi2_ioc.h diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h index 73fcdbf9263..686b09b8121 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2009 LSI Corporation. + *  Copyright (c) 2000-2010 LSI Corporation.   *   *   *           Name:  mpi2_tool.h diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 88e6eebc315..b830d61684d 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3,7 +3,7 @@   * for access to MPT (Message Passing Technology) firmware.   *   * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -58,6 +58,7 @@  #include <linux/sort.h>  #include <linux/io.h>  #include <linux/time.h> +#include <linux/aer.h>  #include "mpt2sas_base.h" @@ -285,6 +286,9 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,  	    request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)  		return; +	if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) +		return; +  	switch (ioc_status) {  /**************************************************************************** @@ -517,8 +521,18 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc,  		desc = "IR Operation Status";  		break;  	case MPI2_EVENT_SAS_DISCOVERY: -		desc =  "Discovery"; -		break; +	{ +		Mpi2EventDataSasDiscovery_t *event_data = +		    (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; +		printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name, +		    (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? +		    "start" : "stop"); +		if (event_data->DiscoveryStatus) +			printk("discovery_status(0x%08x)", +			    le32_to_cpu(event_data->DiscoveryStatus)); +			printk("\n"); +		return; +	}  	case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:  		desc = "SAS Broadcast Primitive";  		break; @@ -1243,6 +1257,9 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  		goto out_fail;  	} +	/* AER (Advanced Error Reporting) hooks */ +	pci_enable_pcie_error_reporting(pdev); +  	pci_set_master(pdev);  	if (_base_config_dma_addressing(ioc, pdev) != 0) { @@ -1253,7 +1270,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  	}  	for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) { -		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { +		if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {  			if (pio_sz)  				continue;  			pio_chip = (u64)pci_resource_start(pdev, i); @@ -1261,15 +1278,18 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  		} else {  			if (memap_sz)  				continue; -			ioc->chip_phys = pci_resource_start(pdev, i); -			chip_phys = (u64)ioc->chip_phys; -			memap_sz = pci_resource_len(pdev, i); -			ioc->chip = ioremap(ioc->chip_phys, memap_sz); -			if (ioc->chip == NULL) { -				printk(MPT2SAS_ERR_FMT "unable to map adapter " -				    "memory!\n", ioc->name); -				r = -EINVAL; -				goto out_fail; +			/* verify memory resource is valid before using */ +			if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { +				ioc->chip_phys = pci_resource_start(pdev, i); +				chip_phys = (u64)ioc->chip_phys; +				memap_sz = pci_resource_len(pdev, i); +				ioc->chip = ioremap(ioc->chip_phys, memap_sz); +				if (ioc->chip == NULL) { +					printk(MPT2SAS_ERR_FMT "unable to map " +					    "adapter memory!\n", ioc->name); +					r = -EINVAL; +					goto out_fail; +				}  			}  		}  	} @@ -1295,6 +1315,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  	ioc->chip_phys = 0;  	ioc->pci_irq = -1;  	pci_release_selected_regions(ioc->pdev, ioc->bars); +	pci_disable_pcie_error_reporting(pdev);  	pci_disable_device(pdev);  	return r;  } @@ -1898,7 +1919,10 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)  		    ioc->config_page, ioc->config_page_dma);  	} -	kfree(ioc->scsi_lookup); +	if (ioc->scsi_lookup) { +		free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages); +		ioc->scsi_lookup = NULL; +	}  	kfree(ioc->hpr_lookup);  	kfree(ioc->internal_lookup);  } @@ -2110,11 +2134,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	    ioc->name, (unsigned long long) ioc->request_dma));  	total_sz += sz; -	ioc->scsi_lookup = kcalloc(ioc->scsiio_depth, -	    sizeof(struct request_tracker), GFP_KERNEL); +	sz = ioc->scsiio_depth * sizeof(struct request_tracker); +	ioc->scsi_lookup_pages = get_order(sz); +	ioc->scsi_lookup = (struct request_tracker *)__get_free_pages( +	    GFP_KERNEL, ioc->scsi_lookup_pages);  	if (!ioc->scsi_lookup) { -		printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n", -		    ioc->name); +		printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, " +		    "sz(%d)\n", ioc->name, (int)sz);  		goto out;  	} @@ -3006,8 +3032,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	 * since epoch ~ midnight January 1, 1970.  	 */  	do_gettimeofday(¤t_time); -	mpi_request.TimeStamp = (current_time.tv_sec * 1000) + -	    (current_time.tv_usec >> 3); +	mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 + +	    (current_time.tv_usec / 1000));  	if (ioc->logging_level & MPT_DEBUG_INIT) {  		u32 *mfp; @@ -3179,7 +3205,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	mpi_request->VP_ID = 0;  	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)  		mpi_request->EventMasks[i] = -		    le32_to_cpu(ioc->event_masks[i]); +		    cpu_to_le32(ioc->event_masks[i]);  	mpt2sas_base_put_smid_default(ioc, smid);  	init_completion(&ioc->base_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); @@ -3516,7 +3542,9 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)  	    __func__));  	_base_mask_interrupts(ioc); +	ioc->shost_recovery = 1;  	_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); +	ioc->shost_recovery = 0;  	if (ioc->pci_irq) {  		synchronize_irq(pdev->irq);  		free_irq(ioc->pci_irq, ioc); @@ -3527,6 +3555,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)  	ioc->pci_irq = -1;  	ioc->chip_phys = 0;  	pci_release_selected_regions(ioc->pdev, ioc->bars); +	pci_disable_pcie_error_reporting(pdev);  	pci_disable_device(pdev);  	return;  } @@ -3560,8 +3589,10 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,  	    sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); -	if (!ioc->pfacts) +	if (!ioc->pfacts) { +		r = -ENOMEM;  		goto out_free_resources; +	}  	for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {  		r = _base_get_port_facts(ioc, i, CAN_SLEEP); @@ -3607,6 +3638,15 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;  	mutex_init(&ioc->ctl_cmds.mutex); +	if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || +	    !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || +	    !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) { +		r = -ENOMEM; +		goto out_free_resources; +	} + +	init_completion(&ioc->shost_recovery_done); +  	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)  		ioc->event_masks[i] = -1; @@ -3639,6 +3679,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	pci_set_drvdata(ioc->pdev, NULL);  	kfree(ioc->tm_cmds.reply);  	kfree(ioc->transport_cmds.reply); +	kfree(ioc->scsih_cmds.reply);  	kfree(ioc->config_cmds.reply);  	kfree(ioc->base_cmds.reply);  	kfree(ioc->ctl_cmds.reply); @@ -3646,6 +3687,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	ioc->ctl_cmds.reply = NULL;  	ioc->base_cmds.reply = NULL;  	ioc->tm_cmds.reply = NULL; +	ioc->scsih_cmds.reply = NULL;  	ioc->transport_cmds.reply = NULL;  	ioc->config_cmds.reply = NULL;  	ioc->pfacts = NULL; @@ -3675,6 +3717,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)  	kfree(ioc->base_cmds.reply);  	kfree(ioc->tm_cmds.reply);  	kfree(ioc->transport_cmds.reply); +	kfree(ioc->scsih_cmds.reply);  	kfree(ioc->config_cmds.reply);  } @@ -3811,9 +3854,8 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);  	ioc->shost_recovery = 0; +	complete(&ioc->shost_recovery_done);  	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -	if (!r) -		_base_reset_handler(ioc, MPT2_IOC_RUNNING);  	return r;  } diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index e18b0544c38..b4afe431ac1 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -3,7 +3,7 @@   * for access to MPT (Message Passing Technology) firmware.   *   * This code is based on drivers/scsi/mpt2sas/mpt2_base.h - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -69,11 +69,11 @@  #define MPT2SAS_DRIVER_NAME		"mpt2sas"  #define MPT2SAS_AUTHOR	"LSI Corporation <DL-MPTFusionLinux@lsi.com>"  #define MPT2SAS_DESCRIPTION	"LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION		"04.100.01.00" -#define MPT2SAS_MAJOR_VERSION		04 +#define MPT2SAS_DRIVER_VERSION		"05.100.00.02" +#define MPT2SAS_MAJOR_VERSION		05  #define MPT2SAS_MINOR_VERSION		100 -#define MPT2SAS_BUILD_VERSION		01 -#define MPT2SAS_RELEASE_VERSION		00 +#define MPT2SAS_BUILD_VERSION		00 +#define MPT2SAS_RELEASE_VERSION		02  /*   * Set MPT2SAS_SG_DEPTH value based on user input. @@ -119,7 +119,6 @@  #define MPT2_IOC_PRE_RESET		1 /* prior to host reset */  #define MPT2_IOC_AFTER_RESET		2 /* just after host reset */  #define MPT2_IOC_DONE_RESET		3 /* links re-initialized */ -#define MPT2_IOC_RUNNING		4 /* shost running */  /*   * logging format @@ -260,16 +259,6 @@ struct _internal_cmd {  	u16	smid;  }; -/* - * SAS Topology Structures - */ - -#define MPTSAS_STATE_TR_SEND		0x0001 -#define MPTSAS_STATE_TR_COMPLETE	0x0002 -#define MPTSAS_STATE_CNTRL_SEND		0x0004 -#define MPTSAS_STATE_CNTRL_COMPLETE	0x0008 - -#define MPT2SAS_REQ_SAS_CNTRL		0x0010  /**   * struct _sas_device - attached device information @@ -307,7 +296,6 @@ struct _sas_device {  	u16	slot;  	u8	hidden_raid_component;  	u8	responding; -	u16	state;  };  /** @@ -378,6 +366,7 @@ struct _sas_port {   * @phy_id: unique phy id   * @handle: device handle for this phy   * @attached_handle: device handle for attached device + * @phy_belongs_to_port: port has been created for this phy   */  struct _sas_phy {  	struct list_head port_siblings; @@ -387,6 +376,7 @@ struct _sas_phy {  	u8	phy_id;  	u16	handle;  	u16	attached_handle; +	u8	phy_belongs_to_port;  };  /** @@ -603,7 +593,6 @@ struct MPT2SAS_ADAPTER {  	/* fw event handler */  	char		firmware_event_name[20];  	struct workqueue_struct	*firmware_event_thread; -	u8		fw_events_off;  	spinlock_t	fw_event_lock;  	struct list_head fw_event_list; @@ -611,6 +600,7 @@ struct MPT2SAS_ADAPTER {  	int		aen_event_read_flag;  	u8		broadcast_aen_busy;  	u8		shost_recovery; +	struct completion	shost_recovery_done;  	spinlock_t 	ioc_reset_in_progress_lock;  	u8		ioc_link_reset_in_progress;  	u8		ignore_loginfos; @@ -688,7 +678,8 @@ struct MPT2SAS_ADAPTER {  	dma_addr_t	request_dma;  	u32		request_dma_sz;  	struct request_tracker *scsi_lookup; -	spinlock_t scsi_lookup_lock; +	ulong		scsi_lookup_pages; +	spinlock_t 	scsi_lookup_lock;  	struct list_head free_list;  	int		pending_io_count;  	wait_queue_head_t reset_wq; @@ -700,7 +691,7 @@ struct MPT2SAS_ADAPTER {  	u16		max_sges_in_chain_message;  	u16		chains_needed_per_io;  	u16		chain_offset_value_for_main_message; -	u16		chain_depth; +	u32		chain_depth;  	/* hi-priority queue */  	u16		hi_priority_smid; @@ -814,8 +805,9 @@ void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc);  /* scsih shared API */  u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,      u32 reply); -void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, -    u8 type, u16 smid_task, ulong timeout); +int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, +    uint channel, uint id, uint lun, u8 type, u16 smid_task, +    ulong timeout, struct scsi_cmnd *scmd);  void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);  void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);  struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index cf44b355bc9..e762dd3e2fc 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -2,7 +2,7 @@   * This module provides common API for accessing firmware configuration pages   *   * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -1390,12 +1390,12 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,  	if (ioc_status != MPI2_IOCSTATUS_SUCCESS)  		goto out;  	for (i = 0; i < config_page->NumElements; i++) { -		if ((config_page->ConfigElement[i].ElementFlags & +		if ((le16_to_cpu(config_page->ConfigElement[i].ElementFlags) &  		    MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) !=  		    MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT)  			continue; -		if (config_page->ConfigElement[i].PhysDiskDevHandle == -		    pd_handle) { +		if (le16_to_cpu(config_page->ConfigElement[i]. +		    PhysDiskDevHandle) == pd_handle) {  			*volume_handle = le16_to_cpu(config_page->  			    ConfigElement[i].VolDevHandle);  			r = 0; diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index fa9bf83819d..d88e9756d8f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -3,7 +3,7 @@   * controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -533,7 +533,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,  	if (!found) {  		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  		    "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name, -		    desc, tm_request->DevHandle, lun)); +		    desc, le16_to_cpu(tm_request->DevHandle), lun));  		tm_reply = ioc->ctl_cmds.reply;  		tm_reply->DevHandle = tm_request->DevHandle;  		tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; @@ -551,7 +551,8 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,  	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  	    "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, -	    desc, tm_request->DevHandle, lun, tm_request->TaskMID)); +	    desc, le16_to_cpu(tm_request->DevHandle), lun, +	     le16_to_cpu(tm_request->TaskMID)));  	return 0;  } @@ -647,9 +648,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||  	    mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { -		if (!mpi_request->FunctionDependent1 || -		    mpi_request->FunctionDependent1 > -		    cpu_to_le16(ioc->facts.MaxDevHandle)) { +		if (!le16_to_cpu(mpi_request->FunctionDependent1) || +		    le16_to_cpu(mpi_request->FunctionDependent1) > +		    ioc->facts.MaxDevHandle) {  			ret = -EINVAL;  			mpt2sas_base_free_smid(ioc, smid);  			goto out; @@ -743,8 +744,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		    mpt2sas_base_get_sense_buffer_dma(ioc, smid);  		priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);  		memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE); -		mpt2sas_base_put_smid_scsi_io(ioc, smid, -		    le16_to_cpu(mpi_request->FunctionDependent1)); +		if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) +			mpt2sas_base_put_smid_scsi_io(ioc, smid, +			    le16_to_cpu(mpi_request->FunctionDependent1)); +		else +			mpt2sas_base_put_smid_default(ioc, smid);  		break;  	}  	case MPI2_FUNCTION_SCSI_TASK_MGMT: @@ -752,6 +756,10 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		Mpi2SCSITaskManagementRequest_t *tm_request =  		    (Mpi2SCSITaskManagementRequest_t *)mpi_request; +		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " +		    "handle(0x%04x), task_type(0x%02x)\n", ioc->name, +		    le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); +  		if (tm_request->TaskType ==  		    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||  		    tm_request->TaskType == @@ -762,7 +770,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  			}  		} -		mutex_lock(&ioc->tm_cmds.mutex);  		mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(  		    tm_request->DevHandle));  		mpt2sas_base_put_smid_hi_priority(ioc, smid); @@ -818,7 +825,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {  		Mpi2SCSITaskManagementRequest_t *tm_request =  		    (Mpi2SCSITaskManagementRequest_t *)mpi_request; -		mutex_unlock(&ioc->tm_cmds.mutex);  		mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu(  		    tm_request->DevHandle));  	} else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || @@ -897,14 +903,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {  			printk(MPT2SAS_INFO_FMT "issue target reset: handle "  			    "= (0x%04x)\n", ioc->name, -			    mpi_request->FunctionDependent1); +			    le16_to_cpu(mpi_request->FunctionDependent1));  			mpt2sas_halt_firmware(ioc); -			mutex_lock(&ioc->tm_cmds.mutex);  			mpt2sas_scsih_issue_tm(ioc, -			    mpi_request->FunctionDependent1, 0, -			    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); +			    le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, +			    0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10, +			    NULL);  			ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -			mutex_unlock(&ioc->tm_cmds.mutex);  		} else  			mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,  			    FORCE_BIG_HAMMER); @@ -1373,7 +1378,8 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,  	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "  	    "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, -	    (unsigned long long)request_data_dma, mpi_request->BufferLength)); +	    (unsigned long long)request_data_dma, +	    le32_to_cpu(mpi_request->BufferLength)));  	for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)  		mpi_request->ProductSpecific[i] = @@ -2334,8 +2340,8 @@ _ctl_version_nvdata_persistent_show(struct device *cdev,  	struct Scsi_Host *shost = class_to_shost(cdev);  	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); -	return snprintf(buf, PAGE_SIZE, "%02xh\n", -	    le16_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); +	return snprintf(buf, PAGE_SIZE, "%08xh\n", +	    le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));  }  static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,      _ctl_version_nvdata_persistent_show, NULL); @@ -2354,8 +2360,8 @@ _ctl_version_nvdata_default_show(struct device *cdev,  	struct Scsi_Host *shost = class_to_shost(cdev);  	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); -	return snprintf(buf, PAGE_SIZE, "%02xh\n", -	    le16_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); +	return snprintf(buf, PAGE_SIZE, "%08xh\n", +	    le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));  }  static DEVICE_ATTR(version_nvdata_default, S_IRUGO,      _ctl_version_nvdata_default_show, NULL); diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 8a5eeb1a5c8..69916e46e04 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h @@ -3,7 +3,7 @@   * controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h index 5308a25cb30..3dcddfeb6f4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h @@ -2,7 +2,7 @@   * Logging Support for MPT (Message Passing Technology) based controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index be171ed682e..c5ff26a2a51 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -2,7 +2,7 @@   * Scsi Host Layer for MPT (Message Passing Technology) based controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -52,6 +52,7 @@  #include <linux/delay.h>  #include <linux/pci.h>  #include <linux/interrupt.h> +#include <linux/aer.h>  #include <linux/raid_class.h>  #include <linux/slab.h> @@ -109,14 +110,16 @@ struct sense_info {  }; +#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF) +  /**   * struct fw_event_work - firmware event struct   * @list: link list framework   * @work: work object (ioc->fault_reset_work_q) + * @cancel_pending_work: flag set during reset handling   * @ioc: per adapter object   * @VF_ID: virtual function id   * @VP_ID: virtual port id - * @host_reset_handling: handling events during host reset   * @ignore: flag meaning this event has been marked to ignore   * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h   * @event_data: reply event data payload follows @@ -125,11 +128,11 @@ struct sense_info {   */  struct fw_event_work {  	struct list_head 	list; -	struct work_struct	work; +	u8			cancel_pending_work; +	struct delayed_work	delayed_work;  	struct MPT2SAS_ADAPTER *ioc;  	u8			VF_ID;  	u8			VP_ID; -	u8			host_reset_handling;  	u8			ignore;  	u16			event;  	void			*event_data; @@ -482,27 +485,17 @@ struct _sas_device *  mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,      u64 sas_address)  { -	struct _sas_device *sas_device, *r; +	struct _sas_device *sas_device; -	r = NULL; -	/* check the sas_device_init_list */ -	list_for_each_entry(sas_device, &ioc->sas_device_init_list, -	    list) { -		if (sas_device->sas_address != sas_address) -			continue; -		r = sas_device; -		goto out; -	} +	list_for_each_entry(sas_device, &ioc->sas_device_list, list) +		if (sas_device->sas_address == sas_address) +			return sas_device; -	/* then check the sas_device_list */ -	list_for_each_entry(sas_device, &ioc->sas_device_list, list) { -		if (sas_device->sas_address != sas_address) -			continue; -		r = sas_device; -		goto out; -	} - out: -	return r; +	list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) +		if (sas_device->sas_address == sas_address) +			return sas_device; + +	return NULL;  }  /** @@ -517,28 +510,17 @@ mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,  static struct _sas_device *  _scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)  { -	struct _sas_device *sas_device, *r; +	struct _sas_device *sas_device; -	r = NULL; -	if (ioc->wait_for_port_enable_to_complete) { -		list_for_each_entry(sas_device, &ioc->sas_device_init_list, -		    list) { -			if (sas_device->handle != handle) -				continue; -			r = sas_device; -			goto out; -		} -	} else { -		list_for_each_entry(sas_device, &ioc->sas_device_list, list) { -			if (sas_device->handle != handle) -				continue; -			r = sas_device; -			goto out; -		} -	} +	list_for_each_entry(sas_device, &ioc->sas_device_list, list) +		if (sas_device->handle == handle) +			return sas_device; - out: -	return r; +	list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) +		if (sas_device->handle == handle) +			return sas_device; + +	return NULL;  }  /** @@ -555,10 +537,15 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,  {  	unsigned long flags; +	if (!sas_device) +		return; +  	spin_lock_irqsave(&ioc->sas_device_lock, flags); -	list_del(&sas_device->list); -	memset(sas_device, 0, sizeof(struct _sas_device)); -	kfree(sas_device); +	if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc, +	    sas_device->sas_address)) { +		list_del(&sas_device->list); +		kfree(sas_device); +	}  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  } @@ -988,7 +975,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,  	u32 chain_offset;  	u32 chain_length;  	u32 chain_flags; -	u32 sges_left; +	int sges_left;  	u32 sges_in_segment;  	u32 sgl_flags;  	u32 sgl_flags_last_element; @@ -1009,7 +996,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,  	sg_scmd = scsi_sglist(scmd);  	sges_left = scsi_dma_map(scmd); -	if (!sges_left) { +	if (sges_left < 0) {  		sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"  		" failed: request for %d bytes!\n", scsi_bufflen(scmd));  		return -ENOMEM; @@ -1395,7 +1382,7 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,  	}  	flags = le16_to_cpu(sas_device_pg0.Flags); -	device_info = le16_to_cpu(sas_device_pg0.DeviceInfo); +	device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);  	sdev_printk(KERN_INFO, sdev,  	    "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), " @@ -1963,65 +1950,78 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)  	}  } +  /**   * mpt2sas_scsih_issue_tm - main routine for sending tm requests   * @ioc: per adapter struct   * @device_handle: device handle + * @channel: the channel assigned by the OS + * @id: the id assigned by the OS   * @lun: lun number   * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)   * @smid_task: smid assigned to the task   * @timeout: timeout in seconds - * Context: The calling function needs to acquire the tm_cmds.mutex + * Context: user   *   * A generic API for sending task management requests to firmware.   * - * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling - * this API. - *   * The callback index is set inside `ioc->tm_cb_idx`.   * - * Return nothing. + * Return SUCCESS or FAILED.   */ -void -mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, -    u8 type, u16 smid_task, ulong timeout) +int +mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, +    uint id, uint lun, u8 type, u16 smid_task, ulong timeout, +    struct scsi_cmnd *scmd)  {  	Mpi2SCSITaskManagementRequest_t *mpi_request;  	Mpi2SCSITaskManagementReply_t *mpi_reply;  	u16 smid = 0;  	u32 ioc_state;  	unsigned long timeleft; +	struct scsi_cmnd *scmd_lookup; +	int rc; +	mutex_lock(&ioc->tm_cmds.mutex);  	if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {  		printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",  		    __func__, ioc->name); -		return; +		rc = FAILED; +		goto err_out;  	} -	if (ioc->shost_recovery) { +	if (ioc->shost_recovery || ioc->remove_host) {  		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",  		    __func__, ioc->name); -		return; +		rc = FAILED; +		goto err_out;  	}  	ioc_state = mpt2sas_base_get_iocstate(ioc, 0);  	if (ioc_state & MPI2_DOORBELL_USED) {  		dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "  		    "active!\n", ioc->name)); -		goto issue_host_reset; +		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +		    FORCE_BIG_HAMMER); +		rc = SUCCESS; +		goto err_out;  	}  	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {  		mpt2sas_base_fault_info(ioc, ioc_state &  		    MPI2_DOORBELL_DATA_MASK); -		goto issue_host_reset; +		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +		    FORCE_BIG_HAMMER); +		rc = SUCCESS; +		goto err_out;  	}  	smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);  	if (!smid) {  		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",  		    ioc->name, __func__); -		return; +		rc = FAILED; +		goto err_out;  	}  	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," @@ -2035,21 +2035,24 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,  	mpi_request->DevHandle = cpu_to_le16(handle);  	mpi_request->TaskType = type;  	mpi_request->TaskMID = cpu_to_le16(smid_task); -	mpi_request->VP_ID = 0;  /* TODO */ -	mpi_request->VF_ID = 0;  	int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);  	mpt2sas_scsih_set_tm_flag(ioc, handle);  	init_completion(&ioc->tm_cmds.done);  	mpt2sas_base_put_smid_hi_priority(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); -	mpt2sas_scsih_clear_tm_flag(ioc, handle);  	if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {  		printk(MPT2SAS_ERR_FMT "%s: timeout\n",  		    ioc->name, __func__);  		_debug_dump_mf(mpi_request,  		    sizeof(Mpi2SCSITaskManagementRequest_t)/4); -		if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) -			goto issue_host_reset; +		if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) { +			mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +			    FORCE_BIG_HAMMER); +			rc = SUCCESS; +			ioc->tm_cmds.status = MPT2_CMD_NOT_USED; +			mpt2sas_scsih_clear_tm_flag(ioc, handle); +			goto err_out; +		}  	}  	if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) { @@ -2059,12 +2062,57 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,  		    ioc->name, le16_to_cpu(mpi_reply->IOCStatus),  		    le32_to_cpu(mpi_reply->IOCLogInfo),  		    le32_to_cpu(mpi_reply->TerminationCount))); -		if (ioc->logging_level & MPT_DEBUG_TM) +		if (ioc->logging_level & MPT_DEBUG_TM) {  			_scsih_response_code(ioc, mpi_reply->ResponseCode); +			if (mpi_reply->IOCStatus) +				_debug_dump_mf(mpi_request, +				    sizeof(Mpi2SCSITaskManagementRequest_t)/4); +		}  	} -	return; - issue_host_reset: -	mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); + +	/* sanity check: +	 * Check to see the commands were terminated. +	 * This is only needed for eh callbacks, hence the scmd check. +	 */ +	rc = FAILED; +	if (scmd == NULL) +		goto bypass_sanity_checks; +	switch (type) { +	case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: +		scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task); +		if (scmd_lookup && (scmd_lookup->serial_number == +		    scmd->serial_number)) +			rc = FAILED; +		else +			rc = SUCCESS; +		break; + +	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: +		if (_scsih_scsi_lookup_find_by_target(ioc, id, channel)) +			rc = FAILED; +		else +			rc = SUCCESS; +		break; + +	case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: +		if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) +			rc = FAILED; +		else +			rc = SUCCESS; +		break; +	} + + bypass_sanity_checks: + +	mpt2sas_scsih_clear_tm_flag(ioc, handle); +	ioc->tm_cmds.status = MPT2_CMD_NOT_USED; +	mutex_unlock(&ioc->tm_cmds.mutex); + +	return rc; + + err_out: +	mutex_unlock(&ioc->tm_cmds.mutex); +	return rc;  }  /** @@ -2081,7 +2129,6 @@ _scsih_abort(struct scsi_cmnd *scmd)  	u16 smid;  	u16 handle;  	int r; -	struct scsi_cmnd *scmd_lookup;  	printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",  	    ioc->name, scmd); @@ -2116,19 +2163,10 @@ _scsih_abort(struct scsi_cmnd *scmd)  	mpt2sas_halt_firmware(ioc); -	mutex_lock(&ioc->tm_cmds.mutex);  	handle = sas_device_priv_data->sas_target->handle; -	mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun, -	    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30); - -	/* sanity check - see whether command actually completed */ -	scmd_lookup = _scsih_scsi_lookup_get(ioc, smid); -	if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number)) -		r = FAILED; -	else -		r = SUCCESS; -	ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -	mutex_unlock(&ioc->tm_cmds.mutex); +	r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, +	    scmd->device->id, scmd->device->lun, +	    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd);   out:  	printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n", @@ -2185,22 +2223,9 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)  		goto out;  	} -	mutex_lock(&ioc->tm_cmds.mutex); -	mpt2sas_scsih_issue_tm(ioc, handle, 0, -	    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun, -	    30); - -	/* -	 *  sanity check see whether all commands to this device been -	 *  completed -	 */ -	if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id, -	    scmd->device->lun, scmd->device->channel)) -		r = FAILED; -	else -		r = SUCCESS; -	ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -	mutex_unlock(&ioc->tm_cmds.mutex); +	r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, +	    scmd->device->id, scmd->device->lun, +	    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd);   out:  	printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n", @@ -2257,21 +2282,9 @@ _scsih_target_reset(struct scsi_cmnd *scmd)  		goto out;  	} -	mutex_lock(&ioc->tm_cmds.mutex); -	mpt2sas_scsih_issue_tm(ioc, handle, 0, -	    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30); - -	/* -	 *  sanity check see whether all commands to this target been -	 *  completed -	 */ -	if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id, -	    scmd->device->channel)) -		r = FAILED; -	else -		r = SUCCESS; -	ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -	mutex_unlock(&ioc->tm_cmds.mutex); +	r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, +	    scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, +	    30, scmd);   out:  	printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n", @@ -2325,8 +2338,9 @@ _scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)  	spin_lock_irqsave(&ioc->fw_event_lock, flags);  	list_add_tail(&fw_event->list, &ioc->fw_event_list); -	INIT_WORK(&fw_event->work, _firmware_event_work); -	queue_work(ioc->firmware_event_thread, &fw_event->work); +	INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work); +	queue_delayed_work(ioc->firmware_event_thread, +	    &fw_event->delayed_work, 0);  	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);  } @@ -2353,61 +2367,53 @@ _scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work  	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);  } +  /** - * _scsih_fw_event_add - requeue an event + * _scsih_queue_rescan - queue a topology rescan from user context   * @ioc: per adapter object - * @fw_event: object describing the event - * Context: This function will acquire ioc->fw_event_lock.   *   * Return nothing.   */  static void -_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work -    *fw_event, unsigned long delay) +_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc)  { -	unsigned long flags; -	if (ioc->firmware_event_thread == NULL) -		return; +	struct fw_event_work *fw_event; -	spin_lock_irqsave(&ioc->fw_event_lock, flags); -	queue_work(ioc->firmware_event_thread, &fw_event->work); -	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +	if (ioc->wait_for_port_enable_to_complete) +		return; +	fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); +	if (!fw_event) +		return; +	fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET; +	fw_event->ioc = ioc; +	_scsih_fw_event_add(ioc, fw_event);  }  /** - * _scsih_fw_event_off - turn flag off preventing event handling + * _scsih_fw_event_cleanup_queue - cleanup event queue   * @ioc: per adapter object   * - * Used to prevent handling of firmware events during adapter reset - * driver unload. + * Walk the firmware event queue, either killing timers, or waiting + * for outstanding events to complete   *   * Return nothing.   */  static void -_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc) +_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)  { -	unsigned long flags; +	struct fw_event_work *fw_event, *next; -	spin_lock_irqsave(&ioc->fw_event_lock, flags); -	ioc->fw_events_off = 1; -	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - -} - -/** - * _scsih_fw_event_on - turn flag on allowing firmware event handling - * @ioc: per adapter object - * - * Returns nothing. - */ -static void -_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc) -{ -	unsigned long flags; +	if (list_empty(&ioc->fw_event_list) || +	     !ioc->firmware_event_thread || in_interrupt()) +		return; -	spin_lock_irqsave(&ioc->fw_event_lock, flags); -	ioc->fw_events_off = 0; -	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +	list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { +		if (cancel_delayed_work(&fw_event->delayed_work)) { +			_scsih_fw_event_free(ioc, fw_event); +			continue; +		} +		fw_event->cancel_pending_work = 1; +	}  }  /** @@ -2571,25 +2577,24 @@ static void  _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)  {  	Mpi2SCSITaskManagementRequest_t *mpi_request; -	struct MPT2SAS_TARGET *sas_target_priv_data;  	u16 smid;  	struct _sas_device *sas_device;  	unsigned long flags;  	struct _tr_list *delayed_tr; -	if (ioc->shost_recovery) { -		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", -		    __func__, ioc->name); +	if (ioc->shost_recovery || ioc->remove_host) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " +		   "progress!\n", __func__, ioc->name));  		return;  	}  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); -	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - -	/* skip is hidden raid component */ -	if (sas_device && sas_device->hidden_raid_component) +	if (sas_device && sas_device->hidden_raid_component) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  		return; +	} +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  	smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);  	if (!smid) { @@ -2598,36 +2603,16 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)  			return;  		INIT_LIST_HEAD(&delayed_tr->list);  		delayed_tr->handle = handle; -		delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL; -		list_add_tail(&delayed_tr->list, -		    &ioc->delayed_tr_list); -		if (sas_device && sas_device->starget) { -			dewtprintk(ioc, starget_printk(KERN_INFO, -			    sas_device->starget, "DELAYED:tr:handle(0x%04x), " -			    "(open)\n", handle)); -		} else { -			dewtprintk(ioc, printk(MPT2SAS_INFO_FMT -			    "DELAYED:tr:handle(0x%04x), (open)\n", -			    ioc->name, handle)); -		} -		return; -	} - -	if (sas_device) { -		sas_device->state |= MPTSAS_STATE_TR_SEND; -		sas_device->state |= MPT2SAS_REQ_SAS_CNTRL; -		if (sas_device->starget && sas_device->starget->hostdata) { -			sas_target_priv_data = sas_device->starget->hostdata; -			sas_target_priv_data->tm_busy = 1; -			dewtprintk(ioc, starget_printk(KERN_INFO, -			    sas_device->starget, "tr:handle(0x%04x), (open)\n", -			    handle)); -		} -	} else { +		list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);  		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT -		    "tr:handle(0x%04x), (open)\n", ioc->name, handle)); +		    "DELAYED:tr:handle(0x%04x), (open)\n", +		    ioc->name, handle)); +		return;  	} +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " +	    "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, +	    ioc->tm_tr_cb_idx));  	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);  	memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));  	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; @@ -2657,35 +2642,15 @@ static u8  _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,      u8 msix_index, u32 reply)  { -	unsigned long flags; -	u16 handle; -	struct _sas_device *sas_device;  	Mpi2SasIoUnitControlReply_t *mpi_reply =  	    mpt2sas_base_get_reply_virt_addr(ioc, reply); -	handle = le16_to_cpu(mpi_reply->DevHandle); - -	spin_lock_irqsave(&ioc->sas_device_lock, flags); -	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); -	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - -	if (sas_device) { -		sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE; -		if (sas_device->starget) -			dewtprintk(ioc, starget_printk(KERN_INFO, -			    sas_device->starget, -			    "sc_complete:handle(0x%04x), " -			    "ioc_status(0x%04x), loginfo(0x%08x)\n", -			    handle, le16_to_cpu(mpi_reply->IOCStatus), -			    le32_to_cpu(mpi_reply->IOCLogInfo))); -	} else { -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT -		    "sc_complete:handle(0x%04x), " -		    "ioc_status(0x%04x), loginfo(0x%08x)\n", -		    ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus), -		    le32_to_cpu(mpi_reply->IOCLogInfo))); -	} - +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT +	    "sc_complete:handle(0x%04x), (open) " +	    "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", +	    ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, +	    le16_to_cpu(mpi_reply->IOCStatus), +	    le32_to_cpu(mpi_reply->IOCLogInfo)));  	return 1;  } @@ -2709,87 +2674,63 @@ static u8  _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,      u32 reply)  { -	unsigned long flags;  	u16 handle; -	struct _sas_device *sas_device; +	Mpi2SCSITaskManagementRequest_t *mpi_request_tm;  	Mpi2SCSITaskManagementReply_t *mpi_reply =  	    mpt2sas_base_get_reply_virt_addr(ioc, reply);  	Mpi2SasIoUnitControlRequest_t *mpi_request;  	u16 smid_sas_ctrl; -	struct MPT2SAS_TARGET *sas_target_priv_data;  	struct _tr_list *delayed_tr; -	u8 rc; -	handle = le16_to_cpu(mpi_reply->DevHandle); -	spin_lock_irqsave(&ioc->sas_device_lock, flags); -	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); -	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - -	if (sas_device) { -		sas_device->state |= MPTSAS_STATE_TR_COMPLETE; -		if (sas_device->starget) { -			dewtprintk(ioc, starget_printk(KERN_INFO, -			    sas_device->starget, "tr_complete:handle(0x%04x), " -			    "(%s) ioc_status(0x%04x), loginfo(0x%08x), " -			    "completed(%d)\n", sas_device->handle, -			    (sas_device->state & MPT2SAS_REQ_SAS_CNTRL) ? -			    "open" : "active", -			    le16_to_cpu(mpi_reply->IOCStatus), -			    le32_to_cpu(mpi_reply->IOCLogInfo), -			    le32_to_cpu(mpi_reply->TerminationCount))); -			if (sas_device->starget->hostdata) { -				sas_target_priv_data = -				    sas_device->starget->hostdata; -				sas_target_priv_data->tm_busy = 0; -			} -		} -	} else { -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT -		    "tr_complete:handle(0x%04x), (open) ioc_status(0x%04x), " -		    "loginfo(0x%08x), completed(%d)\n", ioc->name, -		    handle, le16_to_cpu(mpi_reply->IOCStatus), -		    le32_to_cpu(mpi_reply->IOCLogInfo), -		    le32_to_cpu(mpi_reply->TerminationCount))); +	if (ioc->shost_recovery || ioc->remove_host) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " +		   "progress!\n", __func__, ioc->name)); +		return 1;  	} -	if (!list_empty(&ioc->delayed_tr_list)) { -		delayed_tr = list_entry(ioc->delayed_tr_list.next, -		    struct _tr_list, list); -		mpt2sas_base_free_smid(ioc, smid); -		if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL) -			_scsih_tm_tr_send(ioc, delayed_tr->handle); -		list_del(&delayed_tr->list); -		kfree(delayed_tr); -		rc = 0; /* tells base_interrupt not to free mf */ -	} else -		rc = 1; - -	if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL)) -		return rc; - -	if (ioc->shost_recovery) { -		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", -		    __func__, ioc->name); -		return rc; +	mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); +	handle = le16_to_cpu(mpi_request_tm->DevHandle); +	if (handle != le16_to_cpu(mpi_reply->DevHandle)) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: " +		    "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle, +		    le16_to_cpu(mpi_reply->DevHandle), smid)); +		return 0;  	} +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT +	    "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " +	    "loginfo(0x%08x), completed(%d)\n", ioc->name, +	    handle, smid, le16_to_cpu(mpi_reply->IOCStatus), +	    le32_to_cpu(mpi_reply->IOCLogInfo), +	    le32_to_cpu(mpi_reply->TerminationCount))); +  	smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);  	if (!smid_sas_ctrl) {  		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",  		    ioc->name, __func__); -		return rc; +		return 1;  	} -	if (sas_device) -		sas_device->state |= MPTSAS_STATE_CNTRL_SEND; - +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), " +	    "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl, +	    ioc->tm_sas_control_cb_idx));  	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);  	memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));  	mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;  	mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; -	mpi_request->DevHandle = mpi_reply->DevHandle; +	mpi_request->DevHandle = mpi_request_tm->DevHandle;  	mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); -	return rc; + +	if (!list_empty(&ioc->delayed_tr_list)) { +		delayed_tr = list_entry(ioc->delayed_tr_list.next, +		    struct _tr_list, list); +		mpt2sas_base_free_smid(ioc, smid); +		_scsih_tm_tr_send(ioc, delayed_tr->handle); +		list_del(&delayed_tr->list); +		kfree(delayed_tr); +		return 0; /* tells base_interrupt not to free mf */ +	} +	return 1;  }  /** @@ -3021,25 +2962,32 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  	scmd->scsi_done = done;  	sas_device_priv_data = scmd->device->hostdata; -	if (!sas_device_priv_data) { +	if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {  		scmd->result = DID_NO_CONNECT << 16;  		scmd->scsi_done(scmd);  		return 0;  	}  	sas_target_priv_data = sas_device_priv_data->sas_target; -	if (!sas_target_priv_data || sas_target_priv_data->handle == -	    MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) { +	/* invalid device handle */ +	if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {  		scmd->result = DID_NO_CONNECT << 16;  		scmd->scsi_done(scmd);  		return 0;  	} -	/* see if we are busy with task managment stuff */ -	if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) -		return SCSI_MLQUEUE_DEVICE_BUSY; -	else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) +	/* host recovery or link resets sent via IOCTLs */ +	if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)  		return SCSI_MLQUEUE_HOST_BUSY; +	/* device busy with task managment */ +	else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) +		return SCSI_MLQUEUE_DEVICE_BUSY; +	/* device has been deleted */ +	else if (sas_target_priv_data->deleted) { +		scmd->result = DID_NO_CONNECT << 16; +		scmd->scsi_done(scmd); +		return 0; +	}  	if (scmd->sc_data_direction == DMA_FROM_DEVICE)  		mpi_control = MPI2_SCSIIO_CONTROL_READ; @@ -3110,8 +3058,11 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  		}  	} -	mpt2sas_base_put_smid_scsi_io(ioc, smid, -	    sas_device_priv_data->sas_target->handle); +	if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) +		mpt2sas_base_put_smid_scsi_io(ioc, smid, +		    sas_device_priv_data->sas_target->handle); +	else +		mpt2sas_base_put_smid_default(ioc, smid);  	return 0;   out: @@ -3301,8 +3252,8 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,  		struct sense_info data;  		_scsih_normalize_sense(scmd->sense_buffer, &data);  		printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: " -		    "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey, -		    data.asc, data.ascq); +		    "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey, +		    data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));  	}  	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { @@ -3356,7 +3307,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)  		mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;  		mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;  		mpi_request.SlotStatus = -		    MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT; +		    cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);  		mpi_request.DevHandle = cpu_to_le16(handle);  		mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;  		if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, @@ -4008,6 +3959,134 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)  }  /** + * _scsih_check_access_status - check access flags + * @ioc: per adapter object + * @sas_address: sas address + * @handle: sas device handle + * @access_flags: errors returned during discovery of the device + * + * Return 0 for success, else failure + */ +static u8 +_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, +   u16 handle, u8 access_status) +{ +	u8 rc = 1; +	char *desc = NULL; + +	switch (access_status) { +	case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: +	case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: +		rc = 0; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: +		desc = "sata capability failed"; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: +		desc = "sata affiliation conflict"; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: +		desc = "route not addressable"; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: +		desc = "smp error not addressable"; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: +		desc = "device blocked"; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: +		desc = "sata initialization failed"; +		break; +	default: +		desc = "unknown"; +		break; +	} + +	if (!rc) +		return 0; + +	printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), " +	    "handle(0x%04x)\n", ioc->name, desc, +	    (unsigned long long)sas_address, handle); +	return rc; +} + +static void +_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ +	Mpi2ConfigReply_t mpi_reply; +	Mpi2SasDevicePage0_t sas_device_pg0; +	struct _sas_device *sas_device; +	u32 ioc_status; +	unsigned long flags; +	u64 sas_address; +	struct scsi_target *starget; +	struct MPT2SAS_TARGET *sas_target_priv_data; +	u32 device_info; + +	if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, +	    MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) +		return; + +	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; +	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) +		return; + +	/* check if this is end device */ +	device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); +	if (!(_scsih_is_end_device(device_info))) +		return; + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	sas_address = le64_to_cpu(sas_device_pg0.SASAddress); +	sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, +	    sas_address); + +	if (!sas_device) { +		printk(MPT2SAS_ERR_FMT "device is not present " +		    "handle(0x%04x), no sas_device!!!\n", ioc->name, handle); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		return; +	} + +	if (unlikely(sas_device->handle != handle)) { +		starget = sas_device->starget; +		sas_target_priv_data = starget->hostdata; +		starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)" +		   " to (0x%04x)!!!\n", sas_device->handle, handle); +		sas_target_priv_data->handle = handle; +		sas_device->handle = handle; +	} +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + +	/* check if device is present */ +	if (!(le16_to_cpu(sas_device_pg0.Flags) & +	    MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { +		printk(MPT2SAS_ERR_FMT "device is not present " +		    "handle(0x%04x), flags!!!\n", ioc->name, handle); +		return; +	} + +	/* check if there were any issues with discovery */ +	if (_scsih_check_access_status(ioc, sas_address, handle, +	    sas_device_pg0.AccessStatus)) +		return; +	_scsih_ublock_io_device(ioc, handle); + +} + +/**   * _scsih_add_device -  creating sas device object   * @ioc: per adapter object   * @handle: sas device handle @@ -4045,6 +4124,8 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)  		return -1;  	} +	sas_address = le64_to_cpu(sas_device_pg0.SASAddress); +  	/* check if device is present */  	if (!(le16_to_cpu(sas_device_pg0.Flags) &  	    MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { @@ -4055,15 +4136,10 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)  		return -1;  	} -	/* check if there were any issus with discovery */ -	if (sas_device_pg0.AccessStatus == -	    MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) { -		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", -		    ioc->name, __FILE__, __LINE__, __func__); -		printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n", -		    ioc->name, sas_device_pg0.AccessStatus); +	/* check if there were any issues with discovery */ +	if (_scsih_check_access_status(ioc, sas_address, handle, +	    sas_device_pg0.AccessStatus))  		return -1; -	}  	/* check if this is end device */  	device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); @@ -4073,17 +4149,14 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)  		return -1;  	} -	sas_address = le64_to_cpu(sas_device_pg0.SASAddress);  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,  	    sas_address);  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -	if (sas_device) { -		_scsih_ublock_io_device(ioc, handle); +	if (sas_device)  		return 0; -	}  	sas_device = kzalloc(sizeof(struct _sas_device),  	    GFP_KERNEL); @@ -4126,67 +4199,38 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)  }  /** - * _scsih_remove_device -  removing sas device object + * _scsih_remove_pd_device -  removing sas device pd object   * @ioc: per adapter object - * @sas_device: the sas_device object + * @sas_device_delete: the sas_device object   * + * For hidden raid components, we do driver-fw handshake from + * hotplug work threads.   * Return nothing.   */  static void -_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device -    *sas_device) +_scsih_remove_pd_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device +    sas_device)  { -	struct MPT2SAS_TARGET *sas_target_priv_data;  	Mpi2SasIoUnitControlReply_t mpi_reply;  	Mpi2SasIoUnitControlRequest_t mpi_request; -	u16 device_handle, handle; - -	if (!sas_device) -		return; +	u16 vol_handle, handle; -	handle = sas_device->handle; +	handle = sas_device.handle;  	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"  	    " sas_addr(0x%016llx)\n", ioc->name, __func__, handle, -	    (unsigned long long) sas_device->sas_address)); - -	if (sas_device->starget && sas_device->starget->hostdata) { -		sas_target_priv_data = sas_device->starget->hostdata; -		sas_target_priv_data->deleted = 1; -	} - -	if (ioc->remove_host || ioc->shost_recovery || !handle) -		goto out; - -	if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) { -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip " -		   "target_reset handle(0x%04x)\n", ioc->name, -		   handle)); -		goto skip_tr; -	} +	    (unsigned long long) sas_device.sas_address)); -	/* Target Reset to flush out all the outstanding IO */ -	device_handle = (sas_device->hidden_raid_component) ? -	    sas_device->volume_handle : handle; -	if (device_handle) { -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: " -		    "handle(0x%04x)\n", ioc->name, device_handle)); -		mutex_lock(&ioc->tm_cmds.mutex); -		mpt2sas_scsih_issue_tm(ioc, device_handle, 0, -		    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); -		ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -		mutex_unlock(&ioc->tm_cmds.mutex); -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset " -		    "done: handle(0x%04x)\n", ioc->name, device_handle)); -		if (ioc->shost_recovery) -			goto out; -	} - skip_tr: - -	if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) { -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip " -		   "sas_cntrl handle(0x%04x)\n", ioc->name, handle)); -		goto out; -	} +	vol_handle = sas_device.volume_handle; +	if (!vol_handle) +		return; +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: " +	    "handle(0x%04x)\n", ioc->name, vol_handle)); +	mpt2sas_scsih_issue_tm(ioc, vol_handle, 0, 0, 0, +	    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, NULL); +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset " +	    "done: handle(0x%04x)\n", ioc->name, vol_handle)); +	if (ioc->shost_recovery) +		return;  	/* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */  	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle" @@ -4194,34 +4238,68 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device  	memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));  	mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;  	mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE; -	mpi_request.DevHandle = handle; -	mpi_request.VF_ID = 0; /* TODO */ -	mpi_request.VP_ID = 0; +	mpi_request.DevHandle = cpu_to_le16(handle);  	if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, -	    &mpi_request)) != 0) { +	    &mpi_request)) != 0)  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__); -	}  	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"  	    "(0x%04x), loginfo(0x%08x)\n", ioc->name,  	    le16_to_cpu(mpi_reply.IOCStatus),  	    le32_to_cpu(mpi_reply.IOCLogInfo))); - out: +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle(0x%04x)," +	    " sas_addr(0x%016llx)\n", ioc->name, __func__, handle, +	    (unsigned long long) sas_device.sas_address)); +} -	_scsih_ublock_io_device(ioc, handle); +/** + * _scsih_remove_device -  removing sas device object + * @ioc: per adapter object + * @sas_device_delete: the sas_device object + * + * Return nothing. + */ +static void +_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, +    struct _sas_device *sas_device) +{ +	struct _sas_device sas_device_backup; +	struct MPT2SAS_TARGET *sas_target_priv_data; -	mpt2sas_transport_port_remove(ioc, sas_device->sas_address, -	    sas_device->sas_address_parent); +	if (!sas_device) +		return; -	printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" -	    "(0x%016llx)\n", ioc->name, handle, -	    (unsigned long long) sas_device->sas_address); +	memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device));  	_scsih_sas_device_remove(ioc, sas_device); -	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle" -	    "(0x%04x)\n", ioc->name, __func__, handle)); +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: " +	    "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, +	    sas_device_backup.handle, (unsigned long long) +	    sas_device_backup.sas_address)); + +	if (sas_device_backup.starget && sas_device_backup.starget->hostdata) { +		sas_target_priv_data = sas_device_backup.starget->hostdata; +		sas_target_priv_data->deleted = 1; +	} + +	if (sas_device_backup.hidden_raid_component) +		_scsih_remove_pd_device(ioc, sas_device_backup); + +	_scsih_ublock_io_device(ioc, sas_device_backup.handle); + +	mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address, +	    sas_device_backup.sas_address_parent); + +	printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" +	    "(0x%016llx)\n", ioc->name, sas_device_backup.handle, +	    (unsigned long long) sas_device_backup.sas_address); + +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: " +	    "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, +	    sas_device_backup.handle, (unsigned long long) +	    sas_device_backup.sas_address));  }  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -4331,7 +4409,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  		_scsih_sas_topology_change_event_debug(ioc, event_data);  #endif -	if (ioc->shost_recovery) +	if (ioc->shost_recovery || ioc->remove_host)  		return;  	if (!ioc->sas_hba.num_phys) @@ -4370,7 +4448,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  			    "expander event\n", ioc->name));  			return;  		} -		if (ioc->shost_recovery) +		if (ioc->shost_recovery || ioc->remove_host)  			return;  		phy_number = event_data->StartPhyNum + i;  		reason_code = event_data->PHY[i].PhyStatus & @@ -4393,8 +4471,10 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  			mpt2sas_transport_update_links(ioc, sas_address,  			    handle, phy_number, link_rate); -			if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5) -				_scsih_ublock_io_device(ioc, handle); +			if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) +				break; + +			_scsih_check_device(ioc, handle);  			break;  		case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: @@ -4520,10 +4600,10 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,  		     event_data);  #endif -	if (!(event_data->ReasonCode == +	if (event_data->ReasonCode !=  	    MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && -	   event_data->ReasonCode == -	    MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)) +	   event_data->ReasonCode != +	    MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)  		return;  	spin_lock_irqsave(&ioc->sas_device_lock, flags); @@ -4630,7 +4710,6 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,  	dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,  	    __func__)); -	mutex_lock(&ioc->tm_cmds.mutex);  	termination_count = 0;  	query_count = 0;  	mpi_reply = ioc->tm_cmds.reply; @@ -4654,8 +4733,8 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,  		lun = sas_device_priv_data->lun;  		query_count++; -		mpt2sas_scsih_issue_tm(ioc, handle, lun, -		    MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30); +		mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, +		    MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL);  		ioc->tm_cmds.status = MPT2_CMD_NOT_USED;  		ioc_status = le16_to_cpu(mpi_reply->IOCStatus)  		    & MPI2_IOCSTATUS_MASK; @@ -4666,13 +4745,11 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,  		     MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))  			continue; -		mpt2sas_scsih_issue_tm(ioc, handle, lun, -		    MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30); -		ioc->tm_cmds.status = MPT2_CMD_NOT_USED; +		mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, +		    MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30, NULL);  		termination_count += le32_to_cpu(mpi_reply->TerminationCount);  	}  	ioc->broadcast_aen_busy = 0; -	mutex_unlock(&ioc->tm_cmds.mutex);  	dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT  	    "%s - exit, query_count = %d termination_count = %d\n", @@ -5442,6 +5519,26 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work  }  /** + * _scsih_prep_device_scan - initialize parameters prior to device scan + * @ioc: per adapter object + * + * Set the deleted flag prior to device scan.  If the device is found during + * the scan, then we clear the deleted flag. + */ +static void +_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc) +{ +	struct MPT2SAS_DEVICE *sas_device_priv_data; +	struct scsi_device *sdev; + +	shost_for_each_device(sdev, ioc->shost) { +		sas_device_priv_data = sdev->hostdata; +		if (sas_device_priv_data && sas_device_priv_data->sas_target) +			sas_device_priv_data->sas_target->deleted = 1; +	} +} + +/**   * _scsih_mark_responding_sas_device - mark a sas_devices as responding   * @ioc: per adapter object   * @sas_address: sas address @@ -5467,10 +5564,13 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  		if (sas_device->sas_address == sas_address &&  		    sas_device->slot == slot && sas_device->starget) {  			sas_device->responding = 1; -			sas_device->state = 0;  			starget = sas_device->starget; -			sas_target_priv_data = starget->hostdata; -			sas_target_priv_data->tm_busy = 0; +			if (starget && starget->hostdata) { +				sas_target_priv_data = starget->hostdata; +				sas_target_priv_data->tm_busy = 0; +				sas_target_priv_data->deleted = 0; +			} else +				sas_target_priv_data = NULL;  			starget_printk(KERN_INFO, sas_device->starget,  			    "handle(0x%04x), sas_addr(0x%016llx), enclosure "  			    "logical id(0x%016llx), slot(%d)\n", handle, @@ -5483,7 +5583,8 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  			printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",  			    sas_device->handle);  			sas_device->handle = handle; -			sas_target_priv_data->handle = handle; +			if (sas_target_priv_data) +				sas_target_priv_data->handle = handle;  			goto out;  		}  	} @@ -5558,6 +5659,12 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,  	spin_lock_irqsave(&ioc->raid_device_lock, flags);  	list_for_each_entry(raid_device, &ioc->raid_device_list, list) {  		if (raid_device->wwid == wwid && raid_device->starget) { +			starget = raid_device->starget; +			if (starget && starget->hostdata) { +				sas_target_priv_data = starget->hostdata; +				sas_target_priv_data->deleted = 0; +			} else +				sas_target_priv_data = NULL;  			raid_device->responding = 1;  			starget_printk(KERN_INFO, raid_device->starget,  			    "handle(0x%04x), wwid(0x%016llx)\n", handle, @@ -5567,9 +5674,8 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,  			printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",  			    raid_device->handle);  			raid_device->handle = handle; -			starget = raid_device->starget; -			sas_target_priv_data = starget->hostdata; -			sas_target_priv_data->handle = handle; +			if (sas_target_priv_data) +				sas_target_priv_data->handle = handle;  			goto out;  		}  	} @@ -5694,13 +5800,13 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)  }  /** - * _scsih_remove_unresponding_devices - removing unresponding devices + * _scsih_remove_unresponding_sas_devices - removing unresponding devices   * @ioc: per adapter object   *   * Return nothing.   */  static void -_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) +_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)  {  	struct _sas_device *sas_device, *sas_device_next;  	struct _sas_node *sas_expander; @@ -5722,8 +5828,6 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)  			    (unsigned long long)  			    sas_device->enclosure_logical_id,  			    sas_device->slot); -		/* invalidate the device handle */ -		sas_device->handle = 0;  		_scsih_remove_device(ioc, sas_device);  	} @@ -5774,32 +5878,33 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  	case MPT2_IOC_PRE_RESET:  		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  		    "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); -		_scsih_fw_event_off(ioc);  		break;  	case MPT2_IOC_AFTER_RESET:  		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  		    "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); +		if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) { +			ioc->scsih_cmds.status |= MPT2_CMD_RESET; +			mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid); +			complete(&ioc->scsih_cmds.done); +		}  		if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {  			ioc->tm_cmds.status |= MPT2_CMD_RESET;  			mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);  			complete(&ioc->tm_cmds.done);  		} -		_scsih_fw_event_on(ioc); +		_scsih_fw_event_cleanup_queue(ioc);  		_scsih_flush_running_cmds(ioc); +		_scsih_queue_rescan(ioc);  		break;  	case MPT2_IOC_DONE_RESET:  		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  		    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));  		_scsih_sas_host_refresh(ioc); +		_scsih_prep_device_scan(ioc);  		_scsih_search_responding_sas_devices(ioc);  		_scsih_search_responding_raid_devices(ioc);  		_scsih_search_responding_expanders(ioc);  		break; -	case MPT2_IOC_RUNNING: -		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " -		    "MPT2_IOC_RUNNING\n", ioc->name, __func__)); -		_scsih_remove_unresponding_devices(ioc); -		break;  	}  } @@ -5815,21 +5920,28 @@ static void  _firmware_event_work(struct work_struct *work)  {  	struct fw_event_work *fw_event = container_of(work, -	    struct fw_event_work, work); +	    struct fw_event_work, delayed_work.work);  	unsigned long flags;  	struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;  	/* the queue is being flushed so ignore this event */ -	spin_lock_irqsave(&ioc->fw_event_lock, flags); -	if (ioc->fw_events_off || ioc->remove_host) { -		spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +	if (ioc->remove_host || fw_event->cancel_pending_work) {  		_scsih_fw_event_free(ioc, fw_event);  		return;  	} -	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -	if (ioc->shost_recovery) { -		_scsih_fw_event_requeue(ioc, fw_event, 1000); +	if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) { +		_scsih_fw_event_free(ioc, fw_event); +		spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); +		if (ioc->shost_recovery) { +			init_completion(&ioc->shost_recovery_done); +			spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, +			    flags); +			wait_for_completion(&ioc->shost_recovery_done); +		} else +			spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, +			    flags); +		_scsih_remove_unresponding_sas_devices(ioc);  		return;  	} @@ -5891,16 +6003,12 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  {  	struct fw_event_work *fw_event;  	Mpi2EventNotificationReply_t *mpi_reply; -	unsigned long flags;  	u16 event; +	u16 sz;  	/* events turned off due to host reset or driver unloading */ -	spin_lock_irqsave(&ioc->fw_event_lock, flags); -	if (ioc->fw_events_off || ioc->remove_host) { -		spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +	if (ioc->remove_host)  		return 1; -	} -	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);  	event = le16_to_cpu(mpi_reply->Event); @@ -5947,8 +6055,8 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  		    ioc->name, __FILE__, __LINE__, __func__);  		return 1;  	} -	fw_event->event_data = -	    kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC); +	sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; +	fw_event->event_data = kzalloc(sz, GFP_ATOMIC);  	if (!fw_event->event_data) {  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__); @@ -5957,7 +6065,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  	}  	memcpy(fw_event->event_data, mpi_reply->EventData, -	    mpi_reply->EventDataLength*4); +	    sz);  	fw_event->ioc = ioc;  	fw_event->VF_ID = mpi_reply->VF_ID;  	fw_event->VP_ID = mpi_reply->VP_ID; @@ -6158,6 +6266,18 @@ _scsih_shutdown(struct pci_dev *pdev)  {  	struct Scsi_Host *shost = pci_get_drvdata(pdev);  	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); +	struct workqueue_struct	*wq; +	unsigned long flags; + +	ioc->remove_host = 1; +	_scsih_fw_event_cleanup_queue(ioc); + +	spin_lock_irqsave(&ioc->fw_event_lock, flags); +	wq = ioc->firmware_event_thread; +	ioc->firmware_event_thread = NULL; +	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +	if (wq) +		destroy_workqueue(wq);  	_scsih_ir_shutdown(ioc);  	mpt2sas_base_detach(ioc); @@ -6184,7 +6304,7 @@ _scsih_remove(struct pci_dev *pdev)  	unsigned long flags;  	ioc->remove_host = 1; -	_scsih_fw_event_off(ioc); +	_scsih_fw_event_cleanup_queue(ioc);  	spin_lock_irqsave(&ioc->fw_event_lock, flags);  	wq = ioc->firmware_event_thread; @@ -6557,6 +6677,122 @@ _scsih_resume(struct pci_dev *pdev)  }  #endif /* CONFIG_PM */ +/** + * _scsih_pci_error_detected - Called when a PCI error is detected. + * @pdev: PCI device struct + * @state: PCI channel state + * + * Description: Called when a PCI error is detected. + * + * Return value: + *      PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT + */ +static pci_ers_result_t +_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ +	struct Scsi_Host *shost = pci_get_drvdata(pdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + +	printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n", +	    ioc->name, state); + +	switch (state) { +	case pci_channel_io_normal: +		return PCI_ERS_RESULT_CAN_RECOVER; +	case pci_channel_io_frozen: +		scsi_block_requests(ioc->shost); +		mpt2sas_base_stop_watchdog(ioc); +		mpt2sas_base_free_resources(ioc); +		return PCI_ERS_RESULT_NEED_RESET; +	case pci_channel_io_perm_failure: +		_scsih_remove(pdev); +		return PCI_ERS_RESULT_DISCONNECT; +	} +	return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * _scsih_pci_slot_reset - Called when PCI slot has been reset. + * @pdev: PCI device struct + * + * Description: This routine is called by the pci error recovery + * code after the PCI slot has been reset, just before we + * should resume normal operations. + */ +static pci_ers_result_t +_scsih_pci_slot_reset(struct pci_dev *pdev) +{ +	struct Scsi_Host *shost = pci_get_drvdata(pdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); +	int rc; + +	printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n", +		ioc->name); + +	ioc->pdev = pdev; +	rc = mpt2sas_base_map_resources(ioc); +	if (rc) +		return PCI_ERS_RESULT_DISCONNECT; + + +	rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +	    FORCE_BIG_HAMMER); + +	printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name, +	    (rc == 0) ? "success" : "failed"); + +	if (!rc) +		return PCI_ERS_RESULT_RECOVERED; +	else +		return PCI_ERS_RESULT_DISCONNECT; +} + +/** + * _scsih_pci_resume() - resume normal ops after PCI reset + * @pdev: pointer to PCI device + * + * Called when the error recovery driver tells us that its + * OK to resume normal operation. Use completion to allow + * halted scsi ops to resume. + */ +static void +_scsih_pci_resume(struct pci_dev *pdev) +{ +	struct Scsi_Host *shost = pci_get_drvdata(pdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + +	printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name); + +	pci_cleanup_aer_uncorrect_error_status(pdev); +	mpt2sas_base_start_watchdog(ioc); +	scsi_unblock_requests(ioc->shost); +} + +/** + * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers + * @pdev: pointer to PCI device + */ +static pci_ers_result_t +_scsih_pci_mmio_enabled(struct pci_dev *pdev) +{ +	struct Scsi_Host *shost = pci_get_drvdata(pdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + +	printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n", +	    ioc->name); + +	/* TODO - dump whatever for debugging purposes */ + +	/* Request a slot reset. */ +	return PCI_ERS_RESULT_NEED_RESET; +} + +static struct pci_error_handlers _scsih_err_handler = { +	.error_detected = _scsih_pci_error_detected, +	.mmio_enabled = _scsih_pci_mmio_enabled, +	.slot_reset =	_scsih_pci_slot_reset, +	.resume =	_scsih_pci_resume, +};  static struct pci_driver scsih_driver = {  	.name		= MPT2SAS_DRIVER_NAME, @@ -6564,6 +6800,7 @@ static struct pci_driver scsih_driver = {  	.probe		= _scsih_probe,  	.remove		= __devexit_p(_scsih_remove),  	.shutdown	= _scsih_shutdown, +	.err_handler	= &_scsih_err_handler,  #ifdef CONFIG_PM  	.suspend	= _scsih_suspend,  	.resume		= _scsih_resume, diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index bd7ca2b49f8..2727c3b6510 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -2,7 +2,7 @@   * SAS Transport Layer for MPT (Message Passing Technology) based controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -465,6 +465,85 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,  	return rc;  } + +/** + * _transport_delete_duplicate_port - (see below description) + * @ioc: per adapter object + * @sas_node: sas node object (either expander or sas host) + * @sas_address: sas address of device being added + * @phy_num: phy number + * + * This function is called when attempting to add a new port that is claiming + * the same phy resources already in use by another port.  If we don't release + * the claimed phy resources, the sas transport layer will hang from the BUG + * in sas_port_add_phy. + * + * The reason we would hit this issue is becuase someone is changing the + * sas address of a device on the fly, meanwhile controller firmware sends + * EVENTs out of order when removing the previous instance of the device. + */ +static void +_transport_delete_duplicate_port(struct MPT2SAS_ADAPTER *ioc, +    struct _sas_node *sas_node, u64 sas_address, int phy_num) +{ +	struct _sas_port *mpt2sas_port, *mpt2sas_port_duplicate; +	struct _sas_phy *mpt2sas_phy; + +	printk(MPT2SAS_ERR_FMT "new device located at sas_addr(0x%016llx), " +	    "phy_id(%d)\n", ioc->name, (unsigned long long)sas_address, +	    phy_num); + +	mpt2sas_port_duplicate = NULL; +	list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, port_list) { +		dev_printk(KERN_ERR, &mpt2sas_port->port->dev, +		    "existing device at sas_addr(0x%016llx), num_phys(%d)\n", +		    (unsigned long long) +		    mpt2sas_port->remote_identify.sas_address, +		    mpt2sas_port->num_phys); +		list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, +		    port_siblings) { +			dev_printk(KERN_ERR, &mpt2sas_phy->phy->dev, +			    "phy_number(%d)\n", mpt2sas_phy->phy_id); +			if (mpt2sas_phy->phy_id == phy_num) +				mpt2sas_port_duplicate = mpt2sas_port; +		} +	} + +	if (!mpt2sas_port_duplicate) +		return; + +	dev_printk(KERN_ERR, &mpt2sas_port_duplicate->port->dev, +	    "deleting duplicate device at sas_addr(0x%016llx), phy(%d)!!!!\n", +	    (unsigned long long) +	    mpt2sas_port_duplicate->remote_identify.sas_address, phy_num); +	ioc->logging_level |= MPT_DEBUG_TRANSPORT; +	mpt2sas_transport_port_remove(ioc, +	    mpt2sas_port_duplicate->remote_identify.sas_address, +	    sas_node->sas_address); +	ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; +} + +/** + * _transport_sanity_check - sanity check when adding a new port + * @ioc: per adapter object + * @sas_node: sas node object (either expander or sas host) + * @sas_address: sas address of device being added + * + * See the explanation above from _transport_delete_duplicate_port + */ +static void +_transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node, +     u64 sas_address) +{ +	int i; + +	for (i = 0; i < sas_node->num_phys; i++) +		if (sas_node->phy[i].remote_identify.sas_address == sas_address) +			if (sas_node->phy[i].phy_belongs_to_port) +				_transport_delete_duplicate_port(ioc, sas_node, +					sas_address, i); +} +  /**   * mpt2sas_transport_port_add - insert port to the list   * @ioc: per adapter object @@ -522,6 +601,9 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,  		goto out_fail;  	} +	_transport_sanity_check(ioc, sas_node, +	    mpt2sas_port->remote_identify.sas_address); +  	for (i = 0; i < sas_node->num_phys; i++) {  		if (sas_node->phy[i].remote_identify.sas_address !=  		    mpt2sas_port->remote_identify.sas_address) @@ -553,6 +635,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,  			    mpt2sas_port->remote_identify.sas_address,  			    mpt2sas_phy->phy_id);  		sas_port_add_phy(port, mpt2sas_phy->phy); +		mpt2sas_phy->phy_belongs_to_port = 1;  	}  	mpt2sas_port->port = port; @@ -651,6 +734,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  			    (unsigned long long)  			    mpt2sas_port->remote_identify.sas_address,  			    mpt2sas_phy->phy_id); +		mpt2sas_phy->phy_belongs_to_port = 0;  		sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);  		list_del(&mpt2sas_phy->port_siblings);  	} @@ -1341,7 +1425,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  		memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));  		req->sense_len = sizeof(*mpi_reply);  		req->resid_len = 0; -		rsp->resid_len -= mpi_reply->ResponseDataLength; +		rsp->resid_len -= +		    le16_to_cpu(mpi_reply->ResponseDataLength);  	} else {  		dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT  		    "%s - no reply\n", ioc->name, __func__)); diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c index d722235111a..716d1785cda 100644 --- a/drivers/scsi/mvme147.c +++ b/drivers/scsi/mvme147.c @@ -13,112 +13,116 @@  #include "wd33c93.h"  #include "mvme147.h" -#include<linux/stat.h> +#include <linux/stat.h> -#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))  static struct Scsi_Host *mvme147_host = NULL; -static irqreturn_t mvme147_intr (int irq, void *dummy) +static irqreturn_t mvme147_intr(int irq, void *dummy)  { -    if (irq == MVME147_IRQ_SCSI_PORT) -	wd33c93_intr (mvme147_host); -    else -	m147_pcc->dma_intr = 0x89;	/* Ack and enable ints */ -    return IRQ_HANDLED; +	if (irq == MVME147_IRQ_SCSI_PORT) +		wd33c93_intr(mvme147_host); +	else +		m147_pcc->dma_intr = 0x89;	/* Ack and enable ints */ +	return IRQ_HANDLED;  }  static int dma_setup(struct scsi_cmnd *cmd, int dir_in)  { -    unsigned char flags = 0x01; -    unsigned long addr = virt_to_bus(cmd->SCp.ptr); +	struct WD33C93_hostdata *hdata = shost_priv(mvme147_host); +	unsigned char flags = 0x01; +	unsigned long addr = virt_to_bus(cmd->SCp.ptr); -    /* setup dma direction */ -    if (!dir_in) -	flags |= 0x04; +	/* setup dma direction */ +	if (!dir_in) +		flags |= 0x04; -    /* remember direction */ -    HDATA(mvme147_host)->dma_dir = dir_in; +	/* remember direction */ +	hdata->dma_dir = dir_in; -    if (dir_in) -  	/* invalidate any cache */ -	cache_clear (addr, cmd->SCp.this_residual); -    else -	/* push any dirty cache */ -	cache_push (addr, cmd->SCp.this_residual); +	if (dir_in) { +		/* invalidate any cache */ +		cache_clear(addr, cmd->SCp.this_residual); +	} else { +		/* push any dirty cache */ +		cache_push(addr, cmd->SCp.this_residual); +	} -    /* start DMA */ -    m147_pcc->dma_bcr   = cmd->SCp.this_residual | (1<<24); -    m147_pcc->dma_dadr  = addr; -    m147_pcc->dma_cntrl = flags; +	/* start DMA */ +	m147_pcc->dma_bcr = cmd->SCp.this_residual | (1 << 24); +	m147_pcc->dma_dadr = addr; +	m147_pcc->dma_cntrl = flags; -    /* return success */ -    return 0; +	/* return success */ +	return 0;  }  static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, -		      int status) +		     int status)  { -    m147_pcc->dma_cntrl = 0; +	m147_pcc->dma_cntrl = 0;  }  int mvme147_detect(struct scsi_host_template *tpnt)  { -    static unsigned char called = 0; -    wd33c93_regs regs; +	static unsigned char called = 0; +	wd33c93_regs regs; +	struct WD33C93_hostdata *hdata; -    if (!MACH_IS_MVME147 || called) -	return 0; -    called++; +	if (!MACH_IS_MVME147 || called) +		return 0; +	called++; -    tpnt->proc_name = "MVME147"; -    tpnt->proc_info = &wd33c93_proc_info; +	tpnt->proc_name = "MVME147"; +	tpnt->proc_info = &wd33c93_proc_info; -    mvme147_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata)); -    if (!mvme147_host) -	    goto err_out; +	mvme147_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata)); +	if (!mvme147_host) +		goto err_out; -    mvme147_host->base = 0xfffe4000; -    mvme147_host->irq = MVME147_IRQ_SCSI_PORT; -    regs.SASR = (volatile unsigned char *)0xfffe4000; -    regs.SCMD = (volatile unsigned char *)0xfffe4001; -    HDATA(mvme147_host)->no_sync = 0xff; -    HDATA(mvme147_host)->fast = 0; -    HDATA(mvme147_host)->dma_mode = CTRL_DMA; -    wd33c93_init(mvme147_host, regs, dma_setup, dma_stop, WD33C93_FS_8_10); +	mvme147_host->base = 0xfffe4000; +	mvme147_host->irq = MVME147_IRQ_SCSI_PORT; +	regs.SASR = (volatile unsigned char *)0xfffe4000; +	regs.SCMD = (volatile unsigned char *)0xfffe4001; +	hdata = shost_priv(mvme147_host); +	hdata->no_sync = 0xff; +	hdata->fast = 0; +	hdata->dma_mode = CTRL_DMA; +	wd33c93_init(mvme147_host, regs, dma_setup, dma_stop, WD33C93_FS_8_10); -    if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, "MVME147 SCSI PORT", mvme147_intr)) -	    goto err_unregister; -    if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0, "MVME147 SCSI DMA", mvme147_intr)) -	    goto err_free_irq; +	if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, +			"MVME147 SCSI PORT", mvme147_intr)) +		goto err_unregister; +	if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0, +			"MVME147 SCSI DMA", mvme147_intr)) +		goto err_free_irq;  #if 0	/* Disabled; causes problems booting */ -    m147_pcc->scsi_interrupt = 0x10;	/* Assert SCSI bus reset */ -    udelay(100); -    m147_pcc->scsi_interrupt = 0x00;	/* Negate SCSI bus reset */ -    udelay(2000); -    m147_pcc->scsi_interrupt = 0x40;	/* Clear bus reset interrupt */ +	m147_pcc->scsi_interrupt = 0x10;	/* Assert SCSI bus reset */ +	udelay(100); +	m147_pcc->scsi_interrupt = 0x00;	/* Negate SCSI bus reset */ +	udelay(2000); +	m147_pcc->scsi_interrupt = 0x40;	/* Clear bus reset interrupt */  #endif -    m147_pcc->scsi_interrupt = 0x09;	/* Enable interrupt */ +	m147_pcc->scsi_interrupt = 0x09;	/* Enable interrupt */ -    m147_pcc->dma_cntrl = 0x00;		/* ensure DMA is stopped */ -    m147_pcc->dma_intr = 0x89;		/* Ack and enable ints */ +	m147_pcc->dma_cntrl = 0x00;	/* ensure DMA is stopped */ +	m147_pcc->dma_intr = 0x89;	/* Ack and enable ints */ -    return 1; +	return 1; - err_free_irq: -    free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr); - err_unregister: -    wd33c93_release(); -    scsi_unregister(mvme147_host); - err_out: -    return 0; +err_free_irq: +	free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr); +err_unregister: +	scsi_unregister(mvme147_host); +err_out: +	return 0;  }  static int mvme147_bus_reset(struct scsi_cmnd *cmd)  {  	/* FIXME perform bus-specific reset */ -	/* FIXME 2: kill this function, and let midlayer fallback to  +	/* FIXME 2: kill this function, and let midlayer fallback to  	   the same result, calling wd33c93_host_reset() */  	spin_lock_irq(cmd->device->host->host_lock); @@ -154,10 +158,9 @@ static struct scsi_host_template driver_template = {  int mvme147_release(struct Scsi_Host *instance)  {  #ifdef MODULE -    /* XXX Make sure DMA is stopped! */ -    wd33c93_release(); -    free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr); -    free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr); +	/* XXX Make sure DMA is stopped! */ +	free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr); +	free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr);  #endif -    return 1; +	return 1;  } diff --git a/drivers/scsi/mvme147.h b/drivers/scsi/mvme147.h index 32aee85434d..bfd4566ef05 100644 --- a/drivers/scsi/mvme147.h +++ b/drivers/scsi/mvme147.h @@ -14,11 +14,11 @@ int mvme147_detect(struct scsi_host_template *);  int mvme147_release(struct Scsi_Host *);  #ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 +#define CMD_PER_LUN		2  #endif  #ifndef CAN_QUEUE -#define CAN_QUEUE 16 +#define CAN_QUEUE		16  #endif  #endif /* MVME147_H */ diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c index 10a5077b6ae..afc7f6f3a13 100644 --- a/drivers/scsi/mvsas/mv_64xx.c +++ b/drivers/scsi/mvsas/mv_64xx.c @@ -132,9 +132,9 @@ static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)  	tmp &= ~PHYEV_RDY_CH;  	mvs_write_port_irq_stat(mvi, phy_id, tmp);  	tmp = mvs_read_phy_ctl(mvi, phy_id); -	if (hard) +	if (hard == 1)  		tmp |= PHY_RST_HARD; -	else +	else if (hard == 0)  		tmp |= PHY_RST;  	mvs_write_phy_ctl(mvi, phy_id, tmp);  	if (hard) { @@ -144,6 +144,26 @@ static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)  	}  } +void mvs_64xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all) +{ +	void __iomem *regs = mvi->regs; +	u32 tmp; +	if (clear_all) { +		tmp = mr32(MVS_INT_STAT_SRS_0); +		if (tmp) { +			printk(KERN_DEBUG "check SRS 0 %08X.\n", tmp); +			mw32(MVS_INT_STAT_SRS_0, tmp); +		} +	} else { +		tmp = mr32(MVS_INT_STAT_SRS_0); +		if (tmp &  (1 << (reg_set % 32))) { +			printk(KERN_DEBUG "register set 0x%x was stopped.\n", +			       reg_set); +			mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32)); +		} +	} +} +  static int __devinit mvs_64xx_chip_reset(struct mvs_info *mvi)  {  	void __iomem *regs = mvi->regs; @@ -761,6 +781,7 @@ const struct mvs_dispatch mvs_64xx_dispatch = {  	mvs_write_port_irq_mask,  	mvs_get_sas_addr,  	mvs_64xx_command_active, +	mvs_64xx_clear_srs_irq,  	mvs_64xx_issue_stop,  	mvs_start_delivery,  	mvs_rx_update, diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c index 0940fae19d2..eed4c5c7201 100644 --- a/drivers/scsi/mvsas/mv_94xx.c +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -616,6 +616,15 @@ void mvs_94xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)  }  #endif +/* + * FIXME JEJB: temporary nop clear_srs_irq to make 94xx still work + * with 64xx fixes + */ +static void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, +				   u8 clear_all) +{ +} +  const struct mvs_dispatch mvs_94xx_dispatch = {  	"mv94xx",  	mvs_94xx_init, @@ -640,6 +649,7 @@ const struct mvs_dispatch mvs_94xx_dispatch = {  	mvs_write_port_irq_mask,  	mvs_get_sas_addr,  	mvs_94xx_command_active, +	mvs_94xx_clear_srs_irq,  	mvs_94xx_issue_stop,  	mvs_start_delivery,  	mvs_rx_update, diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index cae6b2cf492..19ad34f381a 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -37,6 +37,7 @@ static const struct mvs_chip_info mvs_chips[] = {  };  #define SOC_SAS_NUM 2 +#define SG_MX 64  static struct scsi_host_template mvs_sht = {  	.module			= THIS_MODULE, @@ -53,10 +54,10 @@ static struct scsi_host_template mvs_sht = {  	.can_queue		= 1,  	.cmd_per_lun		= 1,  	.this_id		= -1, -	.sg_tablesize		= SG_ALL, +	.sg_tablesize		= SG_MX,  	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,  	.use_clustering		= ENABLE_CLUSTERING, -	.eh_device_reset_handler	= sas_eh_device_reset_handler, +	.eh_device_reset_handler = sas_eh_device_reset_handler,  	.eh_bus_reset_handler	= sas_eh_bus_reset_handler,  	.slave_alloc		= mvs_slave_alloc,  	.target_destroy		= sas_target_destroy, @@ -65,19 +66,17 @@ static struct scsi_host_template mvs_sht = {  static struct sas_domain_function_template mvs_transport_ops = {  	.lldd_dev_found 	= mvs_dev_found, -	.lldd_dev_gone	= mvs_dev_gone, - +	.lldd_dev_gone		= mvs_dev_gone,  	.lldd_execute_task	= mvs_queue_command,  	.lldd_control_phy	= mvs_phy_control,  	.lldd_abort_task	= mvs_abort_task,  	.lldd_abort_task_set    = mvs_abort_task_set,  	.lldd_clear_aca         = mvs_clear_aca, -       .lldd_clear_task_set    = mvs_clear_task_set, +	.lldd_clear_task_set    = mvs_clear_task_set,  	.lldd_I_T_nexus_reset	= mvs_I_T_nexus_reset,  	.lldd_lu_reset 		= mvs_lu_reset,  	.lldd_query_task	= mvs_query_task, -  	.lldd_port_formed	= mvs_port_formed,  	.lldd_port_deformed     = mvs_port_deformed, @@ -213,7 +212,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)  static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)  { -	int i, slot_nr; +	int i = 0, slot_nr;  	if (mvi->flags & MVF_FLAG_SOC)  		slot_nr = MVS_SOC_SLOTS; @@ -232,6 +231,7 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)  		mvi->devices[i].dev_type = NO_DEVICE;  		mvi->devices[i].device_id = i;  		mvi->devices[i].dev_status = MVS_DEV_NORMAL; +		init_timer(&mvi->devices[i].timer);  	}  	/* @@ -437,6 +437,7 @@ static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost,  	sha->sas_phy = arr_phy;  	sha->sas_port = arr_port; +	sha->core.shost = shost;  	sha->lldd_ha = kzalloc(sizeof(struct mvs_prv_info), GFP_KERNEL);  	if (!sha->lldd_ha) @@ -574,6 +575,10 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,  		}  		nhost++;  	} while (nhost < chip->n_host); +#ifdef MVS_USE_TASKLET +	tasklet_init(&mv_tasklet, mvs_tasklet, +		     (unsigned long)SHOST_TO_SAS_HA(shost)); +#endif  	mvs_post_sas_ha_init(shost, chip); diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 0d213864121..f5e32179190 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -259,8 +259,6 @@ static inline void mvs_free_reg_set(struct mvs_info *mvi,  		mv_printk("device has been free.\n");  		return;  	} -	if (dev->runing_req != 0) -		return;  	if (dev->taskfileset == MVS_ID_NOT_MAPPED)  		return;  	MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset); @@ -762,8 +760,6 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,  	}  	if (is_tmf)  		flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT); -	else -		flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT);  	hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));  	hdr->tags = cpu_to_le32(tag);  	hdr->data_len = cpu_to_le32(task->total_xfer_len); @@ -878,14 +874,15 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,  	struct mvs_slot_info *slot;  	u32 tag = 0xdeadbeef, rc, n_elem = 0;  	u32 n = num, pass = 0; -	unsigned long flags = 0; +	unsigned long flags = 0,  flags_libsas = 0;  	if (!dev->port) {  		struct task_status_struct *tsm = &t->task_status;  		tsm->resp = SAS_TASK_UNDELIVERED;  		tsm->stat = SAS_PHY_DOWN; -		t->task_done(t); +		if (dev->dev_type != SATA_DEV) +			t->task_done(t);  		return 0;  	} @@ -910,12 +907,25 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,  		else  			tei.port = &mvi->port[dev->port->id]; -		if (!tei.port->port_attached) { +		if (tei.port && !tei.port->port_attached) {  			if (sas_protocol_ata(t->task_proto)) { +				struct task_status_struct *ts = &t->task_status; +  				mv_dprintk("port %d does not"  					"attached device.\n", dev->port->id); -				rc = SAS_PHY_DOWN; -				goto out_done; +				ts->stat = SAS_PROTO_RESPONSE; +				ts->stat = SAS_PHY_DOWN; +				spin_unlock_irqrestore(dev->sata_dev.ap->lock, +						       flags_libsas); +				spin_unlock_irqrestore(&mvi->lock, flags); +				t->task_done(t); +				spin_lock_irqsave(&mvi->lock, flags); +				spin_lock_irqsave(dev->sata_dev.ap->lock, +						  flags_libsas); +				if (n > 1) +					t = list_entry(t->list.next, +						       struct sas_task, list); +				continue;  			} else {  				struct task_status_struct *ts = &t->task_status;  				ts->resp = SAS_TASK_UNDELIVERED; @@ -973,8 +983,8 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,  			break;  		default:  			dev_printk(KERN_ERR, mvi->dev, -				"unknown sas_task proto: 0x%x\n", -				t->task_proto); +				   "unknown sas_task proto: 0x%x\n", +				   t->task_proto);  			rc = -EINVAL;  			break;  		} @@ -993,11 +1003,15 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,  		spin_unlock(&t->task_state_lock);  		mvs_hba_memory_dump(mvi, tag, t->task_proto); -		mvi_dev->runing_req++; +		mvi_dev->running_req++;  		++pass;  		mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);  		if (n > 1)  			t = list_entry(t->list.next, struct sas_task, list); +		if (likely(pass)) +			MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) & +						      (MVS_CHIP_SLOT_SZ - 1)); +  	} while (--n);  	rc = 0;  	goto out_done; @@ -1012,10 +1026,6 @@ err_out:  			dma_unmap_sg(mvi->dev, t->scatter, n_elem,  				     t->data_dir);  out_done: -	if (likely(pass)) { -		MVS_CHIP_DISP->start_delivery(mvi, -			(mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); -	}  	spin_unlock_irqrestore(&mvi->lock, flags);  	return rc;  } @@ -1187,7 +1197,7 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)  				MVS_CHIP_DISP->phy_reset(mvi, i, 0);  				goto out_done;  			} -		}		else if (phy->phy_type & PORT_TYPE_SAS +		}	else if (phy->phy_type & PORT_TYPE_SAS  			|| phy->att_dev_info & PORT_SSP_INIT_MASK) {  			phy->phy_attached = 1;  			phy->identify.device_type = @@ -1256,7 +1266,20 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)  static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)  { -	/*Nothing*/ +	struct domain_device *dev; +	struct mvs_phy *phy = sas_phy->lldd_phy; +	struct mvs_info *mvi = phy->mvi; +	struct asd_sas_port *port = sas_phy->port; +	int phy_no = 0; + +	while (phy != &mvi->phy[phy_no]) { +		phy_no++; +		if (phy_no >= MVS_MAX_PHYS) +			return; +	} +	list_for_each_entry(dev, &port->dev_list, dev_list_node) +		mvs_do_release_task(phy->mvi, phy_no, NULL); +  } @@ -1316,6 +1339,7 @@ int mvs_dev_found_notify(struct domain_device *dev, int lock)  		goto found_out;  	}  	dev->lldd_dev = mvi_device; +	mvi_device->dev_status = MVS_DEV_NORMAL;  	mvi_device->dev_type = dev->dev_type;  	mvi_device->mvi_info = mvi;  	if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { @@ -1351,18 +1375,18 @@ int mvs_dev_found(struct domain_device *dev)  	return mvs_dev_found_notify(dev, 1);  } -void mvs_dev_gone_notify(struct domain_device *dev, int lock) +void mvs_dev_gone_notify(struct domain_device *dev)  {  	unsigned long flags = 0;  	struct mvs_device *mvi_dev = dev->lldd_dev;  	struct mvs_info *mvi = mvi_dev->mvi_info; -	if (lock) -		spin_lock_irqsave(&mvi->lock, flags); +	spin_lock_irqsave(&mvi->lock, flags);  	if (mvi_dev) {  		mv_dprintk("found dev[%d:%x] is gone.\n",  			mvi_dev->device_id, mvi_dev->dev_type); +		mvs_release_task(mvi, dev);  		mvs_free_reg_set(mvi, mvi_dev);  		mvs_free_dev(mvi_dev);  	} else { @@ -1370,14 +1394,13 @@ void mvs_dev_gone_notify(struct domain_device *dev, int lock)  	}  	dev->lldd_dev = NULL; -	if (lock) -		spin_unlock_irqrestore(&mvi->lock, flags); +	spin_unlock_irqrestore(&mvi->lock, flags);  }  void mvs_dev_gone(struct domain_device *dev)  { -	mvs_dev_gone_notify(dev, 1); +	mvs_dev_gone_notify(dev);  }  static  struct sas_task *mvs_alloc_task(void) @@ -1540,7 +1563,7 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun)  		num = mvs_find_dev_phyno(dev, phyno);  		spin_lock_irqsave(&mvi->lock, flags);  		for (i = 0; i < num; i++) -			mvs_release_task(mvi, phyno[i], dev); +			mvs_release_task(mvi, dev);  		spin_unlock_irqrestore(&mvi->lock, flags);  	}  	/* If failed, fall-through I_T_Nexus reset */ @@ -1552,8 +1575,8 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun)  int mvs_I_T_nexus_reset(struct domain_device *dev)  {  	unsigned long flags; -	int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED; -	struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev; +	int rc = TMF_RESP_FUNC_FAILED; +    struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev;  	struct mvs_info *mvi = mvi_dev->mvi_info;  	if (mvi_dev->dev_status != MVS_DEV_EH) @@ -1563,10 +1586,8 @@ int mvs_I_T_nexus_reset(struct domain_device *dev)  		__func__, mvi_dev->device_id, rc);  	/* housekeeper */ -	num = mvs_find_dev_phyno(dev, phyno);  	spin_lock_irqsave(&mvi->lock, flags); -	for (i = 0; i < num; i++) -		mvs_release_task(mvi, phyno[i], dev); +	mvs_release_task(mvi, dev);  	spin_unlock_irqrestore(&mvi->lock, flags);  	return rc; @@ -1603,6 +1624,9 @@ int mvs_query_task(struct sas_task *task)  		case TMF_RESP_FUNC_FAILED:  		case TMF_RESP_FUNC_COMPLETE:  			break; +		default: +			rc = TMF_RESP_FUNC_COMPLETE; +			break;  		}  	}  	mv_printk("%s:rc= %d\n", __func__, rc); @@ -1621,8 +1645,11 @@ int mvs_abort_task(struct sas_task *task)  	unsigned long flags;  	u32 tag; -	if (mvi->exp_req) -		mvi->exp_req--; +	if (!mvi_dev) { +		mv_printk("%s:%d TMF_RESP_FUNC_FAILED\n", __func__, __LINE__); +		rc = TMF_RESP_FUNC_FAILED; +	} +  	spin_lock_irqsave(&task->task_state_lock, flags);  	if (task->task_state_flags & SAS_TASK_STATE_DONE) {  		spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -1630,6 +1657,7 @@ int mvs_abort_task(struct sas_task *task)  		goto out;  	}  	spin_unlock_irqrestore(&task->task_state_lock, flags); +	mvi_dev->dev_status = MVS_DEV_EH;  	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {  		struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task; @@ -1654,12 +1682,31 @@ int mvs_abort_task(struct sas_task *task)  			if (task->lldd_task) {  				slot = task->lldd_task;  				slot_no = (u32) (slot - mvi->slot_info); +				spin_lock_irqsave(&mvi->lock, flags);  				mvs_slot_complete(mvi, slot_no, 1); +				spin_unlock_irqrestore(&mvi->lock, flags);  			}  		} +  	} else if (task->task_proto & SAS_PROTOCOL_SATA ||  		task->task_proto & SAS_PROTOCOL_STP) {  		/* to do free register_set */ +		if (SATA_DEV == dev->dev_type) { +			struct mvs_slot_info *slot = task->lldd_task; +			struct task_status_struct *tstat; +			u32 slot_idx = (u32)(slot - mvi->slot_info); +			tstat = &task->task_status; +			mv_dprintk(KERN_DEBUG "mv_abort_task() mvi=%p task=%p " +				   "slot=%p slot_idx=x%x\n", +				   mvi, task, slot, slot_idx); +			tstat->stat = SAS_ABORTED_TASK; +			if (mvi_dev && mvi_dev->running_req) +				mvi_dev->running_req--; +			if (sas_protocol_ata(task->task_proto)) +				mvs_free_reg_set(mvi, mvi_dev); +			mvs_slot_task_free(mvi, task, slot, slot_idx); +			return -1; +		}  	} else {  		/* SMP */ @@ -1717,8 +1764,13 @@ static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,  	       SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset),  	       sizeof(struct dev_to_host_fis));  	tstat->buf_valid_size = sizeof(*resp); -	if (unlikely(err)) -		stat = SAS_PROTO_RESPONSE; +	if (unlikely(err)) { +		if (unlikely(err & CMD_ISS_STPD)) +			stat = SAS_OPEN_REJECT; +		else +			stat = SAS_PROTO_RESPONSE; +       } +  	return stat;  } @@ -1753,9 +1805,7 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,  			mv_printk("find reserved error, why?\n");  		task->ata_task.use_ncq = 0; -		stat = SAS_PROTO_RESPONSE; -		mvs_sata_done(mvi, task, slot_idx, 1); - +		mvs_sata_done(mvi, task, slot_idx, err_dw0);  	}  		break;  	default: @@ -1772,18 +1822,20 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)  	struct sas_task *task = slot->task;  	struct mvs_device *mvi_dev = NULL;  	struct task_status_struct *tstat; +	struct domain_device *dev; +	u32 aborted; -	bool aborted;  	void *to;  	enum exec_status sts;  	if (mvi->exp_req)  		mvi->exp_req--; -	if (unlikely(!task || !task->lldd_task)) +	if (unlikely(!task || !task->lldd_task || !task->dev))  		return -1;  	tstat = &task->task_status; -	mvi_dev = task->dev->lldd_dev; +	dev = task->dev; +	mvi_dev = dev->lldd_dev;  	mvs_hba_cq_dump(mvi); @@ -1800,8 +1852,8 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)  	if (unlikely(aborted)) {  		tstat->stat = SAS_ABORTED_TASK; -		if (mvi_dev) -			mvi_dev->runing_req--; +		if (mvi_dev && mvi_dev->running_req) +			mvi_dev->running_req--;  		if (sas_protocol_ata(task->task_proto))  			mvs_free_reg_set(mvi, mvi_dev); @@ -1809,24 +1861,17 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)  		return -1;  	} -	if (unlikely(!mvi_dev || !slot->port->port_attached || flags)) { -		mv_dprintk("port has not device.\n"); +	if (unlikely(!mvi_dev || flags)) { +		if (!mvi_dev) +			mv_dprintk("port has not device.\n");  		tstat->stat = SAS_PHY_DOWN;  		goto out;  	} -	/* -	if (unlikely((rx_desc & RXQ_ERR) || (*(u64 *) slot->response))) { -		 mv_dprintk("Find device[%016llx] RXQ_ERR %X, -		 err info:%016llx\n", -		 SAS_ADDR(task->dev->sas_addr), -		 rx_desc, (u64)(*(u64 *) slot->response)); -	} -	*/ -  	/* error info record present */  	if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {  		tstat->stat = mvs_slot_err(mvi, task, slot_idx); +		tstat->resp = SAS_TASK_COMPLETE;  		goto out;  	} @@ -1868,11 +1913,16 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)  		tstat->stat = SAM_CHECK_COND;  		break;  	} +	if (!slot->port->port_attached) { +		mv_dprintk("port %d has removed.\n", slot->port->sas_port.id); +		tstat->stat = SAS_PHY_DOWN; +	} +  out: -	if (mvi_dev) { -		mvi_dev->runing_req--; -		if (sas_protocol_ata(task->task_proto)) +	if (mvi_dev && mvi_dev->running_req) { +		mvi_dev->running_req--; +		if (sas_protocol_ata(task->task_proto) && !mvi_dev->running_req)  			mvs_free_reg_set(mvi, mvi_dev);  	}  	mvs_slot_task_free(mvi, task, slot, slot_idx); @@ -1888,10 +1938,10 @@ out:  	return sts;  } -void mvs_release_task(struct mvs_info *mvi, +void mvs_do_release_task(struct mvs_info *mvi,  		int phy_no, struct domain_device *dev)  { -	int i = 0; u32 slot_idx; +	u32 slot_idx;  	struct mvs_phy *phy;  	struct mvs_port *port;  	struct mvs_slot_info *slot, *slot2; @@ -1900,6 +1950,10 @@ void mvs_release_task(struct mvs_info *mvi,  	port = phy->port;  	if (!port)  		return; +	/* clean cmpl queue in case request is already finished */ +	mvs_int_rx(mvi, false); + +  	list_for_each_entry_safe(slot, slot2, &port->list, entry) {  		struct sas_task *task; @@ -1911,18 +1965,22 @@ void mvs_release_task(struct mvs_info *mvi,  		mv_printk("Release slot [%x] tag[%x], task [%p]:\n",  			slot_idx, slot->slot_tag, task); - -		if (task->task_proto & SAS_PROTOCOL_SSP) { -			mv_printk("attached with SSP task CDB["); -			for (i = 0; i < 16; i++) -				mv_printk(" %02x", task->ssp_task.cdb[i]); -			mv_printk(" ]\n"); -		} +		MVS_CHIP_DISP->command_active(mvi, slot_idx);  		mvs_slot_complete(mvi, slot_idx, 1);  	}  } +void mvs_release_task(struct mvs_info *mvi, +		      struct domain_device *dev) +{ +	int i, phyno[WIDE_PORT_MAX_PHY], num; +	/* housekeeper */ +	num = mvs_find_dev_phyno(dev, phyno); +	for (i = 0; i < num; i++) +		mvs_do_release_task(mvi, phyno[i], dev); +} +  static void mvs_phy_disconnected(struct mvs_phy *phy)  {  	phy->phy_attached = 0; @@ -2029,16 +2087,18 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)  	* we need check the interrupt status which belongs to per port.  	*/ -	if (phy->irq_status & PHYEV_DCDR_ERR) +	if (phy->irq_status & PHYEV_DCDR_ERR) {  		mv_dprintk("port %d STP decoding error.\n", -		phy_no+mvi->id*mvi->chip->n_phy); +		phy_no + mvi->id*mvi->chip->n_phy); +	}  	if (phy->irq_status & PHYEV_POOF) {  		if (!(phy->phy_event & PHY_PLUG_OUT)) {  			int dev_sata = phy->phy_type & PORT_TYPE_SATA;  			int ready; -			mvs_release_task(mvi, phy_no, NULL); +			mvs_do_release_task(mvi, phy_no, NULL);  			phy->phy_event |= PHY_PLUG_OUT; +			MVS_CHIP_DISP->clear_srs_irq(mvi, 0, 1);  			mvs_handle_event(mvi,  				(void *)(unsigned long)phy_no,  				PHY_PLUG_EVENT); @@ -2085,6 +2145,11 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)  							phy_no, tmp);  			}  			mvs_update_phyinfo(mvi, phy_no, 0); +			if (phy->phy_type & PORT_TYPE_SAS) { +				MVS_CHIP_DISP->phy_reset(mvi, phy_no, 2); +				mdelay(10); +			} +  			mvs_bytes_dmaed(mvi, phy_no);  			/* whether driver is going to handle hot plug */  			if (phy->phy_event & PHY_PLUG_OUT) { diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index 885858bcc40..77ddc7c1e5f 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -39,6 +39,7 @@  #include <linux/slab.h>  #include <linux/vmalloc.h>  #include <scsi/libsas.h> +#include <scsi/scsi.h>  #include <scsi/scsi_tcq.h>  #include <scsi/sas_ata.h>  #include <linux/version.h> @@ -49,7 +50,7 @@  #define _MV_DUMP		0  #define MVS_ID_NOT_MAPPED	0x7f  /* #define DISABLE_HOTPLUG_DMA_FIX */ -#define MAX_EXP_RUNNING_REQ	2 +// #define MAX_EXP_RUNNING_REQ	2  #define WIDE_PORT_MAX_PHY		4  #define	MV_DISABLE_NCQ	0  #define mv_printk(fmt, arg ...)	\ @@ -129,6 +130,7 @@ struct mvs_dispatch {  	void (*get_sas_addr)(void *buf, u32 buflen);  	void (*command_active)(struct mvs_info *mvi, u32 slot_idx); +	void (*clear_srs_irq)(struct mvs_info *mvi, u8 reg_set, u8 clear_all);  	void (*issue_stop)(struct mvs_info *mvi, enum mvs_port_type type,  				u32 tfs);  	void (*start_delivery)(struct mvs_info *mvi, u32 tx); @@ -236,9 +238,10 @@ struct mvs_device {  	enum sas_dev_type dev_type;  	struct mvs_info *mvi_info;  	struct domain_device *sas_device; +	struct timer_list timer;  	u32 attached_phy;  	u32 device_id; -	u32 runing_req; +	u32 running_req;  	u8 taskfileset;  	u8 dev_status;  	u16 reserved; @@ -397,7 +400,9 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun);  int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags);  int mvs_I_T_nexus_reset(struct domain_device *dev);  int mvs_query_task(struct sas_task *task); -void mvs_release_task(struct mvs_info *mvi, int phy_no, +void mvs_release_task(struct mvs_info *mvi, +			struct domain_device *dev); +void mvs_do_release_task(struct mvs_info *mvi, int phy_no,  			struct domain_device *dev);  void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);  void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st); diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 909c00ec044..5ff8261c5d6 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -4390,7 +4390,6 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,  				return -ENOMEM;  		}  	} -	memset(buffer, 0, fw_control->len);  	memcpy(buffer, fw_control->buffer, fw_control->len);  	flash_update_info.sgl.addr = cpu_to_le64(phys_addr);  	flash_update_info.sgl.im_len.len = cpu_to_le32(fw_control->len); diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index bff4f5139b9..cd02ceaf67f 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -885,11 +885,13 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)  	u32 tag;  	struct pm8001_hba_info *pm8001_ha;  	struct pm8001_device *pm8001_dev = dev->lldd_dev; -	u32 device_id = pm8001_dev->device_id; +  	pm8001_ha = pm8001_find_ha_by_dev(dev);  	spin_lock_irqsave(&pm8001_ha->lock, flags);  	pm8001_tag_alloc(pm8001_ha, &tag);  	if (pm8001_dev) { +		u32 device_id = pm8001_dev->device_id; +  		PM8001_DISC_DBG(pm8001_ha,  			pm8001_printk("found dev[%d:%x] is gone.\n",  			pm8001_dev->device_id, pm8001_dev->dev_type)); diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 53aefffbaea..c44e4ab4e93 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3751,12 +3751,6 @@ static int pmcraid_check_ioctl_buffer(  		return -EINVAL;  	} -	/* buffer length can't be negetive */ -	if (hdr->buffer_length < 0) { -		pmcraid_err("ioctl: invalid buffer length specified\n"); -		return -EINVAL; -	} -  	/* check for appropriate buffer access */  	if ((_IOC_DIR(cmd) & _IOC_READ) == _IOC_READ)  		access = VERIFY_WRITE; diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile index c51fd1f8663..5df782f4a09 100644 --- a/drivers/scsi/qla2xxx/Makefile +++ b/drivers/scsi/qla2xxx/Makefile @@ -1,4 +1,5 @@  qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ -		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o +		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \ +        qla_nx.o  obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 1c7ef55966f..3b708606b93 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -12,9 +12,7 @@  #include <linux/delay.h>  static int qla24xx_vport_disable(struct fc_vport *, bool); -static int qla84xx_reset(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *); -int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t, uint16_t *); -static int qla84xx_mgmt_cmd(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *); +  /* SYSFS attributes --------------------------------------------------------- */  static ssize_t @@ -43,6 +41,12 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj,  	struct qla_hw_data *ha = vha->hw;  	int reading; +	if (IS_QLA82XX(ha)) { +		DEBUG2(qla_printk(KERN_INFO, ha, +			"Firmware dump not supported for ISP82xx\n")); +		return count; +	} +  	if (off != 0)  		return (0); @@ -277,6 +281,12 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,  			return count;  		} +		if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { +			qla_printk(KERN_WARNING, ha, +				"HBA not online, failing NVRAM update.\n"); +			return -EAGAIN; +		} +  		DEBUG2(qla_printk(KERN_INFO, ha,  		    "Reading flash region -- 0x%x/0x%x.\n",  		    ha->optrom_region_start, ha->optrom_region_size)); @@ -315,8 +325,8 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,  		else if (start == (ha->flt_region_boot * 4) ||  		    start == (ha->flt_region_fw * 4))  			valid = 1; -		else if (IS_QLA25XX(ha) || IS_QLA81XX(ha)) -		    valid = 1; +		else if (IS_QLA25XX(ha) || IS_QLA8XXX_TYPE(ha)) +			valid = 1;  		if (!valid) {  			qla_printk(KERN_WARNING, ha,  			    "Invalid start region 0x%x/0x%x.\n", start, size); @@ -519,6 +529,7 @@ qla2x00_sysfs_write_reset(struct kobject *kobj,  	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,  	    struct device, kobj)));  	struct qla_hw_data *ha = vha->hw; +	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);  	int type;  	if (off != 0) @@ -553,6 +564,20 @@ qla2x00_sysfs_write_reset(struct kobject *kobj,  			    "MPI reset failed on (%ld).\n", vha->host_no);  		scsi_unblock_requests(vha->host);  		break; +	case 0x2025e: +		if (!IS_QLA82XX(ha) || vha != base_vha) { +			qla_printk(KERN_INFO, ha, +			    "FCoE ctx reset not supported for host%ld.\n", +			    vha->host_no); +			return count; +		} + +		qla_printk(KERN_INFO, ha, +		    "Issuing FCoE CTX reset on host%ld.\n", vha->host_no); +		set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); +		qla2xxx_wake_dpc(vha); +		qla2x00_wait_for_fcoe_ctx_reset(vha); +		break;  	}  	return count;  } @@ -838,7 +863,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)  			continue;  		if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw))  			continue; -		if (iter->is4GBp_only == 3 && !IS_QLA81XX(vha->hw)) +		if (iter->is4GBp_only == 3 && !(IS_QLA8XXX_TYPE(vha->hw)))  			continue;  		ret = sysfs_create_bin_file(&host->shost_gendev.kobj, @@ -862,7 +887,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha)  			continue;  		if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))  			continue; -		if (iter->is4GBp_only == 3 && !IS_QLA81XX(ha)) +		if (iter->is4GBp_only == 3 && !!(IS_QLA8XXX_TYPE(vha->hw)))  			continue;  		sysfs_remove_bin_file(&host->shost_gendev.kobj, @@ -968,7 +993,8 @@ qla2x00_link_state_show(struct device *dev, struct device_attribute *attr,  	int len = 0;  	if (atomic_read(&vha->loop_state) == LOOP_DOWN || -	    atomic_read(&vha->loop_state) == LOOP_DEAD) +	    atomic_read(&vha->loop_state) == LOOP_DEAD || +	    vha->device_flags & DFLG_NO_CABLE)  		len = snprintf(buf, PAGE_SIZE, "Link Down\n");  	else if (atomic_read(&vha->loop_state) != LOOP_READY ||  	    test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || @@ -1179,15 +1205,15 @@ qla24xx_84xx_fw_version_show(struct device *dev,  	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));  	struct qla_hw_data *ha = vha->hw; -	if (IS_QLA84XX(ha) && ha->cs84xx) { -		if (ha->cs84xx->op_fw_version == 0) { -			rval = qla84xx_verify_chip(vha, status); -	} +	if (!IS_QLA84XX(ha)) +		return snprintf(buf, PAGE_SIZE, "\n"); + +	if (ha->cs84xx && ha->cs84xx->op_fw_version == 0) +		rval = qla84xx_verify_chip(vha, status);  	if ((rval == QLA_SUCCESS) && (status[0] == 0))  		return snprintf(buf, PAGE_SIZE, "%u\n",  			(uint32_t)ha->cs84xx->op_fw_version); -	}  	return snprintf(buf, PAGE_SIZE, "\n");  } @@ -1237,7 +1263,7 @@ qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr,  {  	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); -	if (!IS_QLA81XX(vha->hw)) +	if (!IS_QLA8XXX_TYPE(vha->hw))  		return snprintf(buf, PAGE_SIZE, "\n");  	return snprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id); @@ -1249,7 +1275,7 @@ qla2x00_vn_port_mac_address_show(struct device *dev,  {  	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); -	if (!IS_QLA81XX(vha->hw)) +	if (!IS_QLA8XXX_TYPE(vha->hw))  		return snprintf(buf, PAGE_SIZE, "\n");  	return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", @@ -1706,6 +1732,22 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)  			fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);  	} +	if (IS_QLA25XX(ha) && ql2xenabledif) { +		if (ha->fw_attributes & BIT_4) { +			vha->flags.difdix_supported = 1; +			DEBUG18(qla_printk(KERN_INFO, ha, +			    "Registering for DIF/DIX type 1 and 3" +			    " protection.\n")); +			scsi_host_set_prot(vha->host, +			    SHOST_DIF_TYPE1_PROTECTION +			    | SHOST_DIF_TYPE3_PROTECTION +			    | SHOST_DIX_TYPE1_PROTECTION +			    | SHOST_DIX_TYPE3_PROTECTION); +			scsi_host_set_guard(vha->host, SHOST_DIX_GUARD_CRC); +		} else +			vha->flags.difdix_supported = 0; +	} +  	if (scsi_add_host_with_dma(vha->host, &fc_vport->dev,  				   &ha->pdev->dev)) {  		DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n", @@ -1825,582 +1867,6 @@ qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)  	return 0;  } -/* BSG support for ELS/CT pass through */ -inline srb_t * -qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size) -{ -	srb_t *sp; -	struct qla_hw_data *ha = vha->hw; -	struct srb_bsg_ctx *ctx; - -	sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); -	if (!sp) -		goto done; -	ctx = kzalloc(size, GFP_KERNEL); -	if (!ctx) { -		mempool_free(sp, ha->srb_mempool); -		goto done; -	} - -	memset(sp, 0, sizeof(*sp)); -	sp->fcport = fcport; -	sp->ctx = ctx; -done: -	return sp; -} - -static int -qla2x00_process_els(struct fc_bsg_job *bsg_job) -{ -	struct fc_rport *rport; -	fc_port_t *fcport; -	struct Scsi_Host *host; -	scsi_qla_host_t *vha; -	struct qla_hw_data *ha; -	srb_t *sp; -	const char *type; -	int req_sg_cnt, rsp_sg_cnt; -	int rval =  (DRIVER_ERROR << 16); -	uint16_t nextlid = 0; -	struct srb_bsg *els; - -	/*  Multiple SG's are not supported for ELS requests */ -        if (bsg_job->request_payload.sg_cnt > 1 || -		bsg_job->reply_payload.sg_cnt > 1) { -		DEBUG2(printk(KERN_INFO -		    "multiple SG's are not supported for ELS requests" -		    " [request_sg_cnt: %x reply_sg_cnt: %x]\n", -		    bsg_job->request_payload.sg_cnt, -		    bsg_job->reply_payload.sg_cnt)); -		rval = -EPERM; -		goto done; -        } - -	/* ELS request for rport */ -	if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { -		rport = bsg_job->rport; -		fcport = *(fc_port_t **) rport->dd_data; -		host = rport_to_shost(rport); -		vha = shost_priv(host); -		ha = vha->hw; -		type = "FC_BSG_RPT_ELS"; - -		/* make sure the rport is logged in, -		 * if not perform fabric login -		 */ -		if (qla2x00_fabric_login(vha, fcport, &nextlid)) { -			DEBUG2(qla_printk(KERN_WARNING, ha, -			    "failed to login port %06X for ELS passthru\n", -			    fcport->d_id.b24)); -			rval = -EIO; -			goto done; -		} -	} else { -		host = bsg_job->shost; -		vha = shost_priv(host); -		ha = vha->hw; -		type = "FC_BSG_HST_ELS_NOLOGIN"; - -		/* Allocate a dummy fcport structure, since functions -		 * preparing the IOCB and mailbox command retrieves port -		 * specific information from fcport structure. For Host based -		 * ELS commands there will be no fcport structure allocated -		 */ -		fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); -		if (!fcport) { -			rval = -ENOMEM; -			goto done; -		} - -		/* Initialize all required  fields of fcport */ -		fcport->vha = vha; -		fcport->vp_idx = vha->vp_idx; -		fcport->d_id.b.al_pa = -		    bsg_job->request->rqst_data.h_els.port_id[0]; -		fcport->d_id.b.area = -		    bsg_job->request->rqst_data.h_els.port_id[1]; -		fcport->d_id.b.domain = -		    bsg_job->request->rqst_data.h_els.port_id[2]; -		fcport->loop_id = -		    (fcport->d_id.b.al_pa == 0xFD) ? -		    NPH_FABRIC_CONTROLLER : NPH_F_PORT; -	} - -	if (!vha->flags.online) { -		DEBUG2(qla_printk(KERN_WARNING, ha, -		    "host not online\n")); -		rval = -EIO; -		goto done; -	} - -        req_sg_cnt = -	    dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, -	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); -        if (!req_sg_cnt) { -		rval = -ENOMEM; -		goto done_free_fcport; -	} -        rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, -	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); -        if (!rsp_sg_cnt) { -		rval = -ENOMEM; -                goto done_free_fcport; -	} - -	if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) || -	    (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) -	{ -		DEBUG2(printk(KERN_INFO -		    "dma mapping resulted in different sg counts \ -		    [request_sg_cnt: %x dma_request_sg_cnt: %x\ -		    reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", -		    bsg_job->request_payload.sg_cnt, req_sg_cnt, -		    bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); -		rval = -EAGAIN; -                goto done_unmap_sg; -	} - -	/* Alloc SRB structure */ -	sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); -	if (!sp) { -		rval = -ENOMEM; -                goto done_unmap_sg; -	} - -	els = sp->ctx; -	els->ctx.type = -	    (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? -	    SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); -	els->bsg_job = bsg_job; - -	DEBUG2(qla_printk(KERN_INFO, ha, -	    "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " -	    "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, -	    bsg_job->request->rqst_data.h_els.command_code, -	    fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, -	    fcport->d_id.b.al_pa)); - -	rval = qla2x00_start_sp(sp); -	if (rval != QLA_SUCCESS) { -		kfree(sp->ctx); -		mempool_free(sp, ha->srb_mempool); -		rval = -EIO; -		goto done_unmap_sg; -	} -	return rval; - -done_unmap_sg: -	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, -		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); -	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, -		bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); -	goto done_free_fcport; - -done_free_fcport: -	if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN) -		kfree(fcport); -done: -	return rval; -} - -static int -qla2x00_process_ct(struct fc_bsg_job *bsg_job) -{ -	srb_t *sp; -	struct Scsi_Host *host = bsg_job->shost; -	scsi_qla_host_t *vha = shost_priv(host); -	struct qla_hw_data *ha = vha->hw; -	int rval = (DRIVER_ERROR << 16); -	int req_sg_cnt, rsp_sg_cnt; -	uint16_t loop_id; -	struct fc_port *fcport; -	char  *type = "FC_BSG_HST_CT"; -	struct srb_bsg *ct; - -	/* pass through is supported only for ISP 4Gb or higher */ -        if (!IS_FWI2_CAPABLE(ha)) { -		DEBUG2(qla_printk(KERN_INFO, ha, -		    "scsi(%ld):Firmware is not capable to support FC " -		    "CT pass thru\n", vha->host_no)); -		rval = -EPERM; -                goto done; -	} - -        req_sg_cnt = -	    dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, -	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); -        if (!req_sg_cnt) { -		rval = -ENOMEM; -		goto done; -	} - -        rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, -            bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); -        if (!rsp_sg_cnt) { -		rval = -ENOMEM; -                goto done; -	} - -	if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) || -		(rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) -	{ -		DEBUG2(qla_printk(KERN_WARNING, ha, -		    "dma mapping resulted in different sg counts \ -		    [request_sg_cnt: %x dma_request_sg_cnt: %x\ -		    reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", -		    bsg_job->request_payload.sg_cnt, req_sg_cnt, -		    bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); -		rval = -EAGAIN; -                goto done_unmap_sg; -	} - -	if (!vha->flags.online) { -		DEBUG2(qla_printk(KERN_WARNING, ha, -		    "host not online\n")); -		rval = -EIO; -                goto done_unmap_sg; -	} - -	loop_id = -	    (bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000) -	    >> 24; -	switch (loop_id) { -		case 0xFC: -			loop_id = cpu_to_le16(NPH_SNS); -			break; -		case 0xFA: -			loop_id = vha->mgmt_svr_loop_id; -			break; -		default: -			DEBUG2(qla_printk(KERN_INFO, ha, -			    "Unknown loop id: %x\n", loop_id)); -			rval = -EINVAL; -			goto done_unmap_sg; -	} - -	/* Allocate a dummy fcport structure, since functions preparing the -	 * IOCB and mailbox command retrieves port specific information -	 * from fcport structure. For Host based ELS commands there will be -	 * no fcport structure allocated -	 */ -	fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); -	if (!fcport) -	{ -		rval = -ENOMEM; -		goto  done_unmap_sg; -	} - -	/* Initialize all required  fields of fcport */ -	fcport->vha = vha; -	fcport->vp_idx = vha->vp_idx; -	fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0]; -	fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1]; -	fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2]; -	fcport->loop_id = loop_id; - -	/* Alloc SRB structure */ -	sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); -	if (!sp) { -		rval = -ENOMEM; -		goto done_free_fcport; -	} - -	ct = sp->ctx; -	ct->ctx.type = SRB_CT_CMD; -	ct->bsg_job = bsg_job; - -	DEBUG2(qla_printk(KERN_INFO, ha, -	    "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " -	    "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, -	    (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16), -	    fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, -	    fcport->d_id.b.al_pa)); - -	rval = qla2x00_start_sp(sp); -	if (rval != QLA_SUCCESS) { -		kfree(sp->ctx); -		mempool_free(sp, ha->srb_mempool); -		rval = -EIO; -		goto done_free_fcport; -	} -	return rval; - -done_free_fcport: -	kfree(fcport); -done_unmap_sg: -	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, -	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); -	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, -	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); -done: -	return rval; -} - -static int -qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) -{ -	struct Scsi_Host *host = bsg_job->shost; -	scsi_qla_host_t *vha = shost_priv(host); -	struct qla_hw_data *ha = vha->hw; -	int rval; -	uint8_t command_sent; -	uint32_t vendor_cmd; -	char *type; -	struct msg_echo_lb elreq; -	uint16_t response[MAILBOX_REGISTER_COUNT]; -	uint8_t* fw_sts_ptr; -	uint8_t *req_data; -	dma_addr_t req_data_dma; -	uint32_t req_data_len; -	uint8_t *rsp_data; -	dma_addr_t rsp_data_dma; -	uint32_t rsp_data_len; - -	if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || -	    test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || -	    test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { -		rval = -EBUSY; -		goto done; -	} - -	if (!vha->flags.online) { -		DEBUG2(qla_printk(KERN_WARNING, ha, -		    "host not online\n")); -		rval = -EIO; -                goto done; -	} - -        elreq.req_sg_cnt = -	    dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, -	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); -        if (!elreq.req_sg_cnt) { -		rval = -ENOMEM; -		goto done; -	} -        elreq.rsp_sg_cnt = -	    dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, -	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); -        if (!elreq.rsp_sg_cnt) { -		rval = -ENOMEM; -                goto done; -	} - -	if ((elreq.req_sg_cnt !=  bsg_job->request_payload.sg_cnt) || -	    (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) -	{ -		DEBUG2(printk(KERN_INFO -		    "dma mapping resulted in different sg counts \ -		    [request_sg_cnt: %x dma_request_sg_cnt: %x\ -		    reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", -		    bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt, -		    bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt)); -		rval = -EAGAIN; -                goto done_unmap_sg; -	} -	req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; -	req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len, -	    &req_data_dma, GFP_KERNEL); - -	rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len, -	    &rsp_data_dma, GFP_KERNEL); - -	/* Copy the request buffer in req_data now */ -	sg_copy_to_buffer(bsg_job->request_payload.sg_list, -	    bsg_job->request_payload.sg_cnt, req_data, -	    req_data_len); - -	elreq.send_dma = req_data_dma; -	elreq.rcv_dma = rsp_data_dma; -	elreq.transfer_size = req_data_len; - -	/* Vendor cmd : loopback or ECHO diagnostic -	 * Options: -	 * 	Loopback : Either internal or external loopback -	 * 	ECHO: ECHO ELS or Vendor specific FC4  link data -	 */ -	vendor_cmd = bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]; -	elreq.options = -	    *(((uint32_t *)bsg_job->request->rqst_data.h_vendor.vendor_cmd) -	    + 1); - -	switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { -	case QL_VND_LOOPBACK: -		if (ha->current_topology != ISP_CFG_F) { -			type = "FC_BSG_HST_VENDOR_LOOPBACK"; - -			DEBUG2(qla_printk(KERN_INFO, ha, -				"scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n", -				vha->host_no, type, vendor_cmd, elreq.options)); - -			command_sent = INT_DEF_LB_LOOPBACK_CMD; -			rval = qla2x00_loopback_test(vha, &elreq, response); -			if (IS_QLA81XX(ha)) { -				if (response[0] == MBS_COMMAND_ERROR && response[1] == MBS_LB_RESET) { -					DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing " -						"ISP\n", __func__, vha->host_no)); -					set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); -					qla2xxx_wake_dpc(vha); -				 } -			} -		} else { -			type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; -			DEBUG2(qla_printk(KERN_INFO, ha, -				"scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n", -				vha->host_no, type, vendor_cmd, elreq.options)); - -			command_sent = INT_DEF_LB_ECHO_CMD; -			rval = qla2x00_echo_test(vha, &elreq, response); -		} -		break; -	case QLA84_RESET: -		if (!IS_QLA84XX(vha->hw)) { -			rval = -EINVAL; -			DEBUG16(printk( -				"%s(%ld): 8xxx exiting.\n", -				__func__, vha->host_no)); -			return rval; -		} -		rval = qla84xx_reset(vha, &elreq, bsg_job); -		break; -	case QLA84_MGMT_CMD: -		if (!IS_QLA84XX(vha->hw)) { -			rval = -EINVAL; -			DEBUG16(printk( -				"%s(%ld): 8xxx exiting.\n", -				__func__, vha->host_no)); -			return rval; -		} -		rval = qla84xx_mgmt_cmd(vha, &elreq, bsg_job); -		break; -	default: -		rval = -ENOSYS; -	} - -	if (rval != QLA_SUCCESS) { -		DEBUG2(qla_printk(KERN_WARNING, ha, -			"scsi(%ld) Vendor request %s failed\n", vha->host_no, type)); -		rval = 0; -		bsg_job->reply->result = (DID_ERROR << 16); -		bsg_job->reply->reply_payload_rcv_len = 0; -		fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); -		memcpy( fw_sts_ptr, response, sizeof(response)); -		fw_sts_ptr += sizeof(response); -                *fw_sts_ptr = command_sent; -	} else { -		DEBUG2(qla_printk(KERN_WARNING, ha, -			"scsi(%ld) Vendor request %s completed\n", vha->host_no, type)); -		rval = bsg_job->reply->result = 0; -		bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(response) + sizeof(uint8_t); -		bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; -		fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); -		memcpy(fw_sts_ptr, response, sizeof(response)); -		fw_sts_ptr += sizeof(response); -		*fw_sts_ptr = command_sent; -		sg_copy_from_buffer(bsg_job->reply_payload.sg_list, -		bsg_job->reply_payload.sg_cnt, rsp_data, -		rsp_data_len); -	} -	bsg_job->job_done(bsg_job); - -done_unmap_sg: - -	if(req_data) -		dma_free_coherent(&ha->pdev->dev, req_data_len, -			req_data, req_data_dma); -	dma_unmap_sg(&ha->pdev->dev, -	    bsg_job->request_payload.sg_list, -	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); -	dma_unmap_sg(&ha->pdev->dev, -	    bsg_job->reply_payload.sg_list, -	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - -done: -        return rval; -} - -static int -qla24xx_bsg_request(struct fc_bsg_job *bsg_job) -{ -        int ret = -EINVAL; - -        switch (bsg_job->request->msgcode) { -		case FC_BSG_RPT_ELS: -		case FC_BSG_HST_ELS_NOLOGIN: -			ret = qla2x00_process_els(bsg_job); -			break; -		case FC_BSG_HST_CT: -			ret = qla2x00_process_ct(bsg_job); -			break; -		case FC_BSG_HST_VENDOR: -			ret = qla2x00_process_vendor_specific(bsg_job); -			break; -		case FC_BSG_HST_ADD_RPORT: -		case FC_BSG_HST_DEL_RPORT: -		case FC_BSG_RPT_CT: -		default: -			DEBUG2(printk("qla2xxx: unsupported BSG request\n")); -			break; -        } -	return ret; -} - -static int -qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) -{ -        scsi_qla_host_t *vha = shost_priv(bsg_job->shost); -        struct qla_hw_data *ha = vha->hw; -        srb_t *sp; -        int cnt, que; -        unsigned long flags; -        struct req_que *req; -	struct srb_bsg *sp_bsg; - -	/* find the bsg job from the active list of commands */ -        spin_lock_irqsave(&ha->hardware_lock, flags); -	for (que = 0; que < ha->max_req_queues; que++) { -		req = ha->req_q_map[que]; -		if (!req) -			continue; - -		for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++ ) { -			sp = req->outstanding_cmds[cnt]; - -			if (sp) { -				sp_bsg = (struct srb_bsg*)sp->ctx; - -				if (((sp_bsg->ctx.type == SRB_CT_CMD) || -				    (sp_bsg->ctx.type == SRB_ELS_CMD_RPT) -				    || ( sp_bsg->ctx.type == SRB_ELS_CMD_HST)) && -				    (sp_bsg->bsg_job == bsg_job)) { -					if (ha->isp_ops->abort_command(sp)) { -						DEBUG2(qla_printk(KERN_INFO, ha, -						"scsi(%ld): mbx abort_command failed\n", vha->host_no)); -						bsg_job->req->errors = bsg_job->reply->result = -EIO; -					} else { -						DEBUG2(qla_printk(KERN_INFO, ha, -						"scsi(%ld): mbx abort_command success\n", vha->host_no)); -						bsg_job->req->errors = bsg_job->reply->result = 0; -					} -					goto done; -				} -			} -		} -	} -	spin_unlock_irqrestore(&ha->hardware_lock, flags); -	DEBUG2(qla_printk(KERN_INFO, ha, -		"scsi(%ld) SRB not found to abort\n", vha->host_no)); -	bsg_job->req->errors = bsg_job->reply->result = -ENXIO; -	return 0; - -done: -	spin_unlock_irqrestore(&ha->hardware_lock, flags); -	if (bsg_job->request->msgcode == FC_BSG_HST_CT) -		kfree(sp->fcport); -	kfree(sp->ctx); -	mempool_free(sp, ha->srb_mempool); -	return 0; -} -  struct fc_function_template qla2xxx_transport_functions = {  	.show_host_node_name = 1, @@ -2502,7 +1968,7 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)  	fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports;  	fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count; -	if (IS_QLA81XX(ha)) +	if (IS_QLA8XXX_TYPE(ha))  		speed = FC_PORTSPEED_10GBIT;  	else if (IS_QLA25XX(ha))  		speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | @@ -2516,125 +1982,3 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)  		speed = FC_PORTSPEED_1GBIT;  	fc_host_supported_speeds(vha->host) = speed;  } -static int -qla84xx_reset(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job) -{ -	int             ret = 0; -	int             cmd; -	uint16_t        cmd_status; - -	DEBUG16(printk("%s(%ld): entered.\n", __func__, ha->host_no)); - -	cmd = (*((bsg_job->request->rqst_data.h_vendor.vendor_cmd) + 2)) -			== A84_RESET_FLAG_ENABLE_DIAG_FW ? -				A84_ISSUE_RESET_DIAG_FW : A84_ISSUE_RESET_OP_FW; -	ret = qla84xx_reset_chip(ha, cmd == A84_ISSUE_RESET_DIAG_FW, -	&cmd_status); -	return ret; -} - -static int -qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job) -{ -	struct access_chip_84xx *mn; -	dma_addr_t mn_dma, mgmt_dma; -	void *mgmt_b = NULL; -	int ret = 0; -	int rsp_hdr_len, len = 0; -	struct qla84_msg_mgmt *ql84_mgmt; - -	ql84_mgmt = (struct qla84_msg_mgmt *) vmalloc(sizeof(struct qla84_msg_mgmt)); -	ql84_mgmt->cmd = -		*((uint16_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 2)); -	ql84_mgmt->mgmtp.u.mem.start_addr = -		*((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 3)); -	ql84_mgmt->len = -		*((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 4)); -	ql84_mgmt->mgmtp.u.config.id = -		*((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 5)); -	ql84_mgmt->mgmtp.u.config.param0 = -		*((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 6)); -	ql84_mgmt->mgmtp.u.config.param1 = -		*((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 7)); -	ql84_mgmt->mgmtp.u.info.type = -		*((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 8)); -	ql84_mgmt->mgmtp.u.info.context = -		*((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 9)); - -	rsp_hdr_len = bsg_job->request_payload.payload_len; - -	mn = dma_pool_alloc(ha->hw->s_dma_pool, GFP_KERNEL, &mn_dma); -	if (mn == NULL) { -		DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer " -		"failed%lu\n", __func__, ha->host_no)); -		return -ENOMEM; -	} - -	memset(mn, 0, sizeof (struct access_chip_84xx)); - -	mn->entry_type = ACCESS_CHIP_IOCB_TYPE; -	mn->entry_count = 1; - -	switch (ql84_mgmt->cmd) { -	case QLA84_MGMT_READ_MEM: -		mn->options = cpu_to_le16(ACO_DUMP_MEMORY); -		mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); -		break; -	case QLA84_MGMT_WRITE_MEM: -		mn->options = cpu_to_le16(ACO_LOAD_MEMORY); -		mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); -		break; -	case QLA84_MGMT_CHNG_CONFIG: -		mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); -		mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.id); -		mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param0); -		mn->parameter3 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param1); -		break; -	case QLA84_MGMT_GET_INFO: -		mn->options = cpu_to_le16(ACO_REQUEST_INFO); -		mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.type); -		mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.context); -		break; -	default: -		ret = -EIO; -		goto exit_mgmt0; -	} - -	if ((len == ql84_mgmt->len) && -		ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) { -		mgmt_b = dma_alloc_coherent(&ha->hw->pdev->dev, len, -				&mgmt_dma, GFP_KERNEL); -		if (mgmt_b == NULL) { -			DEBUG2(printk(KERN_ERR "%s: dma alloc mgmt_b " -			"failed%lu\n", __func__, ha->host_no)); -			ret = -ENOMEM; -			goto exit_mgmt0; -		} -		mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->len); -		mn->dseg_count = cpu_to_le16(1); -		mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); -		mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); -		mn->dseg_length = cpu_to_le32(len); - -		if (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) { -			memcpy(mgmt_b, ql84_mgmt->payload, len); -		} -	} - -	ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0); -	if ((ret != QLA_SUCCESS) || (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) -		|| (ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) { -			if (ret != QLA_SUCCESS) -				DEBUG2(printk(KERN_ERR "%s(%lu): failed\n", -					__func__, ha->host_no)); -	} else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM) || -			(ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) { -	} - -	if (mgmt_b) -		dma_free_coherent(&ha->hw->pdev->dev, len, mgmt_b, mgmt_dma); - -exit_mgmt0: -	dma_pool_free(ha->hw->s_dma_pool, mn, mn_dma); -	return ret; -} diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c new file mode 100644 index 00000000000..b905dfe5ea6 --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -0,0 +1,1212 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c)  2003-2008 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ +#include "qla_def.h" + +#include <linux/kthread.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> + +/* BSG support for ELS/CT pass through */ +inline srb_t * +qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size) +{ +	srb_t *sp; +	struct qla_hw_data *ha = vha->hw; +	struct srb_ctx *ctx; + +	sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); +	if (!sp) +		goto done; +	ctx = kzalloc(size, GFP_KERNEL); +	if (!ctx) { +		mempool_free(sp, ha->srb_mempool); +		sp = NULL; +		goto done; +	} + +	memset(sp, 0, sizeof(*sp)); +	sp->fcport = fcport; +	sp->ctx = ctx; +done: +	return sp; +} + +int +qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag) +{ +	int i, ret, num_valid; +	uint8_t *bcode; +	struct qla_fcp_prio_entry *pri_entry; + +	ret = 1; +	num_valid = 0; +	bcode = (uint8_t *)pri_cfg; + +	if (bcode[0x0] != 'H' || bcode[0x1] != 'Q' || bcode[0x2] != 'O' || +			bcode[0x3] != 'S') { +		return 0; +	} +	if (flag != 1) +		return ret; + +	pri_entry = &pri_cfg->entry[0]; +	for (i = 0; i < pri_cfg->num_entries; i++) { +		if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID) +			num_valid++; +		pri_entry++; +	} + +	if (num_valid == 0) +		ret = 0; + +	return ret; +} + +static int +qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job) +{ +	struct Scsi_Host *host = bsg_job->shost; +	scsi_qla_host_t *vha = shost_priv(host); +	struct qla_hw_data *ha = vha->hw; +	int ret = 0; +	uint32_t len; +	uint32_t oper; + +	bsg_job->reply->reply_payload_rcv_len = 0; + +	if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || +		test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || +		test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { +		ret = -EBUSY; +		goto exit_fcp_prio_cfg; +	} + +	/* Get the sub command */ +	oper = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; + +	/* Only set config is allowed if config memory is not allocated */ +	if (!ha->fcp_prio_cfg && (oper != QLFC_FCP_PRIO_SET_CONFIG)) { +		ret = -EINVAL; +		goto exit_fcp_prio_cfg; +	} +	switch (oper) { +	case QLFC_FCP_PRIO_DISABLE: +		if (ha->flags.fcp_prio_enabled) { +			ha->flags.fcp_prio_enabled = 0; +			ha->fcp_prio_cfg->attributes &= +				~FCP_PRIO_ATTR_ENABLE; +			qla24xx_update_all_fcp_prio(vha); +			bsg_job->reply->result = DID_OK; +		} else { +			ret = -EINVAL; +			bsg_job->reply->result = (DID_ERROR << 16); +			goto exit_fcp_prio_cfg; +		} +		break; + +	case QLFC_FCP_PRIO_ENABLE: +		if (!ha->flags.fcp_prio_enabled) { +			if (ha->fcp_prio_cfg) { +				ha->flags.fcp_prio_enabled = 1; +				ha->fcp_prio_cfg->attributes |= +				    FCP_PRIO_ATTR_ENABLE; +				qla24xx_update_all_fcp_prio(vha); +				bsg_job->reply->result = DID_OK; +			} else { +				ret = -EINVAL; +				bsg_job->reply->result = (DID_ERROR << 16); +				goto exit_fcp_prio_cfg; +			} +		} +		break; + +	case QLFC_FCP_PRIO_GET_CONFIG: +		len = bsg_job->reply_payload.payload_len; +		if (!len || len > FCP_PRIO_CFG_SIZE) { +			ret = -EINVAL; +			bsg_job->reply->result = (DID_ERROR << 16); +			goto exit_fcp_prio_cfg; +		} + +		bsg_job->reply->result = DID_OK; +		bsg_job->reply->reply_payload_rcv_len = +			sg_copy_from_buffer( +			bsg_job->reply_payload.sg_list, +			bsg_job->reply_payload.sg_cnt, ha->fcp_prio_cfg, +			len); + +		break; + +	case QLFC_FCP_PRIO_SET_CONFIG: +		len = bsg_job->request_payload.payload_len; +		if (!len || len > FCP_PRIO_CFG_SIZE) { +			bsg_job->reply->result = (DID_ERROR << 16); +			ret = -EINVAL; +			goto exit_fcp_prio_cfg; +		} + +		if (!ha->fcp_prio_cfg) { +			ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE); +			if (!ha->fcp_prio_cfg) { +				qla_printk(KERN_WARNING, ha, +					"Unable to allocate memory " +					"for fcp prio config data (%x).\n", +					FCP_PRIO_CFG_SIZE); +				bsg_job->reply->result = (DID_ERROR << 16); +				ret = -ENOMEM; +				goto exit_fcp_prio_cfg; +			} +		} + +		memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE); +		sg_copy_to_buffer(bsg_job->request_payload.sg_list, +		bsg_job->request_payload.sg_cnt, ha->fcp_prio_cfg, +			FCP_PRIO_CFG_SIZE); + +		/* validate fcp priority data */ +		if (!qla24xx_fcp_prio_cfg_valid( +			(struct qla_fcp_prio_cfg *) +			ha->fcp_prio_cfg, 1)) { +			bsg_job->reply->result = (DID_ERROR << 16); +			ret = -EINVAL; +			/* If buffer was invalidatic int +			 * fcp_prio_cfg is of no use +			 */ +			vfree(ha->fcp_prio_cfg); +			ha->fcp_prio_cfg = NULL; +			goto exit_fcp_prio_cfg; +		} + +		ha->flags.fcp_prio_enabled = 0; +		if (ha->fcp_prio_cfg->attributes & FCP_PRIO_ATTR_ENABLE) +			ha->flags.fcp_prio_enabled = 1; +		qla24xx_update_all_fcp_prio(vha); +		bsg_job->reply->result = DID_OK; +		break; +	default: +		ret = -EINVAL; +		break; +	} +exit_fcp_prio_cfg: +	bsg_job->job_done(bsg_job); +	return ret; +} +static int +qla2x00_process_els(struct fc_bsg_job *bsg_job) +{ +	struct fc_rport *rport; +	fc_port_t *fcport; +	struct Scsi_Host *host; +	scsi_qla_host_t *vha; +	struct qla_hw_data *ha; +	srb_t *sp; +	const char *type; +	int req_sg_cnt, rsp_sg_cnt; +	int rval =  (DRIVER_ERROR << 16); +	uint16_t nextlid = 0; +	struct srb_ctx *els; + +	/*  Multiple SG's are not supported for ELS requests */ +	if (bsg_job->request_payload.sg_cnt > 1 || +		bsg_job->reply_payload.sg_cnt > 1) { +		DEBUG2(printk(KERN_INFO +			"multiple SG's are not supported for ELS requests" +			" [request_sg_cnt: %x reply_sg_cnt: %x]\n", +			bsg_job->request_payload.sg_cnt, +			bsg_job->reply_payload.sg_cnt)); +		rval = -EPERM; +		goto done; +	} + +	/* ELS request for rport */ +	if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { +		rport = bsg_job->rport; +		fcport = *(fc_port_t **) rport->dd_data; +		host = rport_to_shost(rport); +		vha = shost_priv(host); +		ha = vha->hw; +		type = "FC_BSG_RPT_ELS"; + +		/* make sure the rport is logged in, +		 * if not perform fabric login +		 */ +		if (qla2x00_fabric_login(vha, fcport, &nextlid)) { +			DEBUG2(qla_printk(KERN_WARNING, ha, +			"failed to login port %06X for ELS passthru\n", +			fcport->d_id.b24)); +			rval = -EIO; +			goto done; +		} +	} else { +		host = bsg_job->shost; +		vha = shost_priv(host); +		ha = vha->hw; +		type = "FC_BSG_HST_ELS_NOLOGIN"; + +		/* Allocate a dummy fcport structure, since functions +		 * preparing the IOCB and mailbox command retrieves port +		 * specific information from fcport structure. For Host based +		 * ELS commands there will be no fcport structure allocated +		 */ +		fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); +		if (!fcport) { +			rval = -ENOMEM; +			goto done; +		} + +		/* Initialize all required  fields of fcport */ +		fcport->vha = vha; +		fcport->vp_idx = vha->vp_idx; +		fcport->d_id.b.al_pa = +			bsg_job->request->rqst_data.h_els.port_id[0]; +		fcport->d_id.b.area = +			bsg_job->request->rqst_data.h_els.port_id[1]; +		fcport->d_id.b.domain = +			bsg_job->request->rqst_data.h_els.port_id[2]; +		fcport->loop_id = +			(fcport->d_id.b.al_pa == 0xFD) ? +			NPH_FABRIC_CONTROLLER : NPH_F_PORT; +	} + +	if (!vha->flags.online) { +		DEBUG2(qla_printk(KERN_WARNING, ha, +		"host not online\n")); +		rval = -EIO; +		goto done; +	} + +	req_sg_cnt = +		dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, +		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); +	if (!req_sg_cnt) { +		rval = -ENOMEM; +		goto done_free_fcport; +	} + +	rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, +		bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); +        if (!rsp_sg_cnt) { +		rval = -ENOMEM; +		goto done_free_fcport; +	} + +	if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) || +		(rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { +		DEBUG2(printk(KERN_INFO +			"dma mapping resulted in different sg counts \ +			[request_sg_cnt: %x dma_request_sg_cnt: %x\ +			reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", +			bsg_job->request_payload.sg_cnt, req_sg_cnt, +			bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); +		rval = -EAGAIN; +		goto done_unmap_sg; +	} + +	/* Alloc SRB structure */ +	sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx)); +	if (!sp) { +		rval = -ENOMEM; +		goto done_unmap_sg; +	} + +	els = sp->ctx; +	els->type = +		(bsg_job->request->msgcode == FC_BSG_RPT_ELS ? +		SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); +	els->name = +		(bsg_job->request->msgcode == FC_BSG_RPT_ELS ? +		"bsg_els_rpt" : "bsg_els_hst"); +	els->u.bsg_job = bsg_job; + +	DEBUG2(qla_printk(KERN_INFO, ha, +		"scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " +		"portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, +		bsg_job->request->rqst_data.h_els.command_code, +		fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, +		fcport->d_id.b.al_pa)); + +	rval = qla2x00_start_sp(sp); +	if (rval != QLA_SUCCESS) { +		kfree(sp->ctx); +		mempool_free(sp, ha->srb_mempool); +		rval = -EIO; +		goto done_unmap_sg; +	} +	return rval; + +done_unmap_sg: +	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, +		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); +	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, +		bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); +	goto done_free_fcport; + +done_free_fcport: +	if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN) +		kfree(fcport); +done: +	return rval; +} + +static int +qla2x00_process_ct(struct fc_bsg_job *bsg_job) +{ +	srb_t *sp; +	struct Scsi_Host *host = bsg_job->shost; +	scsi_qla_host_t *vha = shost_priv(host); +	struct qla_hw_data *ha = vha->hw; +	int rval = (DRIVER_ERROR << 16); +	int req_sg_cnt, rsp_sg_cnt; +	uint16_t loop_id; +	struct fc_port *fcport; +	char  *type = "FC_BSG_HST_CT"; +	struct srb_ctx *ct; + +	/* pass through is supported only for ISP 4Gb or higher */ +	if (!IS_FWI2_CAPABLE(ha)) { +		DEBUG2(qla_printk(KERN_INFO, ha, +		    "scsi(%ld):Firmware is not capable to support FC " +		    "CT pass thru\n", vha->host_no)); +		rval = -EPERM; +		goto done; +	} + +	req_sg_cnt = +		dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, +			bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); +	if (!req_sg_cnt) { +		rval = -ENOMEM; +		goto done; +	} + +	rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, +		bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); +	if (!rsp_sg_cnt) { +		rval = -ENOMEM; +		goto done; +	} + +	if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) || +	    (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { +		DEBUG2(qla_printk(KERN_WARNING, ha, +		    "[request_sg_cnt: %x dma_request_sg_cnt: %x\ +		    reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", +		    bsg_job->request_payload.sg_cnt, req_sg_cnt, +		    bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); +		rval = -EAGAIN; +		goto done_unmap_sg; +	} + +	if (!vha->flags.online) { +		DEBUG2(qla_printk(KERN_WARNING, ha, +			"host not online\n")); +		rval = -EIO; +		goto done_unmap_sg; +	} + +	loop_id = +		(bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000) +			>> 24; +	switch (loop_id) { +	case 0xFC: +		loop_id = cpu_to_le16(NPH_SNS); +		break; +	case 0xFA: +		loop_id = vha->mgmt_svr_loop_id; +		break; +	default: +		DEBUG2(qla_printk(KERN_INFO, ha, +		    "Unknown loop id: %x\n", loop_id)); +		rval = -EINVAL; +		goto done_unmap_sg; +	} + +	/* Allocate a dummy fcport structure, since functions preparing the +	 * IOCB and mailbox command retrieves port specific information +	 * from fcport structure. For Host based ELS commands there will be +	 * no fcport structure allocated +	 */ +	fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); +	if (!fcport) { +		rval = -ENOMEM; +		goto done_unmap_sg; +	} + +	/* Initialize all required  fields of fcport */ +	fcport->vha = vha; +	fcport->vp_idx = vha->vp_idx; +	fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0]; +	fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1]; +	fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2]; +	fcport->loop_id = loop_id; + +	/* Alloc SRB structure */ +	sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx)); +	if (!sp) { +		rval = -ENOMEM; +		goto done_free_fcport; +	} + +	ct = sp->ctx; +	ct->type = SRB_CT_CMD; +	ct->name = "bsg_ct"; +	ct->u.bsg_job = bsg_job; + +	DEBUG2(qla_printk(KERN_INFO, ha, +		"scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " +		"portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, +		(bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16), +		fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, +		fcport->d_id.b.al_pa)); + +	rval = qla2x00_start_sp(sp); +	if (rval != QLA_SUCCESS) { +		kfree(sp->ctx); +		mempool_free(sp, ha->srb_mempool); +		rval = -EIO; +		goto done_free_fcport; +	} +	return rval; + +done_free_fcport: +	kfree(fcport); +done_unmap_sg: +	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, +		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); +	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, +		bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); +done: +	return rval; +} + +static int +qla2x00_process_loopback(struct fc_bsg_job *bsg_job) +{ +	struct Scsi_Host *host = bsg_job->shost; +	scsi_qla_host_t *vha = shost_priv(host); +	struct qla_hw_data *ha = vha->hw; +	int rval; +	uint8_t command_sent; +	char *type; +	struct msg_echo_lb elreq; +	uint16_t response[MAILBOX_REGISTER_COUNT]; +	uint8_t *fw_sts_ptr; +	uint8_t *req_data = NULL; +	dma_addr_t req_data_dma; +	uint32_t req_data_len; +	uint8_t *rsp_data = NULL; +	dma_addr_t rsp_data_dma; +	uint32_t rsp_data_len; + +	if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || +		test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || +		test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) +		return -EBUSY; + +	if (!vha->flags.online) { +		DEBUG2(qla_printk(KERN_WARNING, ha, "host not online\n")); +		return -EIO; +	} + +	elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev, +		bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, +		DMA_TO_DEVICE); + +	if (!elreq.req_sg_cnt) +		return -ENOMEM; + +	elreq.rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, +		bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt, +		DMA_FROM_DEVICE); + +	if (!elreq.rsp_sg_cnt) { +		rval = -ENOMEM; +		goto done_unmap_req_sg; +	} + +	if ((elreq.req_sg_cnt !=  bsg_job->request_payload.sg_cnt) || +		(elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { +		DEBUG2(printk(KERN_INFO +			"dma mapping resulted in different sg counts " +			"[request_sg_cnt: %x dma_request_sg_cnt: %x " +			"reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", +			bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt, +			bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt)); +		rval = -EAGAIN; +		goto done_unmap_sg; +	} +	req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; +	req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len, +		&req_data_dma, GFP_KERNEL); +	if (!req_data) { +		DEBUG2(printk(KERN_ERR "%s: dma alloc for req_data " +			"failed for host=%lu\n", __func__, vha->host_no)); +		rval = -ENOMEM; +		goto done_unmap_sg; +	} + +	rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len, +		&rsp_data_dma, GFP_KERNEL); +	if (!rsp_data) { +		DEBUG2(printk(KERN_ERR "%s: dma alloc for rsp_data " +			"failed for host=%lu\n", __func__, vha->host_no)); +		rval = -ENOMEM; +		goto done_free_dma_req; +	} + +	/* Copy the request buffer in req_data now */ +	sg_copy_to_buffer(bsg_job->request_payload.sg_list, +		bsg_job->request_payload.sg_cnt, req_data, req_data_len); + +	elreq.send_dma = req_data_dma; +	elreq.rcv_dma = rsp_data_dma; +	elreq.transfer_size = req_data_len; + +	elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; + +	if (ha->current_topology != ISP_CFG_F) { +		type = "FC_BSG_HST_VENDOR_LOOPBACK"; +		DEBUG2(qla_printk(KERN_INFO, ha, +			"scsi(%ld) bsg rqst type: %s\n", +			vha->host_no, type)); + +		command_sent = INT_DEF_LB_LOOPBACK_CMD; +		rval = qla2x00_loopback_test(vha, &elreq, response); +		if (IS_QLA81XX(ha)) { +			if (response[0] == MBS_COMMAND_ERROR && +				response[1] == MBS_LB_RESET) { +				DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing " +				"ISP\n", __func__, vha->host_no)); +				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); +				qla2xxx_wake_dpc(vha); +			} +		} +	} else { +		type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; +		DEBUG2(qla_printk(KERN_INFO, ha, +		    "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type)); +		command_sent = INT_DEF_LB_ECHO_CMD; +		rval = qla2x00_echo_test(vha, &elreq, response); +	} + +	if (rval) { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " +		    "request %s failed\n", vha->host_no, type)); + +		fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) + +		    sizeof(struct fc_bsg_reply); + +		memcpy(fw_sts_ptr, response, sizeof(response)); +		fw_sts_ptr += sizeof(response); +		*fw_sts_ptr = command_sent; +		rval = 0; +		bsg_job->reply->reply_payload_rcv_len = 0; +		bsg_job->reply->result = (DID_ERROR << 16); +	} else { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " +			"request %s completed\n", vha->host_no, type)); + +		bsg_job->reply_len = sizeof(struct fc_bsg_reply) + +			sizeof(response) + sizeof(uint8_t); +		bsg_job->reply->reply_payload_rcv_len = +			bsg_job->reply_payload.payload_len; +		fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) + +			sizeof(struct fc_bsg_reply); +		memcpy(fw_sts_ptr, response, sizeof(response)); +		fw_sts_ptr += sizeof(response); +		*fw_sts_ptr = command_sent; +		bsg_job->reply->result = DID_OK; +		sg_copy_from_buffer(bsg_job->reply_payload.sg_list, +			bsg_job->reply_payload.sg_cnt, rsp_data, +			rsp_data_len); +	} +	bsg_job->job_done(bsg_job); + +	dma_free_coherent(&ha->pdev->dev, rsp_data_len, +		rsp_data, rsp_data_dma); +done_free_dma_req: +	dma_free_coherent(&ha->pdev->dev, req_data_len, +		req_data, req_data_dma); +done_unmap_sg: +	dma_unmap_sg(&ha->pdev->dev, +	    bsg_job->reply_payload.sg_list, +	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); +done_unmap_req_sg: +	dma_unmap_sg(&ha->pdev->dev, +	    bsg_job->request_payload.sg_list, +	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); +	return rval; +} + +static int +qla84xx_reset(struct fc_bsg_job *bsg_job) +{ +	struct Scsi_Host *host = bsg_job->shost; +	scsi_qla_host_t *vha = shost_priv(host); +	struct qla_hw_data *ha = vha->hw; +	int rval = 0; +	uint32_t flag; + +	if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || +	    test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || +	    test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) +		return -EBUSY; + +	if (!IS_QLA84XX(ha)) { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, " +		   "exiting.\n", vha->host_no)); +		return -EINVAL; +	} + +	flag = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; + +	rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW); + +	if (rval) { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " +		    "request 84xx reset failed\n", vha->host_no)); +		rval = bsg_job->reply->reply_payload_rcv_len = 0; +		bsg_job->reply->result = (DID_ERROR << 16); + +	} else { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " +		    "request 84xx reset completed\n", vha->host_no)); +		bsg_job->reply->result = DID_OK; +	} + +	bsg_job->job_done(bsg_job); +	return rval; +} + +static int +qla84xx_updatefw(struct fc_bsg_job *bsg_job) +{ +	struct Scsi_Host *host = bsg_job->shost; +	scsi_qla_host_t *vha = shost_priv(host); +	struct qla_hw_data *ha = vha->hw; +	struct verify_chip_entry_84xx *mn = NULL; +	dma_addr_t mn_dma, fw_dma; +	void *fw_buf = NULL; +	int rval = 0; +	uint32_t sg_cnt; +	uint32_t data_len; +	uint16_t options; +	uint32_t flag; +	uint32_t fw_ver; + +	if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || +		test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || +		test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) +		return -EBUSY; + +	if (!IS_QLA84XX(ha)) { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, " +			"exiting.\n", vha->host_no)); +		return -EINVAL; +	} + +	sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, +		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); +	if (!sg_cnt) +		return -ENOMEM; + +	if (sg_cnt != bsg_job->request_payload.sg_cnt) { +		DEBUG2(printk(KERN_INFO +			"dma mapping resulted in different sg counts " +			"request_sg_cnt: %x dma_request_sg_cnt: %x ", +			bsg_job->request_payload.sg_cnt, sg_cnt)); +		rval = -EAGAIN; +		goto done_unmap_sg; +	} + +	data_len = bsg_job->request_payload.payload_len; +	fw_buf = dma_alloc_coherent(&ha->pdev->dev, data_len, +		&fw_dma, GFP_KERNEL); +	if (!fw_buf) { +		DEBUG2(printk(KERN_ERR "%s: dma alloc for fw_buf " +			"failed for host=%lu\n", __func__, vha->host_no)); +		rval = -ENOMEM; +		goto done_unmap_sg; +	} + +	sg_copy_to_buffer(bsg_job->request_payload.sg_list, +		bsg_job->request_payload.sg_cnt, fw_buf, data_len); + +	mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); +	if (!mn) { +		DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer " +			"failed for host=%lu\n", __func__, vha->host_no)); +		rval = -ENOMEM; +		goto done_free_fw_buf; +	} + +	flag = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; +	fw_ver = le32_to_cpu(*((uint32_t *)((uint32_t *)fw_buf + 2))); + +	memset(mn, 0, sizeof(struct access_chip_84xx)); +	mn->entry_type = VERIFY_CHIP_IOCB_TYPE; +	mn->entry_count = 1; + +	options = VCO_FORCE_UPDATE | VCO_END_OF_DATA; +	if (flag == A84_ISSUE_UPDATE_DIAGFW_CMD) +		options |= VCO_DIAG_FW; + +	mn->options = cpu_to_le16(options); +	mn->fw_ver =  cpu_to_le32(fw_ver); +	mn->fw_size =  cpu_to_le32(data_len); +	mn->fw_seq_size =  cpu_to_le32(data_len); +	mn->dseg_address[0] = cpu_to_le32(LSD(fw_dma)); +	mn->dseg_address[1] = cpu_to_le32(MSD(fw_dma)); +	mn->dseg_length = cpu_to_le32(data_len); +	mn->data_seg_cnt = cpu_to_le16(1); + +	rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120); + +	if (rval) { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " +			"request 84xx updatefw failed\n", vha->host_no)); + +		rval = bsg_job->reply->reply_payload_rcv_len = 0; +		bsg_job->reply->result = (DID_ERROR << 16); + +	} else { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " +			"request 84xx updatefw completed\n", vha->host_no)); + +		bsg_job->reply_len = sizeof(struct fc_bsg_reply); +		bsg_job->reply->result = DID_OK; +	} + +	bsg_job->job_done(bsg_job); +	dma_pool_free(ha->s_dma_pool, mn, mn_dma); + +done_free_fw_buf: +	dma_free_coherent(&ha->pdev->dev, data_len, fw_buf, fw_dma); + +done_unmap_sg: +	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, +		bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + +	return rval; +} + +static int +qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job) +{ +	struct Scsi_Host *host = bsg_job->shost; +	scsi_qla_host_t *vha = shost_priv(host); +	struct qla_hw_data *ha = vha->hw; +	struct access_chip_84xx *mn = NULL; +	dma_addr_t mn_dma, mgmt_dma; +	void *mgmt_b = NULL; +	int rval = 0; +	struct qla_bsg_a84_mgmt *ql84_mgmt; +	uint32_t sg_cnt; +	uint32_t data_len = 0; +	uint32_t dma_direction = DMA_NONE; + +	if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || +		test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || +		test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) +		return -EBUSY; + +	if (!IS_QLA84XX(ha)) { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, " +			"exiting.\n", vha->host_no)); +		return -EINVAL; +	} + +	ql84_mgmt = (struct qla_bsg_a84_mgmt *)((char *)bsg_job->request + +		sizeof(struct fc_bsg_request)); +	if (!ql84_mgmt) { +		DEBUG2(printk("%s(%ld): mgmt header not provided, exiting.\n", +			__func__, vha->host_no)); +		return -EINVAL; +	} + +	mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); +	if (!mn) { +		DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer " +			"failed for host=%lu\n", __func__, vha->host_no)); +		return -ENOMEM; +	} + +	memset(mn, 0, sizeof(struct access_chip_84xx)); +	mn->entry_type = ACCESS_CHIP_IOCB_TYPE; +	mn->entry_count = 1; + +	switch (ql84_mgmt->mgmt.cmd) { +	case QLA84_MGMT_READ_MEM: +	case QLA84_MGMT_GET_INFO: +		sg_cnt = dma_map_sg(&ha->pdev->dev, +			bsg_job->reply_payload.sg_list, +			bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); +		if (!sg_cnt) { +			rval = -ENOMEM; +			goto exit_mgmt; +		} + +		dma_direction = DMA_FROM_DEVICE; + +		if (sg_cnt != bsg_job->reply_payload.sg_cnt) { +			DEBUG2(printk(KERN_INFO +				"dma mapping resulted in different sg counts " +				"reply_sg_cnt: %x dma_reply_sg_cnt: %x\n", +				bsg_job->reply_payload.sg_cnt, sg_cnt)); +			rval = -EAGAIN; +			goto done_unmap_sg; +		} + +		data_len = bsg_job->reply_payload.payload_len; + +		mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len, +		    &mgmt_dma, GFP_KERNEL); +		if (!mgmt_b) { +			DEBUG2(printk(KERN_ERR "%s: dma alloc for mgmt_b " +				"failed for host=%lu\n", +				__func__, vha->host_no)); +			rval = -ENOMEM; +			goto done_unmap_sg; +		} + +		if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) { +			mn->options = cpu_to_le16(ACO_DUMP_MEMORY); +			mn->parameter1 = +				cpu_to_le32( +				ql84_mgmt->mgmt.mgmtp.u.mem.start_addr); + +		} else if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO) { +			mn->options = cpu_to_le16(ACO_REQUEST_INFO); +			mn->parameter1 = +				cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.info.type); + +			mn->parameter2 = +				cpu_to_le32( +				ql84_mgmt->mgmt.mgmtp.u.info.context); +		} +		break; + +	case QLA84_MGMT_WRITE_MEM: +		sg_cnt = dma_map_sg(&ha->pdev->dev, +			bsg_job->request_payload.sg_list, +			bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + +		if (!sg_cnt) { +			rval = -ENOMEM; +			goto exit_mgmt; +		} + +		dma_direction = DMA_TO_DEVICE; + +		if (sg_cnt != bsg_job->request_payload.sg_cnt) { +			DEBUG2(printk(KERN_INFO +				"dma mapping resulted in different sg counts " +				"request_sg_cnt: %x dma_request_sg_cnt: %x ", +				bsg_job->request_payload.sg_cnt, sg_cnt)); +			rval = -EAGAIN; +			goto done_unmap_sg; +		} + +		data_len = bsg_job->request_payload.payload_len; +		mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len, +			&mgmt_dma, GFP_KERNEL); +		if (!mgmt_b) { +			DEBUG2(printk(KERN_ERR "%s: dma alloc for mgmt_b " +				"failed for host=%lu\n", +				__func__, vha->host_no)); +			rval = -ENOMEM; +			goto done_unmap_sg; +		} + +		sg_copy_to_buffer(bsg_job->request_payload.sg_list, +			bsg_job->request_payload.sg_cnt, mgmt_b, data_len); + +		mn->options = cpu_to_le16(ACO_LOAD_MEMORY); +		mn->parameter1 = +			cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.mem.start_addr); +		break; + +	case QLA84_MGMT_CHNG_CONFIG: +		mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); +		mn->parameter1 = +			cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.id); + +		mn->parameter2 = +			cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param0); + +		mn->parameter3 = +			cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param1); +		break; + +	default: +		rval = -EIO; +		goto exit_mgmt; +	} + +	if (ql84_mgmt->mgmt.cmd != QLA84_MGMT_CHNG_CONFIG) { +		mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->mgmt.len); +		mn->dseg_count = cpu_to_le16(1); +		mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); +		mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); +		mn->dseg_length = cpu_to_le32(ql84_mgmt->mgmt.len); +	} + +	rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0); + +	if (rval) { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " +			"request 84xx mgmt failed\n", vha->host_no)); + +		rval = bsg_job->reply->reply_payload_rcv_len = 0; +		bsg_job->reply->result = (DID_ERROR << 16); + +	} else { +		DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " +			"request 84xx mgmt completed\n", vha->host_no)); + +		bsg_job->reply_len = sizeof(struct fc_bsg_reply); +		bsg_job->reply->result = DID_OK; + +		if ((ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) || +			(ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO)) { +			bsg_job->reply->reply_payload_rcv_len = +				bsg_job->reply_payload.payload_len; + +			sg_copy_from_buffer(bsg_job->reply_payload.sg_list, +				bsg_job->reply_payload.sg_cnt, mgmt_b, +				data_len); +		} +	} + +	bsg_job->job_done(bsg_job); + +done_unmap_sg: +	if (mgmt_b) +		dma_free_coherent(&ha->pdev->dev, data_len, mgmt_b, mgmt_dma); + +	if (dma_direction == DMA_TO_DEVICE) +		dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, +			bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); +	else if (dma_direction == DMA_FROM_DEVICE) +		dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, +			bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + +exit_mgmt: +	dma_pool_free(ha->s_dma_pool, mn, mn_dma); + +	return rval; +} + +static int +qla24xx_iidma(struct fc_bsg_job *bsg_job) +{ +	struct Scsi_Host *host = bsg_job->shost; +	scsi_qla_host_t *vha = shost_priv(host); +	struct qla_hw_data *ha = vha->hw; +	int rval = 0; +	struct qla_port_param *port_param = NULL; +	fc_port_t *fcport = NULL; +	uint16_t mb[MAILBOX_REGISTER_COUNT]; +	uint8_t *rsp_ptr = NULL; + +	bsg_job->reply->reply_payload_rcv_len = 0; + +	if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || +		test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || +		test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) +		return -EBUSY; + +	if (!IS_IIDMA_CAPABLE(vha->hw)) { +		DEBUG2(qla_printk(KERN_WARNING, ha, "%s(%lu): iiDMA not " +			"supported\n",  __func__, vha->host_no)); +		return -EINVAL; +	} + +	port_param = (struct qla_port_param *)((char *)bsg_job->request + +		sizeof(struct fc_bsg_request)); +	if (!port_param) { +		DEBUG2(printk("%s(%ld): port_param header not provided, " +			"exiting.\n", __func__, vha->host_no)); +		return -EINVAL; +	} + +	if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) { +		DEBUG2(printk(KERN_ERR "%s(%ld): Invalid destination type\n", +			__func__, vha->host_no)); +		return -EINVAL; +	} + +	list_for_each_entry(fcport, &vha->vp_fcports, list) { +		if (fcport->port_type != FCT_TARGET) +			continue; + +		if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn, +			fcport->port_name, sizeof(fcport->port_name))) +			continue; +		break; +	} + +	if (!fcport) { +		DEBUG2(printk(KERN_ERR "%s(%ld): Failed to find port\n", +			__func__, vha->host_no)); +		return -EINVAL; +	} + +	if (port_param->mode) +		rval = qla2x00_set_idma_speed(vha, fcport->loop_id, +			port_param->speed, mb); +	else +		rval = qla2x00_get_idma_speed(vha, fcport->loop_id, +			&port_param->speed, mb); + +	if (rval) { +		DEBUG16(printk(KERN_ERR "scsi(%ld): iIDMA cmd failed for " +			"%02x%02x%02x%02x%02x%02x%02x%02x -- " +			"%04x %x %04x %04x.\n", +			vha->host_no, fcport->port_name[0], +			fcport->port_name[1], +			fcport->port_name[2], fcport->port_name[3], +			fcport->port_name[4], fcport->port_name[5], +			fcport->port_name[6], fcport->port_name[7], rval, +			fcport->fp_speed, mb[0], mb[1])); +		rval = 0; +		bsg_job->reply->result = (DID_ERROR << 16); + +	} else { +		if (!port_param->mode) { +			bsg_job->reply_len = sizeof(struct fc_bsg_reply) + +				sizeof(struct qla_port_param); + +			rsp_ptr = ((uint8_t *)bsg_job->reply) + +				sizeof(struct fc_bsg_reply); + +			memcpy(rsp_ptr, port_param, +				sizeof(struct qla_port_param)); +		} + +		bsg_job->reply->result = DID_OK; +	} + +	bsg_job->job_done(bsg_job); +	return rval; +} + +static int +qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) +{ +	switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { +	case QL_VND_LOOPBACK: +		return qla2x00_process_loopback(bsg_job); + +	case QL_VND_A84_RESET: +		return qla84xx_reset(bsg_job); + +	case QL_VND_A84_UPDATE_FW: +		return qla84xx_updatefw(bsg_job); + +	case QL_VND_A84_MGMT_CMD: +		return qla84xx_mgmt_cmd(bsg_job); + +	case QL_VND_IIDMA: +		return qla24xx_iidma(bsg_job); + +	case QL_VND_FCP_PRIO_CFG_CMD: +		return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job); + +	default: +		bsg_job->reply->result = (DID_ERROR << 16); +		bsg_job->job_done(bsg_job); +		return -ENOSYS; +	} +} + +int +qla24xx_bsg_request(struct fc_bsg_job *bsg_job) +{ +	int ret = -EINVAL; + +	switch (bsg_job->request->msgcode) { +	case FC_BSG_RPT_ELS: +	case FC_BSG_HST_ELS_NOLOGIN: +		ret = qla2x00_process_els(bsg_job); +		break; +	case FC_BSG_HST_CT: +		ret = qla2x00_process_ct(bsg_job); +		break; +	case FC_BSG_HST_VENDOR: +		ret = qla2x00_process_vendor_specific(bsg_job); +		break; +	case FC_BSG_HST_ADD_RPORT: +	case FC_BSG_HST_DEL_RPORT: +	case FC_BSG_RPT_CT: +	default: +		DEBUG2(printk("qla2xxx: unsupported BSG request\n")); +		break; +	} +	return ret; +} + +int +qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) +{ +	scsi_qla_host_t *vha = shost_priv(bsg_job->shost); +	struct qla_hw_data *ha = vha->hw; +	srb_t *sp; +	int cnt, que; +	unsigned long flags; +	struct req_que *req; +	struct srb_ctx *sp_bsg; + +	/* find the bsg job from the active list of commands */ +	spin_lock_irqsave(&ha->hardware_lock, flags); +	for (que = 0; que < ha->max_req_queues; que++) { +		req = ha->req_q_map[que]; +		if (!req) +			continue; + +		for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { +			sp = req->outstanding_cmds[cnt]; +			if (sp) { +				sp_bsg = sp->ctx; + +				if (((sp_bsg->type == SRB_CT_CMD) || +					(sp_bsg->type == SRB_ELS_CMD_HST)) +					&& (sp_bsg->u.bsg_job == bsg_job)) { +					if (ha->isp_ops->abort_command(sp)) { +						DEBUG2(qla_printk(KERN_INFO, ha, +						    "scsi(%ld): mbx " +						    "abort_command failed\n", +						    vha->host_no)); +						bsg_job->req->errors = +						bsg_job->reply->result = -EIO; +					} else { +						DEBUG2(qla_printk(KERN_INFO, ha, +						    "scsi(%ld): mbx " +						    "abort_command success\n", +						    vha->host_no)); +						bsg_job->req->errors = +						bsg_job->reply->result = 0; +					} +					goto done; +				} +			} +		} +	} +	spin_unlock_irqrestore(&ha->hardware_lock, flags); +	DEBUG2(qla_printk(KERN_INFO, ha, +		"scsi(%ld) SRB not found to abort\n", vha->host_no)); +	bsg_job->req->errors = bsg_job->reply->result = -ENXIO; +	return 0; + +done: +	spin_unlock_irqrestore(&ha->hardware_lock, flags); +	if (bsg_job->request->msgcode == FC_BSG_HST_CT) +		kfree(sp->fcport); +	kfree(sp->ctx); +	mempool_free(sp, ha->srb_mempool); +	return 0; +} diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h new file mode 100644 index 00000000000..76ed92dd2ef --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -0,0 +1,135 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c)  2003-2008 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ +#ifndef __QLA_BSG_H +#define __QLA_BSG_H + +/* BSG Vendor specific commands */ +#define QL_VND_LOOPBACK		0x01 +#define QL_VND_A84_RESET	0x02 +#define QL_VND_A84_UPDATE_FW	0x03 +#define QL_VND_A84_MGMT_CMD	0x04 +#define QL_VND_IIDMA		0x05 +#define QL_VND_FCP_PRIO_CFG_CMD	0x06 + +/* BSG definations for interpreting CommandSent field */ +#define INT_DEF_LB_LOOPBACK_CMD         0 +#define INT_DEF_LB_ECHO_CMD             1 + +/* BSG Vendor specific definations */ +#define A84_ISSUE_WRITE_TYPE_CMD        0 +#define A84_ISSUE_READ_TYPE_CMD         1 +#define A84_CLEANUP_CMD                 2 +#define A84_ISSUE_RESET_OP_FW           3 +#define A84_ISSUE_RESET_DIAG_FW         4 +#define A84_ISSUE_UPDATE_OPFW_CMD       5 +#define A84_ISSUE_UPDATE_DIAGFW_CMD     6 + +struct qla84_mgmt_param { +	union { +		struct { +			uint32_t start_addr; +		} mem; /* for QLA84_MGMT_READ/WRITE_MEM */ +		struct { +			uint32_t id; +#define QLA84_MGMT_CONFIG_ID_UIF        1 +#define QLA84_MGMT_CONFIG_ID_FCOE_COS   2 +#define QLA84_MGMT_CONFIG_ID_PAUSE      3 +#define QLA84_MGMT_CONFIG_ID_TIMEOUTS   4 + +		uint32_t param0; +		uint32_t param1; +	} config; /* for QLA84_MGMT_CHNG_CONFIG */ + +	struct { +		uint32_t type; +#define QLA84_MGMT_INFO_CONFIG_LOG_DATA         1 /* Get Config Log Data */ +#define QLA84_MGMT_INFO_LOG_DATA                2 /* Get Log Data */ +#define QLA84_MGMT_INFO_PORT_STAT               3 /* Get Port Statistics */ +#define QLA84_MGMT_INFO_LIF_STAT                4 /* Get LIF Statistics  */ +#define QLA84_MGMT_INFO_ASIC_STAT               5 /* Get ASIC Statistics */ +#define QLA84_MGMT_INFO_CONFIG_PARAMS           6 /* Get Config Parameters */ +#define QLA84_MGMT_INFO_PANIC_LOG               7 /* Get Panic Log */ + +		uint32_t context; +/* +* context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA +*/ +#define IC_LOG_DATA_LOG_ID_DEBUG_LOG                    0 +#define IC_LOG_DATA_LOG_ID_LEARN_LOG                    1 +#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG           2 +#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG            3 +#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG     4 +#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG      5 +#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG         6 +#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG          7 +#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG               8 +#define IC_LOG_DATA_LOG_ID_DCX_LOG                      9 + +/* +* context definitions for QLA84_MGMT_INFO_PORT_STAT +*/ +#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0   0 +#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1   1 +#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0        2 +#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1        3 +#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0         4 +#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1         5 + + +/* +* context definitions for QLA84_MGMT_INFO_LIF_STAT +*/ +#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0     0 +#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1     1 +#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0           2 +#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1           3 +#define IC_LIF_STATISTICS_LIF_NUMBER_CPU                6 + +		} info; /* for QLA84_MGMT_GET_INFO */ +	} u; +}; + +struct qla84_msg_mgmt { +	uint16_t cmd; +#define QLA84_MGMT_READ_MEM     0x00 +#define QLA84_MGMT_WRITE_MEM    0x01 +#define QLA84_MGMT_CHNG_CONFIG  0x02 +#define QLA84_MGMT_GET_INFO     0x03 +	uint16_t rsrvd; +	struct qla84_mgmt_param mgmtp;/* parameters for cmd */ +	uint32_t len; /* bytes in payload following this struct */ +	uint8_t payload[0]; /* payload for cmd */ +}; + +struct qla_bsg_a84_mgmt { +	struct qla84_msg_mgmt mgmt; +} __attribute__ ((packed)); + +struct qla_scsi_addr { +	uint16_t bus; +	uint16_t target; +} __attribute__ ((packed)); + +struct qla_ext_dest_addr { +	union { +		uint8_t wwnn[8]; +		uint8_t wwpn[8]; +		uint8_t id[4]; +		struct qla_scsi_addr scsi_addr; +	} dest_addr; +	uint16_t dest_type; +#define	EXT_DEF_TYPE_WWPN	2 +	uint16_t lun; +	uint16_t padding[2]; +} __attribute__ ((packed)); + +struct qla_port_param { +	struct qla_ext_dest_addr fc_scsi_addr; +	uint16_t mode; +	uint16_t speed; +} __attribute__ ((packed)); +#endif diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index cb2eca4c26d..2afc8a362f2 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -769,6 +769,9 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)  	void		*nxt;  	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); +	if (IS_QLA82XX(ha)) +		return; +  	risc_address = ext_mem_cnt = 0;  	flags = 0; @@ -1660,4 +1663,62 @@ qla2x00_dump_buffer(uint8_t * b, uint32_t size)  		printk("\n");  } +void +qla2x00_dump_buffer_zipped(uint8_t *b, uint32_t size) +{ +	uint32_t cnt; +	uint8_t c; +	uint8_t  last16[16], cur16[16]; +	uint32_t lc = 0, num_same16 = 0, j; + +	printk(KERN_DEBUG " 0   1   2   3   4   5   6   7   8   9  " +	    "Ah  Bh  Ch  Dh  Eh  Fh\n"); +	printk(KERN_DEBUG "----------------------------------------" +	    "----------------------\n"); + +	for (cnt = 0; cnt < size;) { +		c = *b++; + +		cur16[lc++] = c; +		cnt++; +		if (cnt % 16) +			continue; + +		/* We have 16 now */ +		lc = 0; +		if (num_same16 == 0) { +			memcpy(last16, cur16, 16); +			num_same16++; +			continue; +		} +		if (memcmp(cur16, last16, 16) == 0) { +			num_same16++; +			continue; +		} +		for (j = 0; j < 16; j++) +			printk(KERN_DEBUG "%02x  ", (uint32_t)last16[j]); +		printk(KERN_DEBUG "\n"); + +		if (num_same16 > 1) +			printk(KERN_DEBUG "> prev pattern repeats (%u)" +			    "more times\n", num_same16-1); +		memcpy(last16, cur16, 16); +		num_same16 = 1; +	} + +	if (num_same16) { +		for (j = 0; j < 16; j++) +			printk(KERN_DEBUG "%02x  ", (uint32_t)last16[j]); +		printk(KERN_DEBUG "\n"); + +		if (num_same16 > 1) +			printk(KERN_DEBUG "> prev pattern repeats (%u)" +			    "more times\n", num_same16-1); +	} +	if (lc) { +		for (j = 0; j < lc; j++) +			printk(KERN_DEBUG "%02x  ", (uint32_t)cur16[j]); +		printk(KERN_DEBUG "\n"); +	} +} diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index d6d9c86cb05..916c81f3f55 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -27,6 +27,9 @@  /* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */  /* #define QL_DEBUG_LEVEL_16 */ /* Output ISP84XX trace msgs */  /* #define QL_DEBUG_LEVEL_17 */ /* Output EEH trace messages */ +/* #define QL_DEBUG_LEVEL_18 */ /* Output T10 CRC trace messages */ + +/* #define QL_PRINTK_BUF */ /* Captures printk to buffer */  /*  * Macros use for debugging the driver. @@ -139,6 +142,13 @@  #define DEBUG17(x)	do {} while (0)  #endif +#if defined(QL_DEBUG_LEVEL_18) +#define DEBUG18(x)	do {if (ql2xextended_error_logging) x; } while (0) +#else +#define DEBUG18(x)	do {} while (0) +#endif + +  /*   * Firmware Dump structure definition   */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index afa95614aaf..83961090901 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -33,7 +33,10 @@  #include <scsi/scsi_transport_fc.h>  #include <scsi/scsi_bsg_fc.h> -#define QLA2XXX_DRIVER_NAME  "qla2xxx" +#include "qla_bsg.h" +#include "qla_nx.h" +#define QLA2XXX_DRIVER_NAME	"qla2xxx" +#define QLA2XXX_APIDEV		"ql2xapidev"  /*   * We have MAILBOX_REGISTER_COUNT sized arrays in a few places, @@ -186,6 +189,16 @@  struct req_que;  /* + * (sd.h is not exported, hence local inclusion) + * Data Integrity Field tuple. + */ +struct sd_dif_tuple { +	__be16 guard_tag;	/* Checksum */ +	__be16 app_tag;		/* Opaque storage */ +	__be32 ref_tag;		/* Target LBA or indirect LBA */ +}; + +/*   * SCSI Request Block   */  typedef struct srb { @@ -205,40 +218,73 @@ typedef struct srb {  /*   * SRB flag definitions   */ -#define SRB_DMA_VALID		BIT_0	/* Command sent to ISP */ +#define SRB_DMA_VALID			BIT_0	/* Command sent to ISP */ +#define SRB_FCP_CMND_DMA_VALID		BIT_12	/* DIF: DSD List valid */ +#define SRB_CRC_CTX_DMA_VALID		BIT_2	/* DIF: context DMA valid */ +#define SRB_CRC_PROT_DMA_VALID		BIT_4	/* DIF: prot DMA valid */ +#define SRB_CRC_CTX_DSD_VALID		BIT_5	/* DIF: dsd_list valid */ + +/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */ +#define IS_PROT_IO(sp)	(sp->flags & SRB_CRC_CTX_DSD_VALID)  /*   * SRB extensions.   */ -struct srb_ctx { -#define SRB_LOGIN_CMD	1 -#define SRB_LOGOUT_CMD	2 -	uint16_t type; -	struct timer_list timer; - -	void (*free)(srb_t *sp); -	void (*timeout)(srb_t *sp); -}; - -struct srb_logio { -	struct srb_ctx ctx; - +struct srb_iocb { +	union { +		struct { +			uint16_t flags;  #define SRB_LOGIN_RETRIED	BIT_0  #define SRB_LOGIN_COND_PLOGI	BIT_1  #define SRB_LOGIN_SKIP_PRLI	BIT_2 -	uint16_t flags; +			uint16_t data[2]; +		} logio; +		struct { +			/* +			 * Values for flags field below are as +			 * defined in tsk_mgmt_entry struct +			 * for control_flags field in qla_fw.h. +			 */ +			uint32_t flags; +			uint32_t lun; +			uint32_t data; +		} tmf; +		struct { +			/* +			 * values for modif field below are as +			 * defined in mrk_entry_24xx struct +			 * for the modifier field in qla_fw.h. +			 */ +			uint8_t modif; +			uint16_t lun; +			uint32_t data; +		} marker; +	} u; + +	struct timer_list timer; + +	void (*done)(srb_t *); +	void (*free)(srb_t *); +	void (*timeout)(srb_t *);  }; -struct srb_bsg_ctx { +/* Values for srb_ctx type */ +#define SRB_LOGIN_CMD	1 +#define SRB_LOGOUT_CMD	2  #define SRB_ELS_CMD_RPT 3  #define SRB_ELS_CMD_HST 4 -#define SRB_CT_CMD 5 -	uint16_t type; -}; +#define SRB_CT_CMD	5 +#define SRB_ADISC_CMD	6 +#define SRB_TM_CMD	7 +#define SRB_MARKER_CMD	8 -struct srb_bsg { -	struct srb_bsg_ctx ctx; -	struct fc_bsg_job *bsg_job; +struct srb_ctx { +	uint16_t type; +	char *name; +	union { +		struct srb_iocb *iocb_cmd; +		struct fc_bsg_job *bsg_job; +	} u;  };  struct msg_echo_lb { @@ -416,6 +462,7 @@ typedef union {  		struct device_reg_2xxx isp;  		struct device_reg_24xx isp24;  		struct device_reg_25xxmq isp25mq; +		struct device_reg_82xx isp82;  } device_reg_t;  #define ISP_REQ_Q_IN(ha, reg) \ @@ -1299,6 +1346,66 @@ typedef struct {  	uint32_t dseg_4_length;		/* Data segment 4 length. */  } cont_a64_entry_t; +#define PO_MODE_DIF_INSERT	0 +#define PO_MODE_DIF_REMOVE	BIT_0 +#define PO_MODE_DIF_PASS	BIT_1 +#define PO_MODE_DIF_REPLACE	(BIT_0 + BIT_1) +#define PO_ENABLE_DIF_BUNDLING	BIT_8 +#define PO_ENABLE_INCR_GUARD_SEED	BIT_3 +#define PO_DISABLE_INCR_REF_TAG	BIT_5 +#define PO_DISABLE_GUARD_CHECK	BIT_4 +/* + * ISP queue - 64-Bit addressing, continuation crc entry structure definition. + */ +struct crc_context { +	uint32_t handle;		/* System handle. */ +	uint32_t ref_tag; +	uint16_t app_tag; +	uint8_t ref_tag_mask[4];	/* Validation/Replacement Mask*/ +	uint8_t app_tag_mask[2];	/* Validation/Replacement Mask*/ +	uint16_t guard_seed;		/* Initial Guard Seed */ +	uint16_t prot_opts;		/* Requested Data Protection Mode */ +	uint16_t blk_size;		/* Data size in bytes */ +	uint16_t runt_blk_guard;	/* Guard value for runt block (tape +					 * only) */ +	uint32_t byte_count;		/* Total byte count/ total data +					 * transfer count */ +	union { +		struct { +			uint32_t	reserved_1; +			uint16_t	reserved_2; +			uint16_t	reserved_3; +			uint32_t	reserved_4; +			uint32_t	data_address[2]; +			uint32_t	data_length; +			uint32_t	reserved_5[2]; +			uint32_t	reserved_6; +		} nobundling; +		struct { +			uint32_t	dif_byte_count;	/* Total DIF byte +							 * count */ +			uint16_t	reserved_1; +			uint16_t	dseg_count;	/* Data segment count */ +			uint32_t	reserved_2; +			uint32_t	data_address[2]; +			uint32_t	data_length; +			uint32_t	dif_address[2]; +			uint32_t	dif_length;	/* Data segment 0 +							 * length */ +		} bundling; +	} u; + +	struct fcp_cmnd	fcp_cmnd; +	dma_addr_t	crc_ctx_dma; +	/* List of DMA context transfers */ +	struct list_head dsd_list; + +	/* This structure should not exceed 512 bytes */ +}; + +#define CRC_CONTEXT_LEN_FW	(offsetof(struct crc_context, fcp_cmnd.lun)) +#define CRC_CONTEXT_FCPCMND_OFF	(offsetof(struct crc_context, fcp_cmnd.lun)) +  /*   * ISP queue - status entry structure definition.   */ @@ -1359,6 +1466,7 @@ typedef struct {  #define CS_ABORTED		0x5	/* System aborted command. */  #define CS_TIMEOUT		0x6	/* Timeout error. */  #define CS_DATA_OVERRUN		0x7	/* Data overrun. */ +#define CS_DIF_ERROR		0xC	/* DIF error detected  */  #define CS_DATA_UNDERRUN	0x15	/* Data Underrun. */  #define CS_QUEUE_FULL		0x1C	/* Queue Full. */ @@ -1579,6 +1687,8 @@ typedef struct fc_port {  	uint16_t loop_id;  	uint16_t old_loop_id; +	uint8_t fcp_prio; +  	uint8_t fabric_port_name[WWN_SIZE];  	uint16_t fp_speed; @@ -1611,6 +1721,7 @@ typedef struct fc_port {  #define FCF_FABRIC_DEVICE	BIT_0  #define FCF_LOGIN_NEEDED	BIT_1  #define FCF_FCP2_DEVICE		BIT_2 +#define FCF_ASYNC_SENT		BIT_3  /* No loop ID flag. */  #define FC_NO_LOOP_ID		0x1000 @@ -2109,6 +2220,7 @@ struct isp_operations {  	int (*get_flash_version) (struct scsi_qla_host *, void *);  	int (*start_scsi) (srb_t *); +	int (*abort_isp) (struct scsi_qla_host *);  };  /* MSI-X Support *************************************************************/ @@ -2143,6 +2255,8 @@ enum qla_work_type {  	QLA_EVT_ASYNC_LOGIN_DONE,  	QLA_EVT_ASYNC_LOGOUT,  	QLA_EVT_ASYNC_LOGOUT_DONE, +	QLA_EVT_ASYNC_ADISC, +	QLA_EVT_ASYNC_ADISC_DONE,  	QLA_EVT_UEVENT,  }; @@ -2295,6 +2409,7 @@ struct qla_hw_data {  		uint32_t	eeh_busy		:1;  		uint32_t	cpu_affinity_enabled	:1;  		uint32_t	disable_msix_handshake	:1; +		uint32_t	fcp_prio_enabled	:1;  	} flags;  	/* This spinlock is used to protect "io transactions", you must @@ -2382,7 +2497,8 @@ struct qla_hw_data {  #define DT_ISP2532                      BIT_11  #define DT_ISP8432                      BIT_12  #define DT_ISP8001			BIT_13 -#define DT_ISP_LAST			(DT_ISP8001 << 1) +#define DT_ISP8021			BIT_14 +#define DT_ISP_LAST			(DT_ISP8021 << 1)  #define DT_IIDMA                        BIT_26  #define DT_FWI2                         BIT_27 @@ -2405,6 +2521,7 @@ struct qla_hw_data {  #define IS_QLA2532(ha)  (DT_MASK(ha) & DT_ISP2532)  #define IS_QLA8432(ha)  (DT_MASK(ha) & DT_ISP8432)  #define IS_QLA8001(ha)	(DT_MASK(ha) & DT_ISP8001) +#define IS_QLA82XX(ha)	(DT_MASK(ha) & DT_ISP8021)  #define IS_QLA23XX(ha)  (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \  			IS_QLA6312(ha) || IS_QLA6322(ha)) @@ -2415,8 +2532,10 @@ struct qla_hw_data {  #define IS_QLA24XX_TYPE(ha)     (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \  				IS_QLA84XX(ha))  #define IS_QLA81XX(ha)		(IS_QLA8001(ha)) +#define IS_QLA8XXX_TYPE(ha)	(IS_QLA81XX(ha) || IS_QLA82XX(ha))  #define IS_QLA2XXX_MIDTYPE(ha)	(IS_QLA24XX(ha) || IS_QLA84XX(ha) || \ -				IS_QLA25XX(ha) || IS_QLA81XX(ha)) +				IS_QLA25XX(ha) || IS_QLA81XX(ha) || \ +				IS_QLA82XX(ha))  #define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha))  #define IS_NOPOLLING_TYPE(ha)	((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \  				(ha)->flags.msix_enabled) @@ -2496,6 +2615,9 @@ struct qla_hw_data {  	dma_addr_t	ex_init_cb_dma;  	struct ex_init_cb_81xx *ex_init_cb; +	void		*async_pd; +	dma_addr_t	async_pd_dma; +  	/* These are used by mailbox operations. */  	volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; @@ -2598,6 +2720,8 @@ struct qla_hw_data {  	uint32_t        flt_region_nvram;  	uint32_t        flt_region_npiv_conf;  	uint32_t	flt_region_gold_fw; +	uint32_t	flt_region_fcp_prio; +	uint32_t	flt_region_bootload;  	/* Needed for BEACON */  	uint16_t        beacon_blink_led; @@ -2626,6 +2750,39 @@ struct qla_hw_data {  	struct isp_operations *isp_ops;  	struct workqueue_struct *wq;  	struct qlfc_fw fw_buf; + +	/* FCP_CMND priority support */ +	struct qla_fcp_prio_cfg *fcp_prio_cfg; + +	struct dma_pool *dl_dma_pool; +#define DSD_LIST_DMA_POOL_SIZE  512 + +	struct dma_pool *fcp_cmnd_dma_pool; +	mempool_t       *ctx_mempool; +#define FCP_CMND_DMA_POOL_SIZE 512 + +	unsigned long	nx_pcibase;		/* Base I/O address */ +	uint8_t		*nxdb_rd_ptr;		/* Doorbell read pointer */ +	unsigned long	nxdb_wr_ptr;		/* Door bell write pointer */ + +	uint32_t	crb_win; +	uint32_t	curr_window; +	uint32_t	ddr_mn_window; +	unsigned long	mn_win_crb; +	unsigned long	ms_win_crb; +	int		qdr_sn_window; +	uint32_t	nx_dev_init_timeout; +	uint32_t	nx_reset_timeout; +	rwlock_t	hw_lock; +	uint16_t	portnum;		/* port number */ +	int		link_width; +	struct fw_blob	*hablob; +	struct qla82xx_legacy_intr_set nx_legacy_intr; + +	uint16_t	gbl_dsd_inuse; +	uint16_t	gbl_dsd_avail; +	struct list_head gbl_dsd_list; +#define NUM_DSD_CHAIN 4096  };  /* @@ -2650,6 +2807,7 @@ typedef struct scsi_qla_host {  		uint32_t	management_server_logged_in :1;  		uint32_t	process_response_queue	:1; +		uint32_t	difdix_supported:1;  	} flags;  	atomic_t	loop_state; @@ -2678,10 +2836,13 @@ typedef struct scsi_qla_host {  #define VP_DPC_NEEDED		14	/* wake up for VP dpc handling */  #define UNLOADING		15  #define NPIV_CONFIG_NEEDED	16 +#define ISP_UNRECOVERABLE	17 +#define FCOE_CTX_RESET_NEEDED	18	/* Initiate FCoE context reset */  	uint32_t	device_flags;  #define SWITCH_FOUND		BIT_0  #define DFLG_NO_CABLE		BIT_1 +#define DFLG_DEV_FAILED		BIT_5  	/* ISP configuration data. */  	uint16_t	loop_id;		/* Host adapter loop id */ @@ -2739,6 +2900,8 @@ typedef struct scsi_qla_host {  #define VP_ERR_ADAP_NORESOURCES	5  	struct qla_hw_data *hw;  	struct req_que *req; +	int		fw_heartbeat_counter; +	int		seconds_since_last_heartbeat;  } scsi_qla_host_t;  /* @@ -2791,134 +2954,16 @@ typedef struct scsi_qla_host {  #define OPTROM_SIZE_24XX	0x100000  #define OPTROM_SIZE_25XX	0x200000  #define OPTROM_SIZE_81XX	0x400000 +#define OPTROM_SIZE_82XX	0x800000 + +#define OPTROM_BURST_SIZE	0x1000 +#define OPTROM_BURST_DWORDS	(OPTROM_BURST_SIZE / 4) + +#define	QLA_DSDS_PER_IOCB	37  #include "qla_gbl.h"  #include "qla_dbg.h"  #include "qla_inline.h"  #define CMD_SP(Cmnd)		((Cmnd)->SCp.ptr) - -/* - * BSG Vendor specific commands - */ - -#define QL_VND_LOOPBACK		0x01 -#define QLA84_RESET		0x02 -#define QLA84_UPDATE_FW		0x03 -#define QLA84_MGMT_CMD		0x04 - -/* BSG definations for interpreting CommandSent field */ -#define INT_DEF_LB_LOOPBACK_CMD         0 -#define INT_DEF_LB_ECHO_CMD             1 - -/* BSG Vendor specific definations */ -typedef struct _A84_RESET { -	uint16_t Flags; -	uint16_t Reserved; -#define A84_RESET_FLAG_ENABLE_DIAG_FW   1 -} __attribute__((packed)) A84_RESET, *PA84_RESET; - -#define A84_ISSUE_WRITE_TYPE_CMD        0 -#define A84_ISSUE_READ_TYPE_CMD         1 -#define A84_CLEANUP_CMD                 2 -#define A84_ISSUE_RESET_OP_FW           3 -#define A84_ISSUE_RESET_DIAG_FW         4 -#define A84_ISSUE_UPDATE_OPFW_CMD       5 -#define A84_ISSUE_UPDATE_DIAGFW_CMD     6 - -struct qla84_mgmt_param { -	union { -		struct { -			uint32_t start_addr; -		} mem; /* for QLA84_MGMT_READ/WRITE_MEM */ -		struct { -			uint32_t id; -#define QLA84_MGMT_CONFIG_ID_UIF        1 -#define QLA84_MGMT_CONFIG_ID_FCOE_COS   2 -#define QLA84_MGMT_CONFIG_ID_PAUSE      3 -#define QLA84_MGMT_CONFIG_ID_TIMEOUTS   4 - -		uint32_t param0; -		uint32_t param1; -	} config; /* for QLA84_MGMT_CHNG_CONFIG */ - -	struct { -		uint32_t type; -#define QLA84_MGMT_INFO_CONFIG_LOG_DATA         1 /* Get Config Log Data */ -#define QLA84_MGMT_INFO_LOG_DATA                2 /* Get Log Data */ -#define QLA84_MGMT_INFO_PORT_STAT               3 /* Get Port Statistics */ -#define QLA84_MGMT_INFO_LIF_STAT                4 /* Get LIF Statistics  */ -#define QLA84_MGMT_INFO_ASIC_STAT               5 /* Get ASIC Statistics */ -#define QLA84_MGMT_INFO_CONFIG_PARAMS           6 /* Get Config Parameters */ -#define QLA84_MGMT_INFO_PANIC_LOG               7 /* Get Panic Log */ - -		uint32_t context; -/* -* context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA -*/ -#define IC_LOG_DATA_LOG_ID_DEBUG_LOG                    0 -#define IC_LOG_DATA_LOG_ID_LEARN_LOG                    1 -#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG           2 -#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG            3 -#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG     4 -#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG      5 -#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG         6 -#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG          7 -#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG               8 -#define IC_LOG_DATA_LOG_ID_DCX_LOG                      9 - -/* -* context definitions for QLA84_MGMT_INFO_PORT_STAT -*/ -#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0   0 -#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1   1 -#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0        2 -#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1        3 -#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0         4 -#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1         5 - - -/* -* context definitions for QLA84_MGMT_INFO_LIF_STAT -*/ -#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0     0 -#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1     1 -#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0           2 -#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1           3 -#define IC_LIF_STATISTICS_LIF_NUMBER_CPU                6 - -		} info; /* for QLA84_MGMT_GET_INFO */ -	} u; -}; - -struct qla84_msg_mgmt { -	uint16_t cmd; -#define QLA84_MGMT_READ_MEM     0x00 -#define QLA84_MGMT_WRITE_MEM    0x01 -#define QLA84_MGMT_CHNG_CONFIG  0x02 -#define QLA84_MGMT_GET_INFO     0x03 -	uint16_t rsrvd; -	struct qla84_mgmt_param mgmtp;/* parameters for cmd */ -	uint32_t len; /* bytes in payload following this struct */ -	uint8_t payload[0]; /* payload for cmd */ -}; - -struct msg_update_fw { -	/* -	* diag_fw = 0  operational fw -	*      otherwise diagnostic fw -	* offset, len, fw_len are present to overcome the current limitation -	* of 128Kb xfer size. The fw is sent in smaller chunks. Each chunk -	* specifies the byte "offset" where it fits in the fw buffer. The -	* number of bytes in each chunk is specified in "len". "fw_len" -	* is the total size of fw. The first chunk should start at offset = 0. -	* When offset+len == fw_len, the fw is written to the HBA. -	*/ -	uint32_t diag_fw; -	uint32_t offset;/* start offset */ -	uint32_t len;   /* num bytes in cur xfer */ -	uint32_t fw_len; /* size of fw in bytes */ -	uint8_t fw_bytes[0]; -}; -  #endif diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 42c5587cc50..93f83396014 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -400,6 +400,7 @@ struct cmd_type_6 {  	struct scsi_lun lun;		/* FCP LUN (BE). */  	uint16_t control_flags;		/* Control flags. */ +#define CF_DIF_SEG_DESCR_ENABLE		BIT_3  #define CF_DATA_SEG_DESCR_ENABLE	BIT_2  #define CF_READ_DATA			BIT_1  #define CF_WRITE_DATA			BIT_0 @@ -466,6 +467,43 @@ struct cmd_type_7 {  	uint32_t dseg_0_len;		/* Data segment 0 length. */  }; +#define COMMAND_TYPE_CRC_2	0x6A	/* Command Type CRC_2 (Type 6) +					 * (T10-DIF) */ +struct cmd_type_crc_2 { +	uint8_t entry_type;		/* Entry type. */ +	uint8_t entry_count;		/* Entry count. */ +	uint8_t sys_define;		/* System defined. */ +	uint8_t entry_status;		/* Entry Status. */ + +	uint32_t handle;		/* System handle. */ + +	uint16_t nport_handle;		/* N_PORT handle. */ +	uint16_t timeout;		/* Command timeout. */ + +	uint16_t dseg_count;		/* Data segment count. */ + +	uint16_t fcp_rsp_dseg_len;	/* FCP_RSP DSD length. */ + +	struct scsi_lun lun;		/* FCP LUN (BE). */ + +	uint16_t control_flags;		/* Control flags. */ + +	uint16_t fcp_cmnd_dseg_len;		/* Data segment length. */ +	uint32_t fcp_cmnd_dseg_address[2];	/* Data segment address. */ + +	uint32_t fcp_rsp_dseg_address[2];	/* Data segment address. */ + +	uint32_t byte_count;		/* Total byte count. */ + +	uint8_t port_id[3];		/* PortID of destination port. */ +	uint8_t vp_index; + +	uint32_t crc_context_address[2];	/* Data segment address. */ +	uint16_t crc_context_len;		/* Data segment length. */ +	uint16_t reserved_1;			/* MUST be set to 0. */ +}; + +  /*   * ISP queue - status entry structure definition.   */ @@ -496,10 +534,17 @@ struct sts_entry_24xx {  	uint32_t sense_len;		/* FCP SENSE length. */  	uint32_t rsp_data_len;		/* FCP response data length. */ -  	uint8_t data[28];		/* FCP response/sense information. */ +	/* +	 * If DIF Error is set in comp_status, these additional fields are +	 * defined: +	 * &data[10] : uint8_t report_runt_bg[2];	- computed guard +	 * &data[12] : uint8_t actual_dif[8];		- DIF Data recieved +	 * &data[20] : uint8_t expected_dif[8];		- DIF Data computed +	*/  }; +  /*   * Status entry completion status   */ @@ -841,6 +886,8 @@ struct device_reg_24xx {  #define FA_HW_EVENT_ENTRY_SIZE	4  #define FA_NPIV_CONF0_ADDR	0x5C000  #define FA_NPIV_CONF1_ADDR	0x5D000 +#define FA_FCP_PRIO0_ADDR	0x10000 +#define FA_FCP_PRIO1_ADDR	0x12000  /*   * Flash Error Log Event Codes. @@ -1274,6 +1321,8 @@ struct qla_flt_header {  #define FLT_REG_NPIV_CONF_0	0x29  #define FLT_REG_NPIV_CONF_1	0x2a  #define FLT_REG_GOLD_FW		0x2f +#define FLT_REG_FCP_PRIO_0	0x87 +#define FLT_REG_FCP_PRIO_1	0x88  struct qla_flt_region {  	uint32_t code; @@ -1750,6 +1799,61 @@ struct ex_init_cb_81xx {  #define FARX_ACCESS_FLASH_CONF_81XX	0x7FFD0000  #define FARX_ACCESS_FLASH_DATA_81XX	0x7F800000 +/* FCP priority config defines *************************************/ +/* operations */ +#define QLFC_FCP_PRIO_DISABLE           0x0 +#define QLFC_FCP_PRIO_ENABLE            0x1 +#define QLFC_FCP_PRIO_GET_CONFIG        0x2 +#define QLFC_FCP_PRIO_SET_CONFIG        0x3 + +struct qla_fcp_prio_entry { +	uint16_t flags;         /* Describes parameter(s) in FCP        */ +	/* priority entry that are valid        */ +#define FCP_PRIO_ENTRY_VALID            0x1 +#define FCP_PRIO_ENTRY_TAG_VALID        0x2 +#define FCP_PRIO_ENTRY_SPID_VALID       0x4 +#define FCP_PRIO_ENTRY_DPID_VALID       0x8 +#define FCP_PRIO_ENTRY_LUNB_VALID       0x10 +#define FCP_PRIO_ENTRY_LUNE_VALID       0x20 +#define FCP_PRIO_ENTRY_SWWN_VALID       0x40 +#define FCP_PRIO_ENTRY_DWWN_VALID       0x80 +	uint8_t  tag;           /* Priority value                   */ +	uint8_t  reserved;      /* Reserved for future use          */ +	uint32_t src_pid;       /* Src port id. high order byte     */ +				/* unused; -1 (wild card)           */ +	uint32_t dst_pid;       /* Src port id. high order byte     */ +	/* unused; -1 (wild card)           */ +	uint16_t lun_beg;       /* 1st lun num of lun range.        */ +				/* -1 (wild card)                   */ +	uint16_t lun_end;       /* 2nd lun num of lun range.        */ +				/* -1 (wild card)                   */ +	uint8_t  src_wwpn[8];   /* Source WWPN: -1 (wild card)      */ +	uint8_t  dst_wwpn[8];   /* Destination WWPN: -1 (wild card) */ +}; + +struct qla_fcp_prio_cfg { +	uint8_t  signature[4];  /* "HQOS" signature of config data  */ +	uint16_t version;       /* 1: Initial version               */ +	uint16_t length;        /* config data size in num bytes    */ +	uint16_t checksum;      /* config data bytes checksum       */ +	uint16_t num_entries;   /* Number of entries                */ +	uint16_t size_of_entry; /* Size of each entry in num bytes  */ +	uint8_t  attributes;    /* enable/disable, persistence      */ +#define FCP_PRIO_ATTR_DISABLE   0x0 +#define FCP_PRIO_ATTR_ENABLE    0x1 +#define FCP_PRIO_ATTR_PERSIST   0x2 +	uint8_t  reserved;      /* Reserved for future use          */ +#define FCP_PRIO_CFG_HDR_SIZE   0x10 +	struct qla_fcp_prio_entry entry[1];     /* fcp priority entries  */ +#define FCP_PRIO_CFG_ENTRY_SIZE 0x20 +}; + +#define FCP_PRIO_CFG_SIZE       (32*1024) /* fcp prio data per port*/ + +/* 25XX Support ****************************************************/ +#define FA_FCP_PRIO0_ADDR_25	0x3C000 +#define FA_FCP_PRIO1_ADDR_25	0x3E000 +  /* 81XX Flash locations -- occupies second 2MB region. */  #define FA_BOOT_CODE_ADDR_81	0x80000  #define FA_RISC_CODE_ADDR_81	0xA0000 diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 3a89bc514e2..8217c3bcbc2 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -44,6 +44,7 @@ extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);  extern void qla2x00_update_fcports(scsi_qla_host_t *);  extern int qla2x00_abort_isp(scsi_qla_host_t *); +extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *);  extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); @@ -55,10 +56,20 @@ extern void qla84xx_put_chip(struct scsi_qla_host *);  extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *,      uint16_t *);  extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *); -extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, +extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,      uint16_t *); -extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, +extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t); +extern int qla2x00_async_marker(fc_port_t *, uint16_t, uint8_t); +extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,      uint16_t *); +extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, +    uint16_t *); +extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *, +    uint16_t *); +extern void qla2x00_async_tm_cmd_done(struct scsi_qla_host *, fc_port_t *, +	struct srb_iocb *); +extern void qla2x00_async_marker_done(struct scsi_qla_host *, fc_port_t *, +	struct srb_iocb *);  extern fc_port_t *  qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t ); @@ -79,6 +90,13 @@ extern int ql2xmaxqueues;  extern int ql2xmultique_tag;  extern int ql2xfwloadbin;  extern int ql2xetsenable; +extern int ql2xshiftctondsd; +extern int ql2xdbwr; +extern int ql2xdontresethba; +extern int ql2xasynctmfenable; +extern int ql2xenabledif; +extern int ql2xenablehba_err_chk; +extern int ql2xtargetreset;  extern int qla2x00_loop_reset(scsi_qla_host_t *);  extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); @@ -93,6 +111,10 @@ extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *,      uint16_t *);  extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *,      fc_port_t *, uint16_t *); +extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *, +    uint16_t *); +extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *, +    fc_port_t *, uint16_t *);  extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);  extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *); @@ -135,6 +157,7 @@ extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);  extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);  extern int qla2x00_wait_for_chip_reset(scsi_qla_host_t *); +extern int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *);  extern void qla2xxx_wake_dpc(struct scsi_qla_host *);  extern void qla2x00_alert_all_vps(struct rsp_que *, uint16_t *); @@ -157,6 +180,10 @@ int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,  						uint16_t, uint16_t, uint8_t);  extern int qla2x00_start_sp(srb_t *);  extern void qla2x00_ctx_sp_free(srb_t *); +extern uint16_t qla24xx_calc_iocbs(uint16_t); +extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t); +extern int qla24xx_dif_start_scsi(srb_t *); +  /*   * Global Function Prototypes in qla_mbx.c source file. @@ -328,6 +355,9 @@ extern int  qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t);  extern int qla2x00_get_data_rate(scsi_qla_host_t *); +extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t, +	uint16_t *); +  /*   * Global Function Prototypes in qla_isr.c source file.   */ @@ -340,6 +370,7 @@ qla24xx_process_response_queue(struct scsi_qla_host *, struct rsp_que *);  extern int qla2x00_request_irqs(struct qla_hw_data *, struct rsp_que *);  extern void qla2x00_free_irqs(scsi_qla_host_t *); +extern int qla2x00_get_data_rate(scsi_qla_host_t *);  /*   * Global Function Prototypes in qla_sup.c source file.   */ @@ -384,6 +415,7 @@ extern int qla2xxx_get_flash_info(scsi_qla_host_t *);  extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);  extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *); +extern int qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *);  /*   * Global Function Prototypes in qla_dbg.c source file. @@ -395,6 +427,7 @@ extern void qla25xx_fw_dump(scsi_qla_host_t *, int);  extern void qla81xx_fw_dump(scsi_qla_host_t *, int);  extern void qla2x00_dump_regs(scsi_qla_host_t *);  extern void qla2x00_dump_buffer(uint8_t *, uint32_t); +extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);  /*   * Global Function Prototypes in qla_gs.c source file. @@ -430,7 +463,10 @@ extern void qla2x00_init_host_attr(scsi_qla_host_t *);  extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);  extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);  extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *); -extern int qla2x00_echo_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *); +extern int qla2x00_echo_test(scsi_qla_host_t *, +	struct msg_echo_lb *, uint16_t *); +extern int qla24xx_update_all_fcp_prio(scsi_qla_host_t *); +extern int qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *, uint8_t);  /*   * Global Function Prototypes in qla_dfs.c source file. @@ -459,4 +495,88 @@ extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);  extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);  extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); +/* qla82xx related functions */ + +/* PCI related functions */ +extern int qla82xx_pci_config(struct scsi_qla_host *); +extern int qla82xx_pci_mem_read_2M(struct qla_hw_data *, u64, void *, int); +extern int qla82xx_pci_mem_write_2M(struct qla_hw_data *, u64, void *, int); +extern char *qla82xx_pci_info_str(struct scsi_qla_host *, char *); +extern int qla82xx_pci_region_offset(struct pci_dev *, int); +extern int qla82xx_pci_region_len(struct pci_dev *, int); +extern int qla82xx_iospace_config(struct qla_hw_data *); + +/* Initialization related functions */ +extern void qla82xx_reset_chip(struct scsi_qla_host *); +extern void qla82xx_config_rings(struct scsi_qla_host *); +extern int qla82xx_nvram_config(struct scsi_qla_host *); +extern int qla82xx_pinit_from_rom(scsi_qla_host_t *); +extern int qla82xx_load_firmware(scsi_qla_host_t *); +extern int qla82xx_reset_hw(scsi_qla_host_t *); +extern int qla82xx_load_risc_blob(scsi_qla_host_t *, uint32_t *); +extern void qla82xx_watchdog(scsi_qla_host_t *); + +/* Firmware and flash related functions */ +extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *); +extern uint8_t *qla82xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, +    uint32_t, uint32_t); +extern int qla82xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, +    uint32_t, uint32_t); + +/* Mailbox related functions */ +extern int qla82xx_abort_isp(scsi_qla_host_t *); +extern int qla82xx_restart_isp(scsi_qla_host_t *); + +/* IOCB related functions */ +extern int qla82xx_start_scsi(srb_t *); + +/* Interrupt related */ +extern irqreturn_t qla82xx_intr_handler(int, void *); +extern irqreturn_t qla82xx_msi_handler(int, void *); +extern irqreturn_t qla82xx_msix_default(int, void *); +extern irqreturn_t qla82xx_msix_rsp_q(int, void *); +extern void qla82xx_enable_intrs(struct qla_hw_data *); +extern void qla82xx_disable_intrs(struct qla_hw_data *); +extern void qla82xx_mbx_completion(scsi_qla_host_t *, uint16_t); +extern void qla82xx_poll(int, void *); +extern void qla82xx_init_flags(struct qla_hw_data *); + +/* ISP 8021 hardware related */ +extern int qla82xx_crb_win_lock(struct qla_hw_data *); +extern void qla82xx_crb_win_unlock(struct qla_hw_data *); +extern int qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *, ulong *); +extern int qla82xx_wr_32(struct qla_hw_data *, ulong, u32); +extern int qla82xx_rd_32(struct qla_hw_data *, ulong); +extern int qla82xx_rdmem(struct qla_hw_data *, u64, void *, int); +extern int qla82xx_wrmem(struct qla_hw_data *, u64, void *, int); +extern int qla82xx_check_for_bad_spd(struct qla_hw_data *); +extern int qla82xx_load_fw(scsi_qla_host_t *); +extern int qla82xx_rom_lock(struct qla_hw_data *); +extern void qla82xx_rom_unlock(struct qla_hw_data *); +extern int qla82xx_rom_fast_read(struct qla_hw_data *, int , int *); +extern int qla82xx_do_rom_fast_read(struct qla_hw_data *, int, int *); +extern unsigned long qla82xx_decode_crb_addr(unsigned long); + +/* ISP 8021 IDC */ +extern void qla82xx_clear_drv_active(struct qla_hw_data *); +extern int qla82xx_idc_lock(struct qla_hw_data *); +extern void qla82xx_idc_unlock(struct qla_hw_data *); +extern int qla82xx_device_state_handler(scsi_qla_host_t *); + +extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *, +    size_t, char *); +extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *); +extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *); +extern void qla82xx_start_iocbs(srb_t *); +extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *); +extern void qla82xx_wait_for_pending_commands(scsi_qla_host_t *); + +/* BSG related functions */ +extern int qla24xx_bsg_request(struct fc_bsg_job *); +extern int qla24xx_bsg_timeout(struct fc_bsg_job *); +extern int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t); +extern int qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, +	dma_addr_t, size_t, uint32_t); +extern int qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, +	uint16_t *, uint16_t *);  #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 4647015eba6..872c55f049a 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1535,7 +1535,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)  	eiter = (struct ct_fdmi_port_attr *) (entries + size);  	eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);  	eiter->len = __constant_cpu_to_be16(4 + 4); -	if (IS_QLA81XX(ha)) +	if (IS_QLA8XXX_TYPE(ha))  		eiter->a.sup_speed = __constant_cpu_to_be32(  		    FDMI_PORT_SPEED_10GB);  	else if (IS_QLA25XX(ha)) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 4229bb483c5..ab2cc71994c 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -48,6 +48,7 @@ qla2x00_ctx_sp_timeout(unsigned long __data)  {  	srb_t *sp = (srb_t *)__data;  	struct srb_ctx *ctx; +	struct srb_iocb *iocb;  	fc_port_t *fcport = sp->fcport;  	struct qla_hw_data *ha = fcport->vha->hw;  	struct req_que *req; @@ -57,17 +58,21 @@ qla2x00_ctx_sp_timeout(unsigned long __data)  	req = ha->req_q_map[0];  	req->outstanding_cmds[sp->handle] = NULL;  	ctx = sp->ctx; -	ctx->timeout(sp); +	iocb = ctx->u.iocb_cmd; +	iocb->timeout(sp);  	spin_unlock_irqrestore(&ha->hardware_lock, flags); -	ctx->free(sp); +	iocb->free(sp);  }  void  qla2x00_ctx_sp_free(srb_t *sp)  {  	struct srb_ctx *ctx = sp->ctx; +	struct srb_iocb *iocb = ctx->u.iocb_cmd; +	del_timer_sync(&iocb->timer); +	kfree(iocb);  	kfree(ctx);  	mempool_free(sp, sp->fcport->vha->hw->srb_mempool);  } @@ -79,6 +84,7 @@ qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,  	srb_t *sp;  	struct qla_hw_data *ha = vha->hw;  	struct srb_ctx *ctx; +	struct srb_iocb *iocb;  	sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);  	if (!sp) @@ -86,21 +92,30 @@ qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,  	ctx = kzalloc(size, GFP_KERNEL);  	if (!ctx) {  		mempool_free(sp, ha->srb_mempool); +		sp = NULL; +		goto done; +	} +	iocb = kzalloc(sizeof(struct srb_iocb), GFP_KERNEL); +	if (!iocb) { +		mempool_free(sp, ha->srb_mempool); +		sp = NULL; +		kfree(ctx);  		goto done;  	}  	memset(sp, 0, sizeof(*sp));  	sp->fcport = fcport;  	sp->ctx = ctx; -	ctx->free = qla2x00_ctx_sp_free; +	ctx->u.iocb_cmd = iocb; +	iocb->free = qla2x00_ctx_sp_free; -	init_timer(&ctx->timer); +	init_timer(&iocb->timer);  	if (!tmo)  		goto done; -	ctx->timer.expires = jiffies + tmo * HZ; -	ctx->timer.data = (unsigned long)sp; -	ctx->timer.function = qla2x00_ctx_sp_timeout; -	add_timer(&ctx->timer); +	iocb->timer.expires = jiffies + tmo * HZ; +	iocb->timer.data = (unsigned long)sp; +	iocb->timer.function = qla2x00_ctx_sp_timeout; +	add_timer(&iocb->timer);  done:  	return sp;  } @@ -110,41 +125,56 @@ done:  #define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)  static void -qla2x00_async_logio_timeout(srb_t *sp) +qla2x00_async_iocb_timeout(srb_t *sp)  {  	fc_port_t *fcport = sp->fcport; -	struct srb_logio *lio = sp->ctx; +	struct srb_ctx *ctx = sp->ctx;  	DEBUG2(printk(KERN_WARNING  	    "scsi(%ld:%x): Async-%s timeout.\n", -	    fcport->vha->host_no, sp->handle, -	    lio->ctx.type == SRB_LOGIN_CMD ? "login": "logout")); +	    fcport->vha->host_no, sp->handle, ctx->name)); -	if (lio->ctx.type == SRB_LOGIN_CMD) +	fcport->flags &= ~FCF_ASYNC_SENT; +	if (ctx->type == SRB_LOGIN_CMD)  		qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);  } +static void +qla2x00_async_login_ctx_done(srb_t *sp) +{ +	struct srb_ctx *ctx = sp->ctx; +	struct srb_iocb *lio = ctx->u.iocb_cmd; + +	qla2x00_post_async_login_done_work(sp->fcport->vha, sp->fcport, +		lio->u.logio.data); +	lio->free(sp); +} +  int  qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,      uint16_t *data)  {  	struct qla_hw_data *ha = vha->hw;  	srb_t *sp; -	struct srb_logio *lio; +	struct srb_ctx *ctx; +	struct srb_iocb *lio;  	int rval;  	rval = QLA_FUNCTION_FAILED; -	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio), +	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),  	    ELS_TMO_2_RATOV(ha) + 2);  	if (!sp)  		goto done; -	lio = sp->ctx; -	lio->ctx.type = SRB_LOGIN_CMD; -	lio->ctx.timeout = qla2x00_async_logio_timeout; -	lio->flags |= SRB_LOGIN_COND_PLOGI; +	ctx = sp->ctx; +	ctx->type = SRB_LOGIN_CMD; +	ctx->name = "login"; +	lio = ctx->u.iocb_cmd; +	lio->timeout = qla2x00_async_iocb_timeout; +	lio->done = qla2x00_async_login_ctx_done; +	lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;  	if (data[1] & QLA_LOGIO_LOGIN_RETRIED) -		lio->flags |= SRB_LOGIN_RETRIED; +		lio->u.logio.flags |= SRB_LOGIN_RETRIED;  	rval = qla2x00_start_sp(sp);  	if (rval != QLA_SUCCESS)  		goto done_free_sp; @@ -157,29 +187,43 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,  	return rval;  done_free_sp: -	del_timer_sync(&lio->ctx.timer); -	lio->ctx.free(sp); +	lio->free(sp);  done:  	return rval;  } +static void +qla2x00_async_logout_ctx_done(srb_t *sp) +{ +	struct srb_ctx *ctx = sp->ctx; +	struct srb_iocb *lio = ctx->u.iocb_cmd; + +	qla2x00_post_async_logout_done_work(sp->fcport->vha, sp->fcport, +	    lio->u.logio.data); +	lio->free(sp); +} +  int  qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)  {  	struct qla_hw_data *ha = vha->hw;  	srb_t *sp; -	struct srb_logio *lio; +	struct srb_ctx *ctx; +	struct srb_iocb *lio;  	int rval;  	rval = QLA_FUNCTION_FAILED; -	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio), +	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),  	    ELS_TMO_2_RATOV(ha) + 2);  	if (!sp)  		goto done; -	lio = sp->ctx; -	lio->ctx.type = SRB_LOGOUT_CMD; -	lio->ctx.timeout = qla2x00_async_logio_timeout; +	ctx = sp->ctx; +	ctx->type = SRB_LOGOUT_CMD; +	ctx->name = "logout"; +	lio = ctx->u.iocb_cmd; +	lio->timeout = qla2x00_async_iocb_timeout; +	lio->done = qla2x00_async_logout_ctx_done;  	rval = qla2x00_start_sp(sp);  	if (rval != QLA_SUCCESS)  		goto done_free_sp; @@ -191,30 +235,186 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)  	return rval;  done_free_sp: -	del_timer_sync(&lio->ctx.timer); -	lio->ctx.free(sp); +	lio->free(sp);  done:  	return rval;  } +static void +qla2x00_async_adisc_ctx_done(srb_t *sp) +{ +	struct srb_ctx *ctx = sp->ctx; +	struct srb_iocb *lio = ctx->u.iocb_cmd; + +	qla2x00_post_async_adisc_done_work(sp->fcport->vha, sp->fcport, +	    lio->u.logio.data); +	lio->free(sp); +} +  int +qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, +    uint16_t *data) +{ +	struct qla_hw_data *ha = vha->hw; +	srb_t *sp; +	struct srb_ctx *ctx; +	struct srb_iocb *lio; +	int rval; + +	rval = QLA_FUNCTION_FAILED; +	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), +	    ELS_TMO_2_RATOV(ha) + 2); +	if (!sp) +		goto done; + +	ctx = sp->ctx; +	ctx->type = SRB_ADISC_CMD; +	ctx->name = "adisc"; +	lio = ctx->u.iocb_cmd; +	lio->timeout = qla2x00_async_iocb_timeout; +	lio->done = qla2x00_async_adisc_ctx_done; +	if (data[1] & QLA_LOGIO_LOGIN_RETRIED) +		lio->u.logio.flags |= SRB_LOGIN_RETRIED; +	rval = qla2x00_start_sp(sp); +	if (rval != QLA_SUCCESS) +		goto done_free_sp; + +	DEBUG2(printk(KERN_DEBUG +	    "scsi(%ld:%x): Async-adisc - loop-id=%x portid=%02x%02x%02x.\n", +	    fcport->vha->host_no, sp->handle, fcport->loop_id, +	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa)); + +	return rval; + +done_free_sp: +	lio->free(sp); +done: +	return rval; +} + +static void +qla2x00_async_tm_cmd_ctx_done(srb_t *sp) +{ +	struct srb_ctx *ctx = sp->ctx; +	struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd; + +	qla2x00_async_tm_cmd_done(sp->fcport->vha, sp->fcport, iocb); +	iocb->free(sp); +} + +int +qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, +	uint32_t tag) +{ +	struct scsi_qla_host *vha = fcport->vha; +	struct qla_hw_data *ha = vha->hw; +	srb_t *sp; +	struct srb_ctx *ctx; +	struct srb_iocb *tcf; +	int rval; + +	rval = QLA_FUNCTION_FAILED; +	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), +	    ELS_TMO_2_RATOV(ha) + 2); +	if (!sp) +		goto done; + +	ctx = sp->ctx; +	ctx->type = SRB_TM_CMD; +	ctx->name = "tmf"; +	tcf = ctx->u.iocb_cmd; +	tcf->u.tmf.flags = flags; +	tcf->u.tmf.lun = lun; +	tcf->u.tmf.data = tag; +	tcf->timeout = qla2x00_async_iocb_timeout; +	tcf->done = qla2x00_async_tm_cmd_ctx_done; + +	rval = qla2x00_start_sp(sp); +	if (rval != QLA_SUCCESS) +		goto done_free_sp; + +	DEBUG2(printk(KERN_DEBUG +	    "scsi(%ld:%x): Async-tmf - loop-id=%x portid=%02x%02x%02x.\n", +	    fcport->vha->host_no, sp->handle, fcport->loop_id, +	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa)); + +	return rval; + +done_free_sp: +	tcf->free(sp); +done: +	return rval; +} + +static void +qla2x00_async_marker_ctx_done(srb_t *sp) +{ +	struct srb_ctx *ctx = sp->ctx; +	struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd; + +	qla2x00_async_marker_done(sp->fcport->vha, sp->fcport, iocb); +	iocb->free(sp); +} + +int +qla2x00_async_marker(fc_port_t *fcport, uint16_t lun, uint8_t modif) +{ +	struct scsi_qla_host *vha = fcport->vha; +	srb_t *sp; +	struct srb_ctx *ctx; +	struct srb_iocb *mrk; +	int rval; + +	rval = QLA_FUNCTION_FAILED; +	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), 0); +	if (!sp) +		goto done; + +	ctx = sp->ctx; +	ctx->type = SRB_MARKER_CMD; +	ctx->name = "marker"; +	mrk = ctx->u.iocb_cmd; +	mrk->u.marker.lun = lun; +	mrk->u.marker.modif = modif; +	mrk->timeout = qla2x00_async_iocb_timeout; +	mrk->done = qla2x00_async_marker_ctx_done; + +	rval = qla2x00_start_sp(sp); +	if (rval != QLA_SUCCESS) +		goto done_free_sp; + +	DEBUG2(printk(KERN_DEBUG +	    "scsi(%ld:%x): Async-marker - loop-id=%x " +	    "portid=%02x%02x%02x.\n", +	    fcport->vha->host_no, sp->handle, fcport->loop_id, +	    fcport->d_id.b.domain, fcport->d_id.b.area, +	    fcport->d_id.b.al_pa)); + +	return rval; + +done_free_sp: +	mrk->free(sp); +done: +	return rval; +} + +void  qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,      uint16_t *data)  {  	int rval; -	uint8_t opts = 0;  	switch (data[0]) {  	case MBS_COMMAND_COMPLETE: -		if (fcport->flags & FCF_FCP2_DEVICE) -			opts |= BIT_1; -		rval = qla2x00_get_port_database(vha, fcport, opts); -		if (rval != QLA_SUCCESS) -			qla2x00_mark_device_lost(vha, fcport, 1, 0); -		else -			qla2x00_update_fcport(vha, fcport); +		if (fcport->flags & FCF_FCP2_DEVICE) { +			fcport->flags |= FCF_ASYNC_SENT; +			qla2x00_post_async_adisc_work(vha, fcport, data); +			break; +		} +		qla2x00_update_fcport(vha, fcport);  		break;  	case MBS_COMMAND_ERROR: +		fcport->flags &= ~FCF_ASYNC_SENT;  		if (data[1] & QLA_LOGIO_LOGIN_RETRIED)  			set_bit(RELOGIN_NEEDED, &vha->dpc_flags);  		else @@ -228,21 +428,84 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,  		fcport->loop_id++;  		rval = qla2x00_find_new_loop_id(vha, fcport);  		if (rval != QLA_SUCCESS) { +			fcport->flags &= ~FCF_ASYNC_SENT;  			qla2x00_mark_device_lost(vha, fcport, 1, 0);  			break;  		}  		qla2x00_post_async_login_work(vha, fcport, NULL);  		break;  	} -	return QLA_SUCCESS; +	return;  } -int +void  qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,      uint16_t *data)  {  	qla2x00_mark_device_lost(vha, fcport, 1, 0); -	return QLA_SUCCESS; +	return; +} + +void +qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, +    uint16_t *data) +{ +	if (data[0] == MBS_COMMAND_COMPLETE) { +		qla2x00_update_fcport(vha, fcport); + +		return; +	} + +	/* Retry login. */ +	fcport->flags &= ~FCF_ASYNC_SENT; +	if (data[1] & QLA_LOGIO_LOGIN_RETRIED) +		set_bit(RELOGIN_NEEDED, &vha->dpc_flags); +	else +		qla2x00_mark_device_lost(vha, fcport, 1, 0); + +	return; +} + +void +qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport, +    struct srb_iocb *iocb) +{ +	int rval; +	uint32_t flags; +	uint16_t lun; + +	flags = iocb->u.tmf.flags; +	lun = (uint16_t)iocb->u.tmf.lun; + +	/* Issue Marker IOCB */ +	rval = qla2x00_async_marker(fcport, lun, +		flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID); + +	if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) { +		DEBUG2_3_11(printk(KERN_WARNING +			"%s(%ld): TM IOCB failed (%x).\n", +			__func__, vha->host_no, rval)); +	} + +	return; +} + +void +qla2x00_async_marker_done(struct scsi_qla_host *vha, fc_port_t *fcport, +    struct srb_iocb *iocb) +{ +	/* +	 * Currently we dont have any specific post response processing +	 * for this IOCB. We'll just return success or failed +	 * depending on whether the IOCB command succeeded or failed. +	 */ +	if (iocb->u.tmf.data) { +		DEBUG2_3_11(printk(KERN_WARNING +		    "%s(%ld): Marker IOCB failed (%x).\n", +		    __func__, vha->host_no, iocb->u.tmf.data)); +	} + +	return;  }  /****************************************************************************/ @@ -328,6 +591,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)  		if (rval)  			return (rval);  	} +  	if (IS_QLA84XX(ha)) {  		ha->cs84xx = qla84xx_get_chip(vha);  		if (!ha->cs84xx) { @@ -340,7 +604,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)  	ha->flags.chip_reset_done = 1;  	if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) { -	/* Issue verify 84xx FW IOCB to complete 84xx initialization */ +		/* Issue verify 84xx FW IOCB to complete 84xx initialization */  		rval = qla84xx_init_chip(vha);  		if (rval != QLA_SUCCESS) {  			qla_printk(KERN_ERR, ha, @@ -349,6 +613,12 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)  		}  	} +	if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) { +		if (qla24xx_read_fcp_prio_cfg(vha)) +			qla_printk(KERN_ERR, ha, +			"Unable to read FCP priority data.\n"); +	} +  	return (rval);  } @@ -955,6 +1225,9 @@ qla24xx_chip_diag(scsi_qla_host_t *vha)  	struct qla_hw_data *ha = vha->hw;  	struct req_que *req = ha->req_q_map[0]; +	if (IS_QLA82XX(ha)) +		return QLA_SUCCESS; +  	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;  	rval = qla2x00_mbx_reg_test(vha); @@ -1177,6 +1450,12 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)  	unsigned long flags;  	uint16_t fw_major_version; +	if (IS_QLA82XX(ha)) { +		rval = ha->isp_ops->load_risc(vha, &srisc_address); +		if (rval == QLA_SUCCESS) +			goto enable_82xx_npiv; +	} +  	if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {  		/* Disable SRAM, Instruction RAM and GP RAM parity.  */  		spin_lock_irqsave(&ha->hardware_lock, flags); @@ -1202,6 +1481,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)  			rval = qla2x00_execute_fw(vha, srisc_address);  			/* Retrieve firmware information. */  			if (rval == QLA_SUCCESS) { +enable_82xx_npiv:  				fw_major_version = ha->fw_major_version;  				rval = qla2x00_get_fw_version(vha,  				    &ha->fw_major_version, @@ -1226,8 +1506,10 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)  				    &ha->fw_xcb_count, NULL, NULL,  				    &ha->max_npiv_vports, NULL); -				if (!fw_major_version && ql2xallocfwdump) -					qla2x00_alloc_fw_dump(vha); +				if (!fw_major_version && ql2xallocfwdump) { +					if (!IS_QLA82XX(ha)) +						qla2x00_alloc_fw_dump(vha); +				}  			}  		} else {  			DEBUG2(printk(KERN_INFO @@ -1384,6 +1666,9 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)  	int rval;  	struct qla_hw_data *ha = vha->hw; +	if (IS_QLA82XX(ha)) +		return; +  	/* Update Serial Link options. */  	if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)  		return; @@ -1818,7 +2103,7 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)  	return(rval);  } -static inline void +inline void  qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,  	char *def)  { @@ -1826,7 +2111,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,  	uint16_t index;  	struct qla_hw_data *ha = vha->hw;  	int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && -	    !IS_QLA81XX(ha); +	    !IS_QLA8XXX_TYPE(ha);  	if (memcmp(model, BINZERO, len) != 0) {  		strncpy(ha->model_number, model, len); @@ -2017,6 +2302,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)  	if (IS_QLA23XX(ha)) {  		nv->firmware_options[0] |= BIT_2;  		nv->firmware_options[0] &= ~BIT_3; +		nv->firmware_options[0] &= ~BIT_6;  		nv->add_firmware_options[1] |= BIT_5 | BIT_4;  		if (IS_QLA2300(ha)) { @@ -2635,7 +2921,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)  	    PORT_RETRY_TIME;  	atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *  	    PORT_RETRY_TIME); -	fcport->flags &= ~FCF_LOGIN_NEEDED; +	fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);  	qla2x00_iidma_fcport(vha, fcport); @@ -2864,7 +3150,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,  	sw_info_t	*swl;  	int		swl_idx;  	int		first_dev, last_dev; -	port_id_t	wrap, nxt_d_id; +	port_id_t	wrap = {}, nxt_d_id;  	struct qla_hw_data *ha = vha->hw;  	struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);  	struct scsi_qla_host *tvp; @@ -3167,7 +3453,7 @@ qla2x00_device_resync(scsi_qla_host_t *vha)  	uint32_t rscn_entry;  	uint8_t rscn_out_iter;  	uint8_t format; -	port_id_t d_id; +	port_id_t d_id = {};  	rval = QLA_RSCNS_HANDLED; @@ -3281,11 +3567,15 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport,  	retry = 0;  	if (IS_ALOGIO_CAPABLE(ha)) { +		if (fcport->flags & FCF_ASYNC_SENT) +			return rval; +		fcport->flags |= FCF_ASYNC_SENT;  		rval = qla2x00_post_async_login_work(vha, fcport, NULL);  		if (!rval)  			return rval;  	} +	fcport->flags &= ~FCF_ASYNC_SENT;  	rval = qla2x00_fabric_login(vha, fcport, next_loopid);  	if (rval == QLA_SUCCESS) {  		/* Send an ADISC to FCP2 devices.*/ @@ -3546,6 +3836,45 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)  				qla2x00_rport_del(fcport);  } +void +qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) +{ +	struct qla_hw_data *ha = vha->hw; +	struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev); +	struct scsi_qla_host *tvp; + +	vha->flags.online = 0; +	ha->flags.chip_reset_done = 0; +	clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); +	ha->qla_stats.total_isp_aborts++; + +	qla_printk(KERN_INFO, ha, +	    "Performing ISP error recovery - ha= %p.\n", ha); + +	/* Chip reset does not apply to 82XX */ +	if (!IS_QLA82XX(ha)) +		ha->isp_ops->reset_chip(vha); + +	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); +	if (atomic_read(&vha->loop_state) != LOOP_DOWN) { +		atomic_set(&vha->loop_state, LOOP_DOWN); +		qla2x00_mark_all_devices_lost(vha, 0); +		list_for_each_entry_safe(vp, tvp, &base_vha->hw->vp_list, list) +			qla2x00_mark_all_devices_lost(vp, 0); +	} else { +		if (!atomic_read(&vha->loop_down_timer)) +			atomic_set(&vha->loop_down_timer, +			    LOOP_DOWN_TIME); +	} + +	/* Make sure for ISP 82XX IO DMA is complete */ +	if (IS_QLA82XX(ha)) +		qla82xx_wait_for_pending_commands(vha); + +	/* Requeue all commands in outstanding command list. */ +	qla2x00_abort_all_cmds(vha, DID_RESET << 16); +} +  /*  *  qla2x00_abort_isp  *      Resets ISP and aborts all outstanding commands. @@ -3567,27 +3896,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)  	struct req_que *req = ha->req_q_map[0];  	if (vha->flags.online) { -		vha->flags.online = 0; -		ha->flags.chip_reset_done = 0; -		clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); -		ha->qla_stats.total_isp_aborts++; - -		qla_printk(KERN_INFO, ha, -		    "Performing ISP error recovery - ha= %p.\n", ha); -		ha->isp_ops->reset_chip(vha); - -		atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); -		if (atomic_read(&vha->loop_state) != LOOP_DOWN) { -			atomic_set(&vha->loop_state, LOOP_DOWN); -			qla2x00_mark_all_devices_lost(vha, 0); -		} else { -			if (!atomic_read(&vha->loop_down_timer)) -				atomic_set(&vha->loop_down_timer, -				    LOOP_DOWN_TIME); -		} - -		/* Requeue all commands in outstanding command list. */ -		qla2x00_abort_all_cmds(vha, DID_RESET << 16); +		qla2x00_abort_isp_cleanup(vha);  		if (unlikely(pci_channel_offline(ha->pdev) &&  		    ha->flags.pci_channel_io_perm_failure)) { @@ -3843,6 +4152,9 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha)  	struct qla_hw_data *ha = vha->hw;  	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; +	if (IS_QLA82XX(ha)) +		return; +  	vha->flags.online = 0;  	ha->isp_ops->disable_intrs(ha); @@ -3906,6 +4218,8 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)  	}  	ha->nvram_size = sizeof(struct nvram_24xx);  	ha->vpd_size = FA_NVRAM_VPD_SIZE; +	if (IS_QLA82XX(ha)) +		ha->vpd_size = FA_VPD_SIZE_82XX;  	/* Get VPD data into cache */  	ha->vpd = ha->nvram + VPD_OFFSET; @@ -4769,7 +5083,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)  	 * Setup driver NVRAM options.  	 */  	qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name), -	    "QLE81XX"); +	    "QLE8XXX");  	/* Use alternate WWN? */  	if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { @@ -4892,6 +5206,114 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)  	return (rval);  } +int +qla82xx_restart_isp(scsi_qla_host_t *vha) +{ +	int status, rval; +	uint32_t wait_time; +	struct qla_hw_data *ha = vha->hw; +	struct req_que *req = ha->req_q_map[0]; +	struct rsp_que *rsp = ha->rsp_q_map[0]; +	struct scsi_qla_host *vp; +	struct scsi_qla_host *tvp; + +	status = qla2x00_init_rings(vha); +	if (!status) { +		clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); +		ha->flags.chip_reset_done = 1; + +		status = qla2x00_fw_ready(vha); +		if (!status) { +			qla_printk(KERN_INFO, ha, +			"%s(): Start configure loop, " +			"status = %d\n", __func__, status); + +			/* Issue a marker after FW becomes ready. */ +			qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); + +			vha->flags.online = 1; +			/* Wait at most MAX_TARGET RSCNs for a stable link. */ +			wait_time = 256; +			do { +				clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); +				qla2x00_configure_loop(vha); +				wait_time--; +			} while (!atomic_read(&vha->loop_down_timer) && +			    !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) && +			    wait_time && +			    (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))); +		} + +		/* if no cable then assume it's good */ +		if ((vha->device_flags & DFLG_NO_CABLE)) +			status = 0; + +		qla_printk(KERN_INFO, ha, +			"%s(): Configure loop done, status = 0x%x\n", +			__func__, status); +	} + +	if (!status) { +		clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); + +		if (!atomic_read(&vha->loop_down_timer)) { +			/* +			 * Issue marker command only when we are going +			 * to start the I/O . +			 */ +			vha->marker_needed = 1; +		} + +		vha->flags.online = 1; + +		ha->isp_ops->enable_intrs(ha); + +		ha->isp_abort_cnt = 0; +		clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); + +		if (ha->fce) { +			ha->flags.fce_enabled = 1; +			memset(ha->fce, 0, +			    fce_calc_size(ha->fce_bufs)); +			rval = qla2x00_enable_fce_trace(vha, +			    ha->fce_dma, ha->fce_bufs, ha->fce_mb, +			    &ha->fce_bufs); +			if (rval) { +				qla_printk(KERN_WARNING, ha, +				    "Unable to reinitialize FCE " +				    "(%d).\n", rval); +				ha->flags.fce_enabled = 0; +			} +		} + +		if (ha->eft) { +			memset(ha->eft, 0, EFT_SIZE); +			rval = qla2x00_enable_eft_trace(vha, +			    ha->eft_dma, EFT_NUM_BUFFERS); +			if (rval) { +				qla_printk(KERN_WARNING, ha, +				    "Unable to reinitialize EFT " +				    "(%d).\n", rval); +			} +		} +	} + +	if (!status) { +		DEBUG(printk(KERN_INFO +			"qla82xx_restart_isp(%ld): succeeded.\n", +			vha->host_no)); +		list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { +			if (vp->vp_idx) +				qla2x00_vp_abort_isp(vp); +		} +	} else { +		qla_printk(KERN_INFO, ha, +			"qla82xx_restart_isp: **** FAILED ****\n"); +	} + +	return status; +} +  void  qla81xx_update_fw_options(scsi_qla_host_t *vha)  { @@ -4905,3 +5327,165 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha)  	ha->fw_options[2] |= BIT_9;  	qla2x00_set_fw_options(vha, ha->fw_options);  } + +/* + * qla24xx_get_fcp_prio + *	Gets the fcp cmd priority value for the logged in port. + *	Looks for a match of the port descriptors within + *	each of the fcp prio config entries. If a match is found, + *	the tag (priority) value is returned. + * + * Input: + *	ha = adapter block po + *	fcport = port structure pointer. + * + * Return: + *	non-zero (if found) + * 	0 (if not found) + * + * Context: + * 	Kernel context + */ +uint8_t +qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport) +{ +	int i, entries; +	uint8_t pid_match, wwn_match; +	uint8_t priority; +	uint32_t pid1, pid2; +	uint64_t wwn1, wwn2; +	struct qla_fcp_prio_entry *pri_entry; +	struct qla_hw_data *ha = vha->hw; + +	if (!ha->fcp_prio_cfg || !ha->flags.fcp_prio_enabled) +		return 0; + +	priority = 0; +	entries = ha->fcp_prio_cfg->num_entries; +	pri_entry = &ha->fcp_prio_cfg->entry[0]; + +	for (i = 0; i < entries; i++) { +		pid_match = wwn_match = 0; + +		if (!(pri_entry->flags & FCP_PRIO_ENTRY_VALID)) { +			pri_entry++; +			continue; +		} + +		/* check source pid for a match */ +		if (pri_entry->flags & FCP_PRIO_ENTRY_SPID_VALID) { +			pid1 = pri_entry->src_pid & INVALID_PORT_ID; +			pid2 = vha->d_id.b24 & INVALID_PORT_ID; +			if (pid1 == INVALID_PORT_ID) +				pid_match++; +			else if (pid1 == pid2) +				pid_match++; +		} + +		/* check destination pid for a match */ +		if (pri_entry->flags & FCP_PRIO_ENTRY_DPID_VALID) { +			pid1 = pri_entry->dst_pid & INVALID_PORT_ID; +			pid2 = fcport->d_id.b24 & INVALID_PORT_ID; +			if (pid1 == INVALID_PORT_ID) +				pid_match++; +			else if (pid1 == pid2) +				pid_match++; +		} + +		/* check source WWN for a match */ +		if (pri_entry->flags & FCP_PRIO_ENTRY_SWWN_VALID) { +			wwn1 = wwn_to_u64(vha->port_name); +			wwn2 = wwn_to_u64(pri_entry->src_wwpn); +			if (wwn2 == (uint64_t)-1) +				wwn_match++; +			else if (wwn1 == wwn2) +				wwn_match++; +		} + +		/* check destination WWN for a match */ +		if (pri_entry->flags & FCP_PRIO_ENTRY_DWWN_VALID) { +			wwn1 = wwn_to_u64(fcport->port_name); +			wwn2 = wwn_to_u64(pri_entry->dst_wwpn); +			if (wwn2 == (uint64_t)-1) +				wwn_match++; +			else if (wwn1 == wwn2) +				wwn_match++; +		} + +		if (pid_match == 2 || wwn_match == 2) { +			/* Found a matching entry */ +			if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID) +				priority = pri_entry->tag; +			break; +		} + +		pri_entry++; +	} + +	return priority; +} + +/* + * qla24xx_update_fcport_fcp_prio + *	Activates fcp priority for the logged in fc port + * + * Input: + *	ha = adapter block pointer. + *	fcp = port structure pointer. + * + * Return: + *	QLA_SUCCESS or QLA_FUNCTION_FAILED + * + * Context: + *	Kernel context. + */ +int +qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *ha, fc_port_t *fcport) +{ +	int ret; +	uint8_t priority; +	uint16_t mb[5]; + +	if (atomic_read(&fcport->state) == FCS_UNCONFIGURED || +		fcport->port_type != FCT_TARGET || +		fcport->loop_id == FC_NO_LOOP_ID) +		return QLA_FUNCTION_FAILED; + +	priority = qla24xx_get_fcp_prio(ha, fcport); +	ret = qla24xx_set_fcp_prio(ha, fcport->loop_id, priority, mb); +	if (ret == QLA_SUCCESS) +		fcport->fcp_prio = priority; +	else +		DEBUG2(printk(KERN_WARNING +			"scsi(%ld): Unable to activate fcp priority, " +			" ret=0x%x\n", ha->host_no, ret)); + +	return  ret; +} + +/* + * qla24xx_update_all_fcp_prio + *	Activates fcp priority for all the logged in ports + * + * Input: + *	ha = adapter block pointer. + * + * Return: + *	QLA_SUCCESS or QLA_FUNCTION_FAILED + * + * Context: + *	Kernel context. + */ +int +qla24xx_update_all_fcp_prio(scsi_qla_host_t *vha) +{ +	int ret; +	fc_port_t *fcport; + +	ret = QLA_FUNCTION_FAILED; +	/* We need to set priority for all logged in ports */ +	list_for_each_entry(fcport, &vha->vp_fcports, list) +		ret = qla24xx_update_fcport_fcp_prio(vha, fcport); + +	return ret; +} diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 5e0a7095c9f..84c2fea154d 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -37,7 +37,10 @@ qla2x00_poll(struct rsp_que *rsp)  	unsigned long flags;  	struct qla_hw_data *ha = rsp->hw;  	local_irq_save(flags); -	ha->isp_ops->intr_handler(0, rsp); +	if (IS_QLA82XX(ha)) +		qla82xx_poll(0, rsp); +	else +		ha->isp_ops->intr_handler(0, rsp);  	local_irq_restore(flags);  } @@ -64,3 +67,19 @@ qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id)  	return ((loop_id > ha->max_loop_id && loop_id < SNS_FIRST_LOOP_ID) ||  	    loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST);  } + +static inline void +qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp) +{ +	struct dsd_dma *dsd_ptr, *tdsd_ptr; + +	/* clean up allocated prev pool */ +	list_for_each_entry_safe(dsd_ptr, tdsd_ptr, +	    &((struct crc_context *)sp->ctx)->dsd_list, list) { +		dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr, +		    dsd_ptr->dsd_list_dma); +		list_del(&dsd_ptr->list); +		kfree(dsd_ptr); +	} +	INIT_LIST_HEAD(&((struct crc_context *)sp->ctx)->dsd_list); +} diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 8299a9891bf..8ef94536541 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -145,7 +145,49 @@ qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha)  	return (cont_pkt);  } -/** +static inline int +qla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts) +{ +	uint8_t	guard = scsi_host_get_guard(sp->cmd->device->host); + +	/* We only support T10 DIF right now */ +	if (guard != SHOST_DIX_GUARD_CRC) { +		DEBUG2(printk(KERN_ERR "Unsupported guard: %d\n", guard)); +		return 0; +	} + +	/* We always use DIFF Bundling for best performance */ +	*fw_prot_opts = 0; + +	/* Translate SCSI opcode to a protection opcode */ +	switch (scsi_get_prot_op(sp->cmd)) { +	case SCSI_PROT_READ_STRIP: +		*fw_prot_opts |= PO_MODE_DIF_REMOVE; +		break; +	case SCSI_PROT_WRITE_INSERT: +		*fw_prot_opts |= PO_MODE_DIF_INSERT; +		break; +	case SCSI_PROT_READ_INSERT: +		*fw_prot_opts |= PO_MODE_DIF_INSERT; +		break; +	case SCSI_PROT_WRITE_STRIP: +		*fw_prot_opts |= PO_MODE_DIF_REMOVE; +		break; +	case SCSI_PROT_READ_PASS: +		*fw_prot_opts |= PO_MODE_DIF_PASS; +		break; +	case SCSI_PROT_WRITE_PASS: +		*fw_prot_opts |= PO_MODE_DIF_PASS; +		break; +	default:	/* Normal Request */ +		*fw_prot_opts |= PO_MODE_DIF_PASS; +		break; +	} + +	return scsi_prot_sg_count(sp->cmd); +} + +/*   * qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit   * capable IOCB types.   * @@ -506,7 +548,10 @@ qla2x00_req_pkt(struct scsi_qla_host *vha, struct req_que *req,  				cnt = (uint16_t)  					RD_REG_DWORD(®->isp25mq.req_q_out);  			else { -				if (IS_FWI2_CAPABLE(ha)) +				if (IS_QLA82XX(ha)) +					cnt = (uint16_t)RD_REG_DWORD( +					    ®->isp82.req_q_out); +				else if (IS_FWI2_CAPABLE(ha))  					cnt = (uint16_t)RD_REG_DWORD(  						®->isp24.req_q_out);  				else @@ -579,11 +624,29 @@ qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req)  		req->ring_ptr++;  	/* Set chip new ring index. */ -	if (ha->mqenable) { +	if (IS_QLA82XX(ha)) { +		uint32_t dbval = 0x04 | (ha->portnum << 5); + +		/* write, read and verify logic */ +		dbval = dbval | (req->id << 8) | (req->ring_index << 16); +		if (ql2xdbwr) +			qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval); +		else { +			WRT_REG_DWORD( +				(unsigned long __iomem *)ha->nxdb_wr_ptr, +				dbval); +			wmb(); +			while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { +				WRT_REG_DWORD((unsigned long __iomem *) +					ha->nxdb_wr_ptr, dbval); +				wmb(); +			} +		} +	} else if (ha->mqenable) { +		/* Set chip new ring index. */  		WRT_REG_DWORD(®->isp25mq.req_q_in, req->ring_index);  		RD_REG_DWORD(&ioreg->hccr); -	} -	else { +	} else {  		if (IS_FWI2_CAPABLE(ha)) {  			WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index);  			RD_REG_DWORD_RELAXED(®->isp24.req_q_in); @@ -604,7 +667,7 @@ qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req)   *   * Returns the number of IOCB entries needed to store @dsds.   */ -static inline uint16_t +inline uint16_t  qla24xx_calc_iocbs(uint16_t dsds)  {  	uint16_t iocbs; @@ -615,6 +678,8 @@ qla24xx_calc_iocbs(uint16_t dsds)  		if ((dsds - 1) % 5)  			iocbs++;  	} +	DEBUG3(printk(KERN_DEBUG "%s(): Required PKT(s) = %d\n", +	    __func__, iocbs));  	return iocbs;  } @@ -626,7 +691,7 @@ qla24xx_calc_iocbs(uint16_t dsds)   * @cmd_pkt: Command type 3 IOCB   * @tot_dsds: Total number of segments to transfer   */ -static inline void +inline void  qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,      uint16_t tot_dsds)  { @@ -695,6 +760,453 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,  	}  } +struct fw_dif_context { +	uint32_t ref_tag; +	uint16_t app_tag; +	uint8_t ref_tag_mask[4];	/* Validation/Replacement Mask*/ +	uint8_t app_tag_mask[2];	/* Validation/Replacement Mask*/ +}; + +/* + * qla24xx_set_t10dif_tags_from_cmd - Extract Ref and App tags from SCSI command + * + */ +static inline void +qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, +    unsigned int protcnt) +{ +	struct sd_dif_tuple *spt; +	unsigned char op = scsi_get_prot_op(cmd); + +	switch (scsi_get_prot_type(cmd)) { +	/* For TYPE 0 protection: no checking */ +	case SCSI_PROT_DIF_TYPE0: +		pkt->ref_tag_mask[0] = 0x00; +		pkt->ref_tag_mask[1] = 0x00; +		pkt->ref_tag_mask[2] = 0x00; +		pkt->ref_tag_mask[3] = 0x00; +		break; + +	/* +	 * For TYPE 2 protection: 16 bit GUARD + 32 bit REF tag has to +	 * match LBA in CDB + N +	 */ +	case SCSI_PROT_DIF_TYPE2: +		break; + +	/* For Type 3 protection: 16 bit GUARD only */ +	case SCSI_PROT_DIF_TYPE3: +		pkt->ref_tag_mask[0] = pkt->ref_tag_mask[1] = +			pkt->ref_tag_mask[2] = pkt->ref_tag_mask[3] = +								0x00; +		break; + +	/* +	 * For TYpe 1 protection: 16 bit GUARD tag, 32 bit REF tag, and +	 * 16 bit app tag. +	 */ +	case SCSI_PROT_DIF_TYPE1: +		if (!ql2xenablehba_err_chk) +			break; + +		if (protcnt && (op == SCSI_PROT_WRITE_STRIP || +		    op == SCSI_PROT_WRITE_PASS)) { +			spt = page_address(sg_page(scsi_prot_sglist(cmd))) + +			    scsi_prot_sglist(cmd)[0].offset; +			DEBUG18(printk(KERN_DEBUG +			    "%s(): LBA from user %p, lba = 0x%x\n", +			    __func__, spt, (int)spt->ref_tag)); +			pkt->ref_tag = swab32(spt->ref_tag); +			pkt->app_tag_mask[0] = 0x0; +			pkt->app_tag_mask[1] = 0x0; +		} else { +			pkt->ref_tag = cpu_to_le32((uint32_t) +			    (0xffffffff & scsi_get_lba(cmd))); +			pkt->app_tag = __constant_cpu_to_le16(0); +			pkt->app_tag_mask[0] = 0x0; +			pkt->app_tag_mask[1] = 0x0; +		} +		/* enable ALL bytes of the ref tag */ +		pkt->ref_tag_mask[0] = 0xff; +		pkt->ref_tag_mask[1] = 0xff; +		pkt->ref_tag_mask[2] = 0xff; +		pkt->ref_tag_mask[3] = 0xff; +		break; +	} + +	DEBUG18(printk(KERN_DEBUG +	    "%s(): Setting protection Tags: (BIG) ref tag = 0x%x," +	    " app tag = 0x%x, prot SG count %d , cmd lba 0x%x," +	    " prot_type=%u\n", __func__, pkt->ref_tag, pkt->app_tag, protcnt, +	    (int)scsi_get_lba(cmd), scsi_get_prot_type(cmd))); +} + + +static int +qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, +	uint16_t tot_dsds) +{ +	void *next_dsd; +	uint8_t avail_dsds = 0; +	uint32_t dsd_list_len; +	struct dsd_dma *dsd_ptr; +	struct scatterlist *sg; +	uint32_t *cur_dsd = dsd; +	int	i; +	uint16_t	used_dsds = tot_dsds; + +	uint8_t		*cp; + +	scsi_for_each_sg(sp->cmd, sg, tot_dsds, i) { +		dma_addr_t	sle_dma; + +		/* Allocate additional continuation packets? */ +		if (avail_dsds == 0) { +			avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? +					QLA_DSDS_PER_IOCB : used_dsds; +			dsd_list_len = (avail_dsds + 1) * 12; +			used_dsds -= avail_dsds; + +			/* allocate tracking DS */ +			dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); +			if (!dsd_ptr) +				return 1; + +			/* allocate new list */ +			dsd_ptr->dsd_addr = next_dsd = +			    dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, +				&dsd_ptr->dsd_list_dma); + +			if (!next_dsd) { +				/* +				 * Need to cleanup only this dsd_ptr, rest +				 * will be done by sp_free_dma() +				 */ +				kfree(dsd_ptr); +				return 1; +			} + +			list_add_tail(&dsd_ptr->list, +			    &((struct crc_context *)sp->ctx)->dsd_list); + +			sp->flags |= SRB_CRC_CTX_DSD_VALID; + +			/* add new list to cmd iocb or last list */ +			*cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); +			*cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); +			*cur_dsd++ = dsd_list_len; +			cur_dsd = (uint32_t *)next_dsd; +		} +		sle_dma = sg_dma_address(sg); +		DEBUG18(printk("%s(): %p, sg entry %d - addr =0x%x 0x%x," +		    " len =%d\n", __func__ , cur_dsd, i, LSD(sle_dma), +		    MSD(sle_dma), sg_dma_len(sg))); +		*cur_dsd++ = cpu_to_le32(LSD(sle_dma)); +		*cur_dsd++ = cpu_to_le32(MSD(sle_dma)); +		*cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); +		avail_dsds--; + +		if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) { +			cp = page_address(sg_page(sg)) + sg->offset; +			DEBUG18(printk("%s(): User Data buffer= %p:\n", +			    __func__ , cp)); +		} +	} +	/* Null termination */ +	*cur_dsd++ = 0; +	*cur_dsd++ = 0; +	*cur_dsd++ = 0; +	return 0; +} + +static int +qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, +							uint32_t *dsd, +	uint16_t tot_dsds) +{ +	void *next_dsd; +	uint8_t avail_dsds = 0; +	uint32_t dsd_list_len; +	struct dsd_dma *dsd_ptr; +	struct scatterlist *sg; +	int	i; +	struct scsi_cmnd *cmd; +	uint32_t *cur_dsd = dsd; +	uint16_t	used_dsds = tot_dsds; + +	uint8_t		*cp; + + +	cmd = sp->cmd; +	scsi_for_each_prot_sg(cmd, sg, tot_dsds, i) { +		dma_addr_t	sle_dma; + +		/* Allocate additional continuation packets? */ +		if (avail_dsds == 0) { +			avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? +						QLA_DSDS_PER_IOCB : used_dsds; +			dsd_list_len = (avail_dsds + 1) * 12; +			used_dsds -= avail_dsds; + +			/* allocate tracking DS */ +			dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); +			if (!dsd_ptr) +				return 1; + +			/* allocate new list */ +			dsd_ptr->dsd_addr = next_dsd = +			    dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, +				&dsd_ptr->dsd_list_dma); + +			if (!next_dsd) { +				/* +				 * Need to cleanup only this dsd_ptr, rest +				 * will be done by sp_free_dma() +				 */ +				kfree(dsd_ptr); +				return 1; +			} + +			list_add_tail(&dsd_ptr->list, +			    &((struct crc_context *)sp->ctx)->dsd_list); + +			sp->flags |= SRB_CRC_CTX_DSD_VALID; + +			/* add new list to cmd iocb or last list */ +			*cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); +			*cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); +			*cur_dsd++ = dsd_list_len; +			cur_dsd = (uint32_t *)next_dsd; +		} +		sle_dma = sg_dma_address(sg); +		if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) { +			DEBUG18(printk(KERN_DEBUG +			    "%s(): %p, sg entry %d - addr =0x%x" +			    "0x%x, len =%d\n", __func__ , cur_dsd, i, +			    LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg))); +		} +		*cur_dsd++ = cpu_to_le32(LSD(sle_dma)); +		*cur_dsd++ = cpu_to_le32(MSD(sle_dma)); +		*cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + +		if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) { +			cp = page_address(sg_page(sg)) + sg->offset; +			DEBUG18(printk("%s(): Protection Data buffer = %p:\n", +			    __func__ , cp)); +		} +		avail_dsds--; +	} +	/* Null termination */ +	*cur_dsd++ = 0; +	*cur_dsd++ = 0; +	*cur_dsd++ = 0; +	return 0; +} + +/** + * qla24xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command + *							Type 6 IOCB types. + * + * @sp: SRB command to process + * @cmd_pkt: Command type 3 IOCB + * @tot_dsds: Total number of segments to transfer + */ +static inline int +qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, +    uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts) +{ +	uint32_t		*cur_dsd, *fcp_dl; +	scsi_qla_host_t		*vha; +	struct scsi_cmnd	*cmd; +	struct scatterlist	*cur_seg; +	int			sgc; +	uint32_t		total_bytes; +	uint32_t		data_bytes; +	uint32_t		dif_bytes; +	uint8_t			bundling = 1; +	uint16_t		blk_size; +	uint8_t			*clr_ptr; +	struct crc_context	*crc_ctx_pkt = NULL; +	struct qla_hw_data	*ha; +	uint8_t			additional_fcpcdb_len; +	uint16_t		fcp_cmnd_len; +	struct fcp_cmnd		*fcp_cmnd; +	dma_addr_t		crc_ctx_dma; + +	cmd = sp->cmd; + +	sgc = 0; +	/* Update entry type to indicate Command Type CRC_2 IOCB */ +	*((uint32_t *)(&cmd_pkt->entry_type)) = +	    __constant_cpu_to_le32(COMMAND_TYPE_CRC_2); + +	/* No data transfer */ +	data_bytes = scsi_bufflen(cmd); +	if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { +		DEBUG18(printk(KERN_INFO "%s: Zero data bytes or DMA-NONE %d\n", +		    __func__, data_bytes)); +		cmd_pkt->byte_count = __constant_cpu_to_le32(0); +		return QLA_SUCCESS; +	} + +	vha = sp->fcport->vha; +	ha = vha->hw; + +	DEBUG18(printk(KERN_DEBUG +	    "%s(%ld): Executing cmd sp %p, pid=%ld, prot_op=%u.\n", __func__, +	    vha->host_no, sp, cmd->serial_number, scsi_get_prot_op(sp->cmd))); + +	cmd_pkt->vp_index = sp->fcport->vp_idx; + +	/* Set transfer direction */ +	if (cmd->sc_data_direction == DMA_TO_DEVICE) { +		cmd_pkt->control_flags = +		    __constant_cpu_to_le16(CF_WRITE_DATA); +	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { +		cmd_pkt->control_flags = +		    __constant_cpu_to_le16(CF_READ_DATA); +	} + +	tot_prot_dsds = scsi_prot_sg_count(cmd); +	if (!tot_prot_dsds) +		bundling = 0; + +	/* Allocate CRC context from global pool */ +	crc_ctx_pkt = sp->ctx = dma_pool_alloc(ha->dl_dma_pool, +	    GFP_ATOMIC, &crc_ctx_dma); + +	if (!crc_ctx_pkt) +		goto crc_queuing_error; + +	/* Zero out CTX area. */ +	clr_ptr = (uint8_t *)crc_ctx_pkt; +	memset(clr_ptr, 0, sizeof(*crc_ctx_pkt)); + +	crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma; + +	sp->flags |= SRB_CRC_CTX_DMA_VALID; + +	/* Set handle */ +	crc_ctx_pkt->handle = cmd_pkt->handle; + +	INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list); + +	qla24xx_set_t10dif_tags(cmd, (struct fw_dif_context *) +	    &crc_ctx_pkt->ref_tag, tot_prot_dsds); + +	cmd_pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma)); +	cmd_pkt->crc_context_address[1] = cpu_to_le32(MSD(crc_ctx_dma)); +	cmd_pkt->crc_context_len = CRC_CONTEXT_LEN_FW; + +	/* Determine SCSI command length -- align to 4 byte boundary */ +	if (cmd->cmd_len > 16) { +		DEBUG18(printk(KERN_INFO "%s(): **** SCSI CMD > 16\n", +		    __func__)); +		additional_fcpcdb_len = cmd->cmd_len - 16; +		if ((cmd->cmd_len % 4) != 0) { +			/* SCSI cmd > 16 bytes must be multiple of 4 */ +			goto crc_queuing_error; +		} +		fcp_cmnd_len = 12 + cmd->cmd_len + 4; +	} else { +		additional_fcpcdb_len = 0; +		fcp_cmnd_len = 12 + 16 + 4; +	} + +	fcp_cmnd = &crc_ctx_pkt->fcp_cmnd; + +	fcp_cmnd->additional_cdb_len = additional_fcpcdb_len; +	if (cmd->sc_data_direction == DMA_TO_DEVICE) +		fcp_cmnd->additional_cdb_len |= 1; +	else if (cmd->sc_data_direction == DMA_FROM_DEVICE) +		fcp_cmnd->additional_cdb_len |= 2; + +	int_to_scsilun(sp->cmd->device->lun, &fcp_cmnd->lun); +	memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); +	cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len); +	cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32( +	    LSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF)); +	cmd_pkt->fcp_cmnd_dseg_address[1] = cpu_to_le32( +	    MSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF)); +	fcp_cmnd->task_attribute = 0; +	fcp_cmnd->task_managment = 0; + +	cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */ + +	DEBUG18(printk(KERN_INFO "%s(%ld): Total SG(s) Entries %d, Data" +	    "entries %d, data bytes %d, Protection entries %d\n", +	    __func__, vha->host_no, tot_dsds, (tot_dsds-tot_prot_dsds), +	    data_bytes, tot_prot_dsds)); + +	/* Compute dif len and adjust data len to incude protection */ +	total_bytes = data_bytes; +	dif_bytes = 0; +	blk_size = cmd->device->sector_size; +	if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE1) { +		dif_bytes = (data_bytes / blk_size) * 8; +		total_bytes += dif_bytes; +	} + +	if (!ql2xenablehba_err_chk) +		fw_prot_opts |= 0x10; /* Disable Guard tag checking */ + +	if (!bundling) { +		cur_dsd = (uint32_t *) &crc_ctx_pkt->u.nobundling.data_address; +	} else { +		/* +		 * Configure Bundling if we need to fetch interlaving +		 * protection PCI accesses +		 */ +		fw_prot_opts |= PO_ENABLE_DIF_BUNDLING; +		crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes); +		crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds - +							tot_prot_dsds); +		cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.data_address; +	} + +	/* Finish the common fields of CRC pkt */ +	crc_ctx_pkt->blk_size = cpu_to_le16(blk_size); +	crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts); +	crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes); +	crc_ctx_pkt->guard_seed = __constant_cpu_to_le16(0); +	/* Fibre channel byte count */ +	cmd_pkt->byte_count = cpu_to_le32(total_bytes); +	fcp_dl = (uint32_t *)(crc_ctx_pkt->fcp_cmnd.cdb + 16 + +	    additional_fcpcdb_len); +	*fcp_dl = htonl(total_bytes); + +	DEBUG18(printk(KERN_INFO "%s(%ld): dif bytes = 0x%x (%d), total bytes" +	    " = 0x%x (%d), dat block size =0x%x (%d)\n", __func__, +	    vha->host_no, dif_bytes, dif_bytes, total_bytes, total_bytes, +	    crc_ctx_pkt->blk_size, crc_ctx_pkt->blk_size)); + +	/* Walks data segments */ + +	cmd_pkt->control_flags |= +	    __constant_cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE); +	if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd, +	    (tot_dsds - tot_prot_dsds))) +		goto crc_queuing_error; + +	if (bundling && tot_prot_dsds) { +		/* Walks dif segments */ +		cur_seg = scsi_prot_sglist(cmd); +		cmd_pkt->control_flags |= +			__constant_cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE); +		cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address; +		if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd, +		    tot_prot_dsds)) +			goto crc_queuing_error; +	} +	return QLA_SUCCESS; + +crc_queuing_error: +	DEBUG18(qla_printk(KERN_INFO, ha, +	    "CMD sent FAILED crc_q error:sp = %p\n", sp)); +	/* Cleanup will be performed by the caller */ + +	return QLA_FUNCTION_FAILED; +}  /**   * qla24xx_start_scsi() - Send a SCSI command to the ISP @@ -848,6 +1360,191 @@ queuing_error:  	return QLA_FUNCTION_FAILED;  } + +/** + * qla24xx_dif_start_scsi() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * + * Returns non-zero if a failure occurred, else zero. + */ +int +qla24xx_dif_start_scsi(srb_t *sp) +{ +	int			nseg; +	unsigned long		flags; +	uint32_t		*clr_ptr; +	uint32_t		index; +	uint32_t		handle; +	uint16_t		cnt; +	uint16_t		req_cnt = 0; +	uint16_t		tot_dsds; +	uint16_t		tot_prot_dsds; +	uint16_t		fw_prot_opts = 0; +	struct req_que		*req = NULL; +	struct rsp_que		*rsp = NULL; +	struct scsi_cmnd	*cmd = sp->cmd; +	struct scsi_qla_host	*vha = sp->fcport->vha; +	struct qla_hw_data	*ha = vha->hw; +	struct cmd_type_crc_2	*cmd_pkt; +	uint32_t		status = 0; + +#define QDSS_GOT_Q_SPACE	BIT_0 + +	/* Only process protection in this routine */ +	if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) +		return qla24xx_start_scsi(sp); + +	/* Setup device pointers. */ + +	qla25xx_set_que(sp, &rsp); +	req = vha->req; + +	/* So we know we haven't pci_map'ed anything yet */ +	tot_dsds = 0; + +	/* Send marker if required */ +	if (vha->marker_needed != 0) { +		if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != +		    QLA_SUCCESS) +			return QLA_FUNCTION_FAILED; +		vha->marker_needed = 0; +	} + +	/* Acquire ring specific lock */ +	spin_lock_irqsave(&ha->hardware_lock, flags); + +	/* Check for room in outstanding command list. */ +	handle = req->current_outstanding_cmd; +	for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { +		handle++; +		if (handle == MAX_OUTSTANDING_COMMANDS) +			handle = 1; +		if (!req->outstanding_cmds[handle]) +			break; +	} + +	if (index == MAX_OUTSTANDING_COMMANDS) +		goto queuing_error; + +	/* Compute number of required data segments */ +	/* Map the sg table so we have an accurate count of sg entries needed */ +	if (scsi_sg_count(cmd)) { +		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), +		    scsi_sg_count(cmd), cmd->sc_data_direction); +		if (unlikely(!nseg)) +			goto queuing_error; +		else +			sp->flags |= SRB_DMA_VALID; +	} else +		nseg = 0; + +	/* number of required data segments */ +	tot_dsds = nseg; + +	/* Compute number of required protection segments */ +	if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) { +		nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), +		    scsi_prot_sg_count(cmd), cmd->sc_data_direction); +		if (unlikely(!nseg)) +			goto queuing_error; +		else +			sp->flags |= SRB_CRC_PROT_DMA_VALID; +	} else { +		nseg = 0; +	} + +	req_cnt = 1; +	/* Total Data and protection sg segment(s) */ +	tot_prot_dsds = nseg; +	tot_dsds += nseg; +	if (req->cnt < (req_cnt + 2)) { +		cnt = RD_REG_DWORD_RELAXED(req->req_q_out); + +		if (req->ring_index < cnt) +			req->cnt = cnt - req->ring_index; +		else +			req->cnt = req->length - +				(req->ring_index - cnt); +	} + +	if (req->cnt < (req_cnt + 2)) +		goto queuing_error; + +	status |= QDSS_GOT_Q_SPACE; + +	/* Build header part of command packet (excluding the OPCODE). */ +	req->current_outstanding_cmd = handle; +	req->outstanding_cmds[handle] = sp; +	sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; +	req->cnt -= req_cnt; + +	/* Fill-in common area */ +	cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; +	cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + +	clr_ptr = (uint32_t *)cmd_pkt + 2; +	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); + +	/* Set NPORT-ID and LUN number*/ +	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); +	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; +	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; +	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; + +	int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); +	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); + +	/* Total Data and protection segment(s) */ +	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + +	/* Build IOCB segments and adjust for data protection segments */ +	if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *) +	    req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) != +		QLA_SUCCESS) +		goto queuing_error; + +	cmd_pkt->entry_count = (uint8_t)req_cnt; +	/* Specify response queue number where completion should happen */ +	cmd_pkt->entry_status = (uint8_t) rsp->id; +	cmd_pkt->timeout = __constant_cpu_to_le16(0); +	wmb(); + +	/* Adjust ring index. */ +	req->ring_index++; +	if (req->ring_index == req->length) { +		req->ring_index = 0; +		req->ring_ptr = req->ring; +	} else +		req->ring_ptr++; + +	/* Set chip new ring index. */ +	WRT_REG_DWORD(req->req_q_in, req->ring_index); +	RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr); + +	/* Manage unprocessed RIO/ZIO commands in response queue. */ +	if (vha->flags.process_response_queue && +	    rsp->ring_ptr->signature != RESPONSE_PROCESSED) +		qla24xx_process_response_queue(vha, rsp); + +	spin_unlock_irqrestore(&ha->hardware_lock, flags); + +	return QLA_SUCCESS; + +queuing_error: +	if (status & QDSS_GOT_Q_SPACE) { +		req->outstanding_cmds[handle] = NULL; +		req->cnt += req_cnt; +	} +	/* Cleanup will be performed by the caller (queuecommand) */ + +	spin_unlock_irqrestore(&ha->hardware_lock, flags); + +	DEBUG18(qla_printk(KERN_INFO, ha, +	    "CMD sent FAILED SCSI prot_op:%02x\n", scsi_get_prot_op(cmd))); +	return QLA_FUNCTION_FAILED; +} + +  static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp)  {  	struct scsi_cmnd *cmd = sp->cmd; @@ -931,37 +1628,45 @@ qla2x00_start_iocbs(srb_t *sp)  	device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);  	struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; -	/* Adjust ring index. */ -	req->ring_index++; -	if (req->ring_index == req->length) { -		req->ring_index = 0; -		req->ring_ptr = req->ring; -	} else -		req->ring_ptr++; - -	/* Set chip new ring index. */ -	if (ha->mqenable) { -		WRT_REG_DWORD(®->isp25mq.req_q_in, req->ring_index); -		RD_REG_DWORD(&ioreg->hccr); -	} else if (IS_FWI2_CAPABLE(ha)) { -		WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); -		RD_REG_DWORD_RELAXED(®->isp24.req_q_in); +	if (IS_QLA82XX(ha)) { +		qla82xx_start_iocbs(sp);  	} else { -		WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), req->ring_index); -		RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); +		/* Adjust ring index. */ +		req->ring_index++; +		if (req->ring_index == req->length) { +			req->ring_index = 0; +			req->ring_ptr = req->ring; +		} else +			req->ring_ptr++; + +		/* Set chip new ring index. */ +		if (ha->mqenable) { +			WRT_REG_DWORD(®->isp25mq.req_q_in, req->ring_index); +			RD_REG_DWORD(&ioreg->hccr); +		} else if (IS_QLA82XX(ha)) { +			qla82xx_start_iocbs(sp); +		} else if (IS_FWI2_CAPABLE(ha)) { +			WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); +			RD_REG_DWORD_RELAXED(®->isp24.req_q_in); +		} else { +			WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), +				req->ring_index); +			RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); +		}  	}  }  static void  qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)  { -	struct srb_logio *lio = sp->ctx; +	struct srb_ctx *ctx = sp->ctx; +	struct srb_iocb *lio = ctx->u.iocb_cmd;  	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;  	logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); -	if (lio->flags & SRB_LOGIN_COND_PLOGI) +	if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI)  		logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI); -	if (lio->flags & SRB_LOGIN_SKIP_PRLI) +	if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI)  		logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI);  	logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);  	logio->port_id[0] = sp->fcport->d_id.b.al_pa; @@ -974,14 +1679,15 @@ static void  qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx)  {  	struct qla_hw_data *ha = sp->fcport->vha->hw; -	struct srb_logio *lio = sp->ctx; +	struct srb_ctx *ctx = sp->ctx; +	struct srb_iocb *lio = ctx->u.iocb_cmd;  	uint16_t opts;  	mbx->entry_type = MBX_IOCB_TYPE;;  	SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);  	mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT); -	opts = lio->flags & SRB_LOGIN_COND_PLOGI ? BIT_0: 0; -	opts |= lio->flags & SRB_LOGIN_SKIP_PRLI ? BIT_1: 0; +	opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0; +	opts |= lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI ? BIT_1 : 0;  	if (HAS_EXTENDED_IDS(ha)) {  		mbx->mb1 = cpu_to_le16(sp->fcport->loop_id);  		mbx->mb10 = cpu_to_le16(opts); @@ -1026,9 +1732,97 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)  }  static void +qla24xx_adisc_iocb(srb_t *sp, struct logio_entry_24xx *logio) +{ +	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; +	logio->control_flags = cpu_to_le16(LCF_COMMAND_ADISC); +	logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); +	logio->vp_index = sp->fcport->vp_idx; +} + +static void +qla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx) +{ +	struct qla_hw_data *ha = sp->fcport->vha->hw; + +	mbx->entry_type = MBX_IOCB_TYPE; +	SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); +	mbx->mb0 = cpu_to_le16(MBC_GET_PORT_DATABASE); +	if (HAS_EXTENDED_IDS(ha)) { +		mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); +		mbx->mb10 = cpu_to_le16(BIT_0); +	} else { +		mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | BIT_0); +	} +	mbx->mb2 = cpu_to_le16(MSW(ha->async_pd_dma)); +	mbx->mb3 = cpu_to_le16(LSW(ha->async_pd_dma)); +	mbx->mb6 = cpu_to_le16(MSW(MSD(ha->async_pd_dma))); +	mbx->mb7 = cpu_to_le16(LSW(MSD(ha->async_pd_dma))); +	mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); +} + +static void +qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) +{ +	uint32_t flags; +	unsigned int lun; +	struct fc_port *fcport = sp->fcport; +	scsi_qla_host_t *vha = fcport->vha; +	struct qla_hw_data *ha = vha->hw; +	struct srb_ctx *ctx = sp->ctx; +	struct srb_iocb *iocb = ctx->u.iocb_cmd; +	struct req_que *req = vha->req; + +	flags = iocb->u.tmf.flags; +	lun = iocb->u.tmf.lun; + +	tsk->entry_type = TSK_MGMT_IOCB_TYPE; +	tsk->entry_count = 1; +	tsk->handle = MAKE_HANDLE(req->id, tsk->handle); +	tsk->nport_handle = cpu_to_le16(fcport->loop_id); +	tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); +	tsk->control_flags = cpu_to_le32(flags); +	tsk->port_id[0] = fcport->d_id.b.al_pa; +	tsk->port_id[1] = fcport->d_id.b.area; +	tsk->port_id[2] = fcport->d_id.b.domain; +	tsk->vp_index = fcport->vp_idx; + +	if (flags == TCF_LUN_RESET) { +		int_to_scsilun(lun, &tsk->lun); +		host_to_fcp_swap((uint8_t *)&tsk->lun, +			sizeof(tsk->lun)); +	} +} + +static void +qla24xx_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk) +{ +	uint16_t lun; +	uint8_t modif; +	struct fc_port *fcport = sp->fcport; +	scsi_qla_host_t *vha = fcport->vha; +	struct srb_ctx *ctx = sp->ctx; +	struct srb_iocb *iocb = ctx->u.iocb_cmd; +	struct req_que *req = vha->req; + +	lun = iocb->u.marker.lun; +	modif = iocb->u.marker.modif; +	mrk->entry_type = MARKER_TYPE; +	mrk->modifier = modif; +	if (modif !=  MK_SYNC_ALL) { +		mrk->nport_handle = cpu_to_le16(fcport->loop_id); +		mrk->lun[1] = LSB(lun); +		mrk->lun[2] = MSB(lun); +		host_to_fcp_swap(mrk->lun, sizeof(mrk->lun)); +		mrk->vp_index = vha->vp_idx; +		mrk->handle = MAKE_HANDLE(req->id, mrk->handle); +	} +} + +static void  qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)  { -	struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job; +	struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;          els_iocb->entry_type = ELS_IOCB_TYPE;          els_iocb->entry_count = 1; @@ -1041,8 +1835,10 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)          els_iocb->sof_type = EST_SOFI3;          els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); -        els_iocb->opcode =(((struct srb_bsg*)sp->ctx)->ctx.type == SRB_ELS_CMD_RPT) ? -	    bsg_job->request->rqst_data.r_els.els_code : bsg_job->request->rqst_data.h_els.command_code; +	els_iocb->opcode = +	    (((struct srb_ctx *)sp->ctx)->type == SRB_ELS_CMD_RPT) ? +	    bsg_job->request->rqst_data.r_els.els_code : +	    bsg_job->request->rqst_data.h_els.command_code;          els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;          els_iocb->port_id[1] = sp->fcport->d_id.b.area;          els_iocb->port_id[2] = sp->fcport->d_id.b.domain; @@ -1076,7 +1872,7 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)  	int index;  	uint16_t tot_dsds;          scsi_qla_host_t *vha = sp->fcport->vha; -	struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job; +	struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;  	int loop_iterartion = 0;  	int cont_iocb_prsnt = 0;  	int entry_count = 1; @@ -1157,12 +1953,12 @@ qla2x00_start_sp(srb_t *sp)  	switch (ctx->type) {  	case SRB_LOGIN_CMD:  		IS_FWI2_CAPABLE(ha) ? -		    qla24xx_login_iocb(sp, pkt): +		    qla24xx_login_iocb(sp, pkt) :  		    qla2x00_login_iocb(sp, pkt);  		break;  	case SRB_LOGOUT_CMD:  		IS_FWI2_CAPABLE(ha) ? -		    qla24xx_logout_iocb(sp, pkt): +		    qla24xx_logout_iocb(sp, pkt) :  		    qla2x00_logout_iocb(sp, pkt);  		break;  	case SRB_ELS_CMD_RPT: @@ -1172,6 +1968,17 @@ qla2x00_start_sp(srb_t *sp)  	case SRB_CT_CMD:  		qla24xx_ct_iocb(sp, pkt);  		break; +	case SRB_ADISC_CMD: +		IS_FWI2_CAPABLE(ha) ? +		    qla24xx_adisc_iocb(sp, pkt) : +		    qla2x00_adisc_iocb(sp, pkt); +		break; +	case SRB_TM_CMD: +		qla24xx_tm_iocb(sp, pkt); +		break; +	case SRB_MARKER_CMD: +		qla24xx_marker_iocb(sp, pkt); +		break;  	default:  		break;  	} diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index db539b0c3da..be3d8bed2ec 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -10,6 +10,7 @@  #include <linux/slab.h>  #include <scsi/scsi_tcq.h>  #include <scsi/scsi_bsg_fc.h> +#include <scsi/scsi_eh.h>  static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);  static void qla2x00_process_completed_request(struct scsi_qla_host *, @@ -326,7 +327,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)  	/* Setup to process RIO completion. */  	handle_cnt = 0; -	if (IS_QLA81XX(ha)) +	if (IS_QLA8XXX_TYPE(ha))  		goto skip_rio;  	switch (mb[0]) {  	case MBA_SCSI_COMPLETION: @@ -544,7 +545,7 @@ skip_rio:  		if (IS_QLA2100(ha))  			break; -		if (IS_QLA81XX(ha)) +		if (IS_QLA8XXX_TYPE(ha))  			DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "  			    "%04x\n", vha->host_no, mb[1], mb[2], mb[3]));  		else @@ -845,7 +846,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,  		qla2x00_sp_compl(ha, sp);  	} else {  		DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion" -			" handle(%d)\n", vha->host_no, req->id, index)); +			" handle(0x%x)\n", vha->host_no, req->id, index));  		qla_printk(KERN_WARNING, ha,  		    "Invalid ISP SCSI completion handle\n"); @@ -895,36 +896,26 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,  {  	const char func[] = "MBX-IOCB";  	const char *type; -	struct qla_hw_data *ha = vha->hw;  	fc_port_t *fcport;  	srb_t *sp; -	struct srb_logio *lio; -	uint16_t data[2]; +	struct srb_iocb *lio; +	struct srb_ctx *ctx; +	uint16_t *data; +	uint16_t status;  	sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);  	if (!sp)  		return; -	type = NULL; -	lio = sp->ctx; -	switch (lio->ctx.type) { -	case SRB_LOGIN_CMD: -		type = "login"; -		break; -	case SRB_LOGOUT_CMD: -		type = "logout"; -		break; -	default: -		qla_printk(KERN_WARNING, ha, -		    "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, -		    lio->ctx.type); -		return; -	} - -	del_timer(&lio->ctx.timer); +	ctx = sp->ctx; +	lio = ctx->u.iocb_cmd; +	type = ctx->name;  	fcport = sp->fcport; +	data = lio->u.logio.data; -	data[0] = data[1] = 0; +	data[0] = MBS_COMMAND_ERROR; +	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? +	    QLA_LOGIO_LOGIN_RETRIED : 0;  	if (mbx->entry_status) {  		DEBUG2(printk(KERN_WARNING  		    "scsi(%ld:%x): Async-%s error entry - entry-status=%x " @@ -935,23 +926,28 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,  		    le16_to_cpu(mbx->status_flags)));  		DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx))); -		data[0] = MBS_COMMAND_ERROR; -		data[1] = lio->flags & SRB_LOGIN_RETRIED ? -		    QLA_LOGIO_LOGIN_RETRIED: 0; -		goto done_post_logio_done_work; +		goto logio_done;  	} -	if (!mbx->status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { +	status = le16_to_cpu(mbx->status); +	if (status == 0x30 && ctx->type == SRB_LOGIN_CMD && +	    le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) +		status = 0; +	if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {  		DEBUG2(printk(KERN_DEBUG  		    "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n",  		    fcport->vha->host_no, sp->handle, type,  		    le16_to_cpu(mbx->mb1)));  		data[0] = MBS_COMMAND_COMPLETE; -		if (lio->ctx.type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb1) & BIT_1) -			fcport->flags |= FCF_FCP2_DEVICE; - -		goto done_post_logio_done_work; +		if (ctx->type == SRB_LOGIN_CMD) { +			fcport->port_type = FCT_TARGET; +			if (le16_to_cpu(mbx->mb1) & BIT_0) +				fcport->port_type = FCT_INITIATOR; +			if (le16_to_cpu(mbx->mb1) & BIT_1) +				fcport->flags |= FCF_FCP2_DEVICE; +		} +		goto logio_done;  	}  	data[0] = le16_to_cpu(mbx->mb0); @@ -963,25 +959,19 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,  		break;  	default:  		data[0] = MBS_COMMAND_ERROR; -		data[1] = lio->flags & SRB_LOGIN_RETRIED ? -		    QLA_LOGIO_LOGIN_RETRIED: 0;  		break;  	}  	DEBUG2(printk(KERN_WARNING  	    "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x "  	    "mb6=%x mb7=%x.\n", -	    fcport->vha->host_no, sp->handle, type, le16_to_cpu(mbx->status), +	    fcport->vha->host_no, sp->handle, type, status,  	    le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),  	    le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),  	    le16_to_cpu(mbx->mb7))); -done_post_logio_done_work: -	lio->ctx.type == SRB_LOGIN_CMD ? -	    qla2x00_post_async_login_done_work(fcport->vha, fcport, data): -	    qla2x00_post_async_logout_done_work(fcport->vha, fcport, data); - -	lio->ctx.free(sp); +logio_done: +	lio->done(sp);  }  static void @@ -992,7 +982,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,  	const char *type;  	struct qla_hw_data *ha = vha->hw;  	srb_t *sp; -	struct srb_bsg *sp_bsg; +	struct srb_ctx *sp_bsg;  	struct fc_bsg_job *bsg_job;  	uint16_t comp_status;  	uint32_t fw_status[3]; @@ -1001,11 +991,11 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,  	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);  	if (!sp)  		return; -	sp_bsg = (struct srb_bsg*)sp->ctx; -	bsg_job = sp_bsg->bsg_job; +	sp_bsg = sp->ctx; +	bsg_job = sp_bsg->u.bsg_job;  	type = NULL; -	switch (sp_bsg->ctx.type) { +	switch (sp_bsg->type) {  	case SRB_ELS_CMD_RPT:  	case SRB_ELS_CMD_HST:  		type = "els"; @@ -1016,7 +1006,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,  	default:  		qla_printk(KERN_WARNING, ha,  		    "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, -		    sp_bsg->ctx.type); +		    sp_bsg->type);  		return;  	} @@ -1070,8 +1060,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,  	dma_unmap_sg(&ha->pdev->dev,  	    bsg_job->reply_payload.sg_list,  	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); -	if ((sp_bsg->ctx.type == SRB_ELS_CMD_HST) || -	    (sp_bsg->ctx.type == SRB_CT_CMD)) +	if ((sp_bsg->type == SRB_ELS_CMD_HST) || +	    (sp_bsg->type == SRB_CT_CMD))  		kfree(sp->fcport);  	kfree(sp->ctx);  	mempool_free(sp, ha->srb_mempool); @@ -1084,37 +1074,26 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,  {  	const char func[] = "LOGIO-IOCB";  	const char *type; -	struct qla_hw_data *ha = vha->hw;  	fc_port_t *fcport;  	srb_t *sp; -	struct srb_logio *lio; -	uint16_t data[2]; +	struct srb_iocb *lio; +	struct srb_ctx *ctx; +	uint16_t *data;  	uint32_t iop[2];  	sp = qla2x00_get_sp_from_handle(vha, func, req, logio);  	if (!sp)  		return; -	type = NULL; -	lio = sp->ctx; -	switch (lio->ctx.type) { -	case SRB_LOGIN_CMD: -		type = "login"; -		break; -	case SRB_LOGOUT_CMD: -		type = "logout"; -		break; -	default: -		qla_printk(KERN_WARNING, ha, -		    "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, -		    lio->ctx.type); -		return; -	} - -	del_timer(&lio->ctx.timer); +	ctx = sp->ctx; +	lio = ctx->u.iocb_cmd; +	type = ctx->name;  	fcport = sp->fcport; +	data = lio->u.logio.data; -	data[0] = data[1] = 0; +	data[0] = MBS_COMMAND_ERROR; +	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? +		QLA_LOGIO_LOGIN_RETRIED : 0;  	if (logio->entry_status) {  		DEBUG2(printk(KERN_WARNING  		    "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n", @@ -1122,10 +1101,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,  		    logio->entry_status));  		DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio))); -		data[0] = MBS_COMMAND_ERROR; -		data[1] = lio->flags & SRB_LOGIN_RETRIED ? -		    QLA_LOGIO_LOGIN_RETRIED: 0; -		goto done_post_logio_done_work; +		goto logio_done;  	}  	if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { @@ -1135,8 +1111,8 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,  		    le32_to_cpu(logio->io_parameter[0])));  		data[0] = MBS_COMMAND_COMPLETE; -		if (lio->ctx.type == SRB_LOGOUT_CMD) -			goto done_post_logio_done_work; +		if (ctx->type != SRB_LOGIN_CMD) +			goto logio_done;  		iop[0] = le32_to_cpu(logio->io_parameter[0]);  		if (iop[0] & BIT_4) { @@ -1151,7 +1127,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,  		if (logio->io_parameter[9] || logio->io_parameter[10])  			fcport->supported_classes |= FC_COS_CLASS3; -		goto done_post_logio_done_work; +		goto logio_done;  	}  	iop[0] = le32_to_cpu(logio->io_parameter[0]); @@ -1172,8 +1148,6 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,  		/* Fall through. */  	default:  		data[0] = MBS_COMMAND_ERROR; -		data[1] = lio->flags & SRB_LOGIN_RETRIED ? -		    QLA_LOGIO_LOGIN_RETRIED: 0;  		break;  	} @@ -1184,12 +1158,101 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,  	    le32_to_cpu(logio->io_parameter[0]),  	    le32_to_cpu(logio->io_parameter[1]))); -done_post_logio_done_work: -	lio->ctx.type == SRB_LOGIN_CMD ? -	    qla2x00_post_async_login_done_work(fcport->vha, fcport, data): -	    qla2x00_post_async_logout_done_work(fcport->vha, fcport, data); +logio_done: +	lio->done(sp); +} + +static void +qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, +    struct tsk_mgmt_entry *tsk) +{ +	const char func[] = "TMF-IOCB"; +	const char *type; +	fc_port_t *fcport; +	srb_t *sp; +	struct srb_iocb *iocb; +	struct srb_ctx *ctx; +	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk; +	int error = 1; + +	sp = qla2x00_get_sp_from_handle(vha, func, req, tsk); +	if (!sp) +		return; + +	ctx = sp->ctx; +	iocb = ctx->u.iocb_cmd; +	type = ctx->name; +	fcport = sp->fcport; -	lio->ctx.free(sp); +	if (sts->entry_status) { +		DEBUG2(printk(KERN_WARNING +		    "scsi(%ld:%x): Async-%s error - entry-status(%x).\n", +		    fcport->vha->host_no, sp->handle, type, +		    sts->entry_status)); +	} else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { +		DEBUG2(printk(KERN_WARNING +		    "scsi(%ld:%x): Async-%s error - completion status(%x).\n", +		    fcport->vha->host_no, sp->handle, type, +		    sts->comp_status)); +	} else if (!(le16_to_cpu(sts->scsi_status) & +	    SS_RESPONSE_INFO_LEN_VALID)) { +		DEBUG2(printk(KERN_WARNING +		    "scsi(%ld:%x): Async-%s error - no response info(%x).\n", +		    fcport->vha->host_no, sp->handle, type, +		    sts->scsi_status)); +	} else if (le32_to_cpu(sts->rsp_data_len) < 4) { +		DEBUG2(printk(KERN_WARNING +		    "scsi(%ld:%x): Async-%s error - not enough response(%d).\n", +		    fcport->vha->host_no, sp->handle, type, +		    sts->rsp_data_len)); +	} else if (sts->data[3]) { +		DEBUG2(printk(KERN_WARNING +		    "scsi(%ld:%x): Async-%s error - response(%x).\n", +		    fcport->vha->host_no, sp->handle, type, +		    sts->data[3])); +	} else { +		error = 0; +	} + +	if (error) { +		iocb->u.tmf.data = error; +		DEBUG2(qla2x00_dump_buffer((uint8_t *)sts, sizeof(*sts))); +	} + +	iocb->done(sp); +} + +static void +qla24xx_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, +    struct mrk_entry_24xx *mrk) +{ +	const char func[] = "MRK-IOCB"; +	const char *type; +	fc_port_t *fcport; +	srb_t *sp; +	struct srb_iocb *iocb; +	struct srb_ctx *ctx; +	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)mrk; + +	sp = qla2x00_get_sp_from_handle(vha, func, req, mrk); +	if (!sp) +		return; + +	ctx = sp->ctx; +	iocb = ctx->u.iocb_cmd; +	type = ctx->name; +	fcport = sp->fcport; + +	if (sts->entry_status) { +		iocb->u.marker.data = 1; +		DEBUG2(printk(KERN_WARNING +		    "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n", +		    fcport->vha->host_no, sp->handle, type, +		    sts->entry_status)); +		DEBUG2(qla2x00_dump_buffer((uint8_t *)mrk, sizeof(*sts))); +	} + +	iocb->done(sp);  }  /** @@ -1256,6 +1319,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp)  		case MBX_IOCB_TYPE:  			qla2x00_mbx_iocb_entry(vha, rsp->req,  			    (struct mbx_entry *)pkt); +			break;  		default:  			/* Type Not Supported. */  			DEBUG4(printk(KERN_WARNING @@ -1301,6 +1365,78 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len,  		DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len));  } +struct scsi_dif_tuple { +	__be16 guard;       /* Checksum */ +	__be16 app_tag;         /* APPL identifer */ +	__be32 ref_tag;         /* Target LBA or indirect LBA */ +}; + +/* + * Checks the guard or meta-data for the type of error + * detected by the HBA. In case of errors, we set the + * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST + * to indicate to the kernel that the HBA detected error. + */ +static inline void +qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) +{ +	struct scsi_cmnd *cmd = sp->cmd; +	struct scsi_dif_tuple	*ep = +			(struct scsi_dif_tuple *)&sts24->data[20]; +	struct scsi_dif_tuple	*ap = +			(struct scsi_dif_tuple *)&sts24->data[12]; +	uint32_t	e_ref_tag, a_ref_tag; +	uint16_t	e_app_tag, a_app_tag; +	uint16_t	e_guard, a_guard; + +	e_ref_tag = be32_to_cpu(ep->ref_tag); +	a_ref_tag = be32_to_cpu(ap->ref_tag); +	e_app_tag = be16_to_cpu(ep->app_tag); +	a_app_tag = be16_to_cpu(ap->app_tag); +	e_guard = be16_to_cpu(ep->guard); +	a_guard = be16_to_cpu(ap->guard); + +	DEBUG18(printk(KERN_DEBUG +	    "%s(): iocb(s) %p Returned STATUS\n", __func__, sts24)); + +	DEBUG18(printk(KERN_ERR "DIF ERROR in cmd 0x%x lba 0x%llx act ref" +	    " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app" +	    " tag=0x%x, act guard=0x%x, exp guard=0x%x\n", +	    cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag, +	    a_app_tag, e_app_tag, a_guard, e_guard)); + + +	/* check guard */ +	if (e_guard != a_guard) { +		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, +		    0x10, 0x1); +		set_driver_byte(cmd, DRIVER_SENSE); +		set_host_byte(cmd, DID_ABORT); +		cmd->result |= SAM_STAT_CHECK_CONDITION << 1; +		return; +	} + +	/* check appl tag */ +	if (e_app_tag != a_app_tag) { +		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, +		    0x10, 0x2); +		set_driver_byte(cmd, DRIVER_SENSE); +		set_host_byte(cmd, DID_ABORT); +		cmd->result |= SAM_STAT_CHECK_CONDITION << 1; +		return; +	} + +	/* check ref tag */ +	if (e_ref_tag != a_ref_tag) { +		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, +		    0x10, 0x3); +		set_driver_byte(cmd, DRIVER_SENSE); +		set_host_byte(cmd, DID_ABORT); +		cmd->result |= SAM_STAT_CHECK_CONDITION << 1; +		return; +	} +} +  /**   * qla2x00_status_entry() - Process a Status IOCB entry.   * @ha: SCSI driver HA context @@ -1316,6 +1452,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  	struct sts_entry_24xx *sts24;  	uint16_t	comp_status;  	uint16_t	scsi_status; +	uint16_t	ox_id;  	uint8_t		lscsi_status;  	int32_t		resid;  	uint32_t	sense_len, rsp_info_len, resid_len, fw_resid_len; @@ -1324,6 +1461,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  	uint32_t handle;  	uint16_t que;  	struct req_que *req; +	int logit = 1;  	sts = (sts_entry_t *) pkt;  	sts24 = (struct sts_entry_24xx *) pkt; @@ -1337,6 +1475,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  	handle = (uint32_t) LSW(sts->handle);  	que = MSW(sts->handle);  	req = ha->req_q_map[que]; +  	/* Fast path completion. */  	if (comp_status == CS_COMPLETE && scsi_status == 0) {  		qla2x00_process_completed_request(vha, req, handle); @@ -1352,9 +1491,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  		sp = NULL;  	if (sp == NULL) { -		DEBUG2(printk("scsi(%ld): Status Entry invalid handle.\n", -		    vha->host_no)); -		qla_printk(KERN_WARNING, ha, "Status Entry invalid handle.\n"); +		qla_printk(KERN_WARNING, ha, +		    "scsi(%ld): Invalid status handle (0x%x).\n", vha->host_no, +		    sts->handle);  		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);  		qla2xxx_wake_dpc(vha); @@ -1362,10 +1501,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  	}  	cp = sp->cmd;  	if (cp == NULL) { -		DEBUG2(printk("scsi(%ld): Command already returned back to OS " -		    "pkt->handle=%d sp=%p.\n", vha->host_no, handle, sp));  		qla_printk(KERN_WARNING, ha, -		    "Command is NULL: already returned to OS (sp=%p)\n", sp); +		    "scsi(%ld): Command already returned (0x%x/%p).\n", +		    vha->host_no, sts->handle, sp);  		return;  	} @@ -1374,6 +1512,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  	fcport = sp->fcport; +	ox_id = 0;  	sense_len = rsp_info_len = resid_len = fw_resid_len = 0;  	if (IS_FWI2_CAPABLE(ha)) {  		if (scsi_status & SS_SENSE_LEN_VALID) @@ -1387,6 +1526,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  		rsp_info = sts24->data;  		sense_data = sts24->data;  		host_to_fcp_swap(sts24->data, sizeof(sts24->data)); +		ox_id = le16_to_cpu(sts24->ox_id);  	} else {  		if (scsi_status & SS_SENSE_LEN_VALID)  			sense_len = le16_to_cpu(sts->req_sense_length); @@ -1403,17 +1543,13 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  		if (IS_FWI2_CAPABLE(ha))  			sense_data += rsp_info_len;  		if (rsp_info_len > 3 && rsp_info[3]) { -			DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol " -			    "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..." -			    "retrying command\n", vha->host_no, -			    cp->device->channel, cp->device->id, -			    cp->device->lun, rsp_info_len, rsp_info[0], -			    rsp_info[1], rsp_info[2], rsp_info[3], rsp_info[4], -			    rsp_info[5], rsp_info[6], rsp_info[7])); +			DEBUG2(qla_printk(KERN_INFO, ha, +			    "scsi(%ld:%d:%d): FCP I/O protocol failure " +			    "(0x%x/0x%x).\n", vha->host_no, cp->device->id, +			    cp->device->lun, rsp_info_len, rsp_info[3]));  			cp->result = DID_BUS_BUSY << 16; -			qla2x00_sp_compl(ha, sp); -			return; +			goto out;  		}  	} @@ -1440,12 +1576,10 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  			    ((unsigned)(scsi_bufflen(cp) - resid) <  			     cp->underflow)) {  				qla_printk(KERN_INFO, ha, -					   "scsi(%ld:%d:%d:%d): Mid-layer underflow " -					   "detected (%x of %x bytes)...returning " -					   "error status.\n", vha->host_no, -					   cp->device->channel, cp->device->id, -					   cp->device->lun, resid, -					   scsi_bufflen(cp)); +				    "scsi(%ld:%d:%d): Mid-layer underflow " +				    "detected (0x%x of 0x%x bytes).\n", +				    vha->host_no, cp->device->id, +				    cp->device->lun, resid, scsi_bufflen(cp));  				cp->result = DID_ERROR << 16;  				break; @@ -1454,12 +1588,12 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  		cp->result = DID_OK << 16 | lscsi_status;  		if (lscsi_status == SAM_STAT_TASK_SET_FULL) { -			DEBUG2(printk(KERN_INFO -			    "scsi(%ld): QUEUE FULL status detected " -			    "0x%x-0x%x.\n", vha->host_no, comp_status, -			    scsi_status)); +			DEBUG2(qla_printk(KERN_INFO, ha, +			    "scsi(%ld:%d:%d) QUEUE FULL detected.\n", +			    vha->host_no, cp->device->id, cp->device->lun));  			break;  		} +		logit = 0;  		if (lscsi_status != SS_CHECK_CONDITION)  			break; @@ -1471,23 +1605,14 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  		break;  	case CS_DATA_UNDERRUN: -		DEBUG2(printk(KERN_INFO -		    "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x. " -		    "resid=0x%x fw_resid=0x%x cdb=0x%x os_underflow=0x%x\n", -		    vha->host_no, cp->device->id, cp->device->lun, comp_status, -		    scsi_status, resid_len, fw_resid_len, cp->cmnd[0], -		    cp->underflow)); -  		/* Use F/W calculated residual length. */  		resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;  		scsi_set_resid(cp, resid);  		if (scsi_status & SS_RESIDUAL_UNDER) {  			if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) { -				DEBUG2(printk( -				    "scsi(%ld:%d:%d:%d) Dropped frame(s) " -				    "detected (%x of %x bytes)...residual " -				    "length mismatch...retrying command.\n", -				    vha->host_no, cp->device->channel, +				DEBUG2(qla_printk(KERN_INFO, ha, +				    "scsi(%ld:%d:%d) Dropped frame(s) detected " +				    "(0x%x of 0x%x bytes).\n", vha->host_no,  				    cp->device->id, cp->device->lun, resid,  				    scsi_bufflen(cp))); @@ -1499,21 +1624,18 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  			    ((unsigned)(scsi_bufflen(cp) - resid) <  			    cp->underflow)) {  				qla_printk(KERN_INFO, ha, -				    "scsi(%ld:%d:%d:%d): Mid-layer underflow " -				    "detected (%x of %x bytes)...returning " -				    "error status.\n", vha->host_no, -				    cp->device->channel, cp->device->id, +				    "scsi(%ld:%d:%d): Mid-layer underflow " +				    "detected (0x%x of 0x%x bytes).\n", +				    vha->host_no, cp->device->id,  				    cp->device->lun, resid, scsi_bufflen(cp));  				cp->result = DID_ERROR << 16;  				break;  			}  		} else if (!lscsi_status) { -			DEBUG2(printk( -			    "scsi(%ld:%d:%d:%d) Dropped frame(s) detected " -			    "(%x of %x bytes)...firmware reported underrun..." -			    "retrying command.\n", vha->host_no, -			    cp->device->channel, cp->device->id, +			DEBUG2(qla_printk(KERN_INFO, ha, +			    "scsi(%ld:%d:%d) Dropped frame(s) detected (0x%x " +			    "of 0x%x bytes).\n", vha->host_no, cp->device->id,  			    cp->device->lun, resid, scsi_bufflen(cp)));  			cp->result = DID_ERROR << 16; @@ -1521,6 +1643,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  		}  		cp->result = DID_OK << 16 | lscsi_status; +		logit = 0;  		/*  		 * Check to see if SCSI Status is non zero. If so report SCSI @@ -1528,10 +1651,11 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  		 */  		if (lscsi_status != 0) {  			if (lscsi_status == SAM_STAT_TASK_SET_FULL) { -				DEBUG2(printk(KERN_INFO -				    "scsi(%ld): QUEUE FULL status detected " -				    "0x%x-0x%x.\n", vha->host_no, comp_status, -				    scsi_status)); +				DEBUG2(qla_printk(KERN_INFO, ha, +				    "scsi(%ld:%d:%d) QUEUE FULL detected.\n", +				    vha->host_no, cp->device->id, +				    cp->device->lun)); +				logit = 1;  				break;  			}  			if (lscsi_status != SS_CHECK_CONDITION) @@ -1545,109 +1669,60 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)  		}  		break; -	case CS_DATA_OVERRUN: -		DEBUG2(printk(KERN_INFO -		    "scsi(%ld:%d:%d): OVERRUN status detected 0x%x-0x%x\n", -		    vha->host_no, cp->device->id, cp->device->lun, comp_status, -		    scsi_status)); -		DEBUG2(printk(KERN_INFO -		    "CDB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", -		    cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3], -		    cp->cmnd[4], cp->cmnd[5])); -		DEBUG2(printk(KERN_INFO -		    "PID=0x%lx req=0x%x xtra=0x%x -- returning DID_ERROR " -		    "status!\n", -		    cp->serial_number, scsi_bufflen(cp), resid_len)); - -		cp->result = DID_ERROR << 16; -		break; -  	case CS_PORT_LOGGED_OUT:  	case CS_PORT_CONFIG_CHG:  	case CS_PORT_BUSY:  	case CS_INCOMPLETE:  	case CS_PORT_UNAVAILABLE: -		/* -		 * If the port is in Target Down state, return all IOs for this -		 * Target with DID_NO_CONNECT ELSE Queue the IOs in the -		 * retry_queue. -		 */ -		DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down " -		    "pid=%ld, compl status=0x%x, port state=0x%x\n", -		    vha->host_no, cp->device->id, cp->device->lun, -		    cp->serial_number, comp_status, -		    atomic_read(&fcport->state))); - +	case CS_TIMEOUT:  		/*  		 * We are going to have the fc class block the rport  		 * while we try to recover so instruct the mid layer  		 * to requeue until the class decides how to handle this.  		 */  		cp->result = DID_TRANSPORT_DISRUPTED << 16; + +		if (comp_status == CS_TIMEOUT) { +			if (IS_FWI2_CAPABLE(ha)) +				break; +			else if ((le16_to_cpu(sts->status_flags) & +			    SF_LOGOUT_SENT) == 0) +				break; +		} + +		DEBUG2(qla_printk(KERN_INFO, ha, +			"scsi(%ld:%d:%d) Port down status: port-state=0x%x\n", +			vha->host_no, cp->device->id, cp->device->lun, +			atomic_read(&fcport->state))); +  		if (atomic_read(&fcport->state) == FCS_ONLINE)  			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);  		break;  	case CS_RESET: -		DEBUG2(printk(KERN_INFO -		    "scsi(%ld): RESET status detected 0x%x-0x%x.\n", -		    vha->host_no, comp_status, scsi_status)); - -		cp->result = DID_RESET << 16; -		break; -  	case CS_ABORTED: -		/* -		 * hv2.19.12 - DID_ABORT does not retry the request if we -		 * aborted this request then abort otherwise it must be a -		 * reset. -		 */ -		DEBUG2(printk(KERN_INFO -		    "scsi(%ld): ABORT status detected 0x%x-0x%x.\n", -		    vha->host_no, comp_status, scsi_status)); -  		cp->result = DID_RESET << 16;  		break; -	case CS_TIMEOUT: -		/* -		 * We are going to have the fc class block the rport -		 * while we try to recover so instruct the mid layer -		 * to requeue until the class decides how to handle this. -		 */ -		cp->result = DID_TRANSPORT_DISRUPTED << 16; - -		if (IS_FWI2_CAPABLE(ha)) { -			DEBUG2(printk(KERN_INFO -			    "scsi(%ld:%d:%d:%d): TIMEOUT status detected " -			    "0x%x-0x%x\n", vha->host_no, cp->device->channel, -			    cp->device->id, cp->device->lun, comp_status, -			    scsi_status)); -			break; -		} -		DEBUG2(printk(KERN_INFO -		    "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x " -		    "sflags=%x.\n", vha->host_no, cp->device->channel, -		    cp->device->id, cp->device->lun, comp_status, scsi_status, -		    le16_to_cpu(sts->status_flags))); - -		/* Check to see if logout occurred. */ -		if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT)) -			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1); +	case CS_DIF_ERROR: +		qla2x00_handle_dif_error(sp, sts24);  		break; -  	default: -		DEBUG3(printk("scsi(%ld): Error detected (unknown status) " -		    "0x%x-0x%x.\n", vha->host_no, comp_status, scsi_status)); -		qla_printk(KERN_INFO, ha, -		    "Unknown status detected 0x%x-0x%x.\n", -		    comp_status, scsi_status); -  		cp->result = DID_ERROR << 16;  		break;  	} -	/* Place command on done queue. */ +out: +	if (logit) +		DEBUG2(qla_printk(KERN_INFO, ha, +		    "scsi(%ld:%d:%d) FCP command status: 0x%x-0x%x (0x%x) " +		    "oxid=0x%x ser=0x%lx cdb=%02x%02x%02x len=0x%x " +		    "rsp_info=0x%x resid=0x%x fw_resid=0x%x\n", vha->host_no, +		    cp->device->id, cp->device->lun, comp_status, scsi_status, +		    cp->result, ox_id, cp->serial_number, cp->cmnd[0], +		    cp->cmnd[1], cp->cmnd[2], scsi_bufflen(cp), rsp_info_len, +		    resid_len, fw_resid_len)); +  	if (rsp->status_srb == NULL)  		qla2x00_sp_compl(ha, sp);  } @@ -1806,6 +1881,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,  	struct rsp_que *rsp)  {  	struct sts_entry_24xx *pkt; +	struct qla_hw_data *ha = vha->hw;  	if (!vha->flags.online)  		return; @@ -1846,6 +1922,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,  			qla24xx_logio_entry(vha, rsp->req,  			    (struct logio_entry_24xx *)pkt);  			break; +		case TSK_MGMT_IOCB_TYPE: +			qla24xx_tm_iocb_entry(vha, rsp->req, +			    (struct tsk_mgmt_entry *)pkt); +			break; +		case MARKER_TYPE: +			qla24xx_marker_iocb_entry(vha, rsp->req, +			    (struct mrk_entry_24xx *)pkt); +			break;                  case CT_IOCB_TYPE:  			qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);  			clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags); @@ -1866,7 +1950,11 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,  	}  	/* Adjust ring index */ -	WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index); +	if (IS_QLA82XX(ha)) { +		struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; +		WRT_REG_DWORD(®->rsp_q_out[0], rsp->ring_index); +	} else +		WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);  }  static void @@ -2169,6 +2257,11 @@ static struct qla_init_msix_entry msix_entries[3] = {  	{ "qla2xxx (multiq)", qla25xx_msix_rsp_q },  }; +static struct qla_init_msix_entry qla82xx_msix_entries[2] = { +	{ "qla2xxx (default)", qla82xx_msix_default }, +	{ "qla2xxx (rsp_q)", qla82xx_msix_rsp_q }, +}; +  static void  qla24xx_disable_msix(struct qla_hw_data *ha)  { @@ -2195,7 +2288,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)  	struct qla_msix_entry *qentry;  	entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count, -					GFP_KERNEL); +			GFP_KERNEL);  	if (!entries)  		return -ENOMEM; @@ -2240,8 +2333,15 @@ msix_failed:  	/* Enable MSI-X vectors for the base queue */  	for (i = 0; i < 2; i++) {  		qentry = &ha->msix_entries[i]; -		ret = request_irq(qentry->vector, msix_entries[i].handler, -					0, msix_entries[i].name, rsp); +		if (IS_QLA82XX(ha)) { +			ret = request_irq(qentry->vector, +				qla82xx_msix_entries[i].handler, +				0, qla82xx_msix_entries[i].name, rsp); +		} else { +			ret = request_irq(qentry->vector, +				msix_entries[i].handler, +				0, msix_entries[i].name, rsp); +		}  		if (ret) {  			qla_printk(KERN_WARNING, ha,  			"MSI-X: Unable to register handler -- %x/%d.\n", @@ -2272,7 +2372,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)  	/* If possible, enable MSI-X. */  	if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && -		!IS_QLA8432(ha) && !IS_QLA8001(ha)) +		!IS_QLA8432(ha) && !IS_QLA8XXX_TYPE(ha))  		goto skip_msi;  	if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP && @@ -2302,7 +2402,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)  		goto clear_risc_ints;  	}  	qla_printk(KERN_WARNING, ha, -	    "MSI-X: Falling back-to INTa mode -- %d.\n", ret); +	    "MSI-X: Falling back-to MSI mode -- %d.\n", ret);  skip_msix:  	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) && @@ -2313,7 +2413,9 @@ skip_msix:  	if (!ret) {  		DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));  		ha->flags.msi_enabled = 1; -	} +	} else +		qla_printk(KERN_WARNING, ha, +		    "MSI-X: Falling back-to INTa mode -- %d.\n", ret);  skip_msi:  	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, @@ -2331,7 +2433,7 @@ clear_risc_ints:  	 * FIXME: Noted that 8014s were being dropped during NK testing.  	 * Timing deltas during MSI-X/INTa transitions?  	 */ -	if (IS_QLA81XX(ha)) +	if (IS_QLA81XX(ha) || IS_QLA82XX(ha))  		goto fail;  	spin_lock_irq(&ha->hardware_lock);  	if (IS_FWI2_CAPABLE(ha)) { diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 42eb7ffd594..f3650d0434c 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -49,6 +49,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)  	if (ha->pdev->error_state > pci_channel_io_frozen)  		return QLA_FUNCTION_TIMEOUT; +	if (vha->device_flags & DFLG_DEV_FAILED) { +		DEBUG2_3_11(qla_printk(KERN_WARNING, ha, +			"%s(%ld): Device in failed state, " +			"timeout MBX Exiting.\n", +			__func__, base_vha->host_no)); +		return QLA_FUNCTION_TIMEOUT; +	} +  	reg = ha->iobase;  	io_lock_on = base_vha->flags.init_done; @@ -85,7 +93,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)  	spin_lock_irqsave(&ha->hardware_lock, flags);  	/* Load mailbox registers. */ -	if (IS_FWI2_CAPABLE(ha)) +	if (IS_QLA82XX(ha)) +		optr = (uint16_t __iomem *)®->isp82.mailbox_in[0]; +	else if (IS_FWI2_CAPABLE(ha) && !IS_QLA82XX(ha))  		optr = (uint16_t __iomem *)®->isp24.mailbox0;  	else  		optr = (uint16_t __iomem *)MAILBOX_REG(ha, ®->isp, 0); @@ -133,7 +143,18 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)  	if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) {  		set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); -		if (IS_FWI2_CAPABLE(ha)) +		if (IS_QLA82XX(ha)) { +			if (RD_REG_DWORD(®->isp82.hint) & +				HINT_MBX_INT_PENDING) { +				spin_unlock_irqrestore(&ha->hardware_lock, +					flags); +				DEBUG2_3_11(printk(KERN_INFO +				    "%s(%ld): Pending Mailbox timeout. " +				    "Exiting.\n", __func__, base_vha->host_no)); +				return QLA_FUNCTION_TIMEOUT; +			} +			WRT_REG_DWORD(®->isp82.hint, HINT_MBX_INT_PENDING); +		} else if (IS_FWI2_CAPABLE(ha))  			WRT_REG_DWORD(®->isp24.hccr, HCCRX_SET_HOST_INT);  		else  			WRT_REG_WORD(®->isp.hccr, HCCR_SET_HOST_INT); @@ -147,7 +168,18 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)  		DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,  		    base_vha->host_no, command)); -		if (IS_FWI2_CAPABLE(ha)) +		if (IS_QLA82XX(ha)) { +			if (RD_REG_DWORD(®->isp82.hint) & +				HINT_MBX_INT_PENDING) { +				spin_unlock_irqrestore(&ha->hardware_lock, +					flags); +				DEBUG2_3_11(printk(KERN_INFO +				    "%s(%ld): Pending Mailbox timeout. " +				    "Exiting.\n", __func__, base_vha->host_no)); +				return QLA_FUNCTION_TIMEOUT; +			} +			WRT_REG_DWORD(®->isp82.hint, HINT_MBX_INT_PENDING); +		} else if (IS_FWI2_CAPABLE(ha))  			WRT_REG_DWORD(®->isp24.hccr, HCCRX_SET_HOST_INT);  		else  			WRT_REG_WORD(®->isp.hccr, HCCR_SET_HOST_INT); @@ -264,7 +296,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)  			set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);  			clear_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); -			if (qla2x00_abort_isp(base_vha)) { +			if (ha->isp_ops->abort_isp(base_vha)) {  				/* Failed. retry later. */  				set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);  			} @@ -711,7 +743,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *vha, uint32_t risc_addr)   * Context:   *	Kernel context.   */ -static int +int  qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer,      dma_addr_t phys_addr, size_t size, uint32_t tov)  { @@ -952,7 +984,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,  	mcp->mb[9] = vha->vp_idx;  	mcp->out_mb = MBX_9|MBX_0;  	mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; -	if (IS_QLA81XX(vha->hw)) +	if (IS_QLA8XXX_TYPE(vha->hw))  		mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;  	mcp->tov = MBX_TOV_SECONDS;  	mcp->flags = 0; @@ -978,7 +1010,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,  		DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n",  		    vha->host_no)); -		if (IS_QLA81XX(vha->hw)) { +		if (IS_QLA8XXX_TYPE(vha->hw)) {  			vha->fcoe_vlan_id = mcp->mb[9] & 0xfff;  			vha->fcoe_fcf_idx = mcp->mb[10];  			vha->fcoe_vn_port_mac[5] = mcp->mb[11] >> 8; @@ -1076,6 +1108,10 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)  	DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",  	    vha->host_no)); +	if (IS_QLA82XX(ha) && ql2xdbwr) +		qla82xx_wr_32(ha, ha->nxdb_wr_ptr, +			(0x04 | (ha->portnum << 5) | (0 << 8) | (0 << 16))); +  	if (ha->flags.npiv_supported)  		mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;  	else @@ -1408,7 +1444,7 @@ qla2x00_lip_reset(scsi_qla_host_t *vha)  	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); -	if (IS_QLA81XX(vha->hw)) { +	if (IS_QLA8XXX_TYPE(vha->hw)) {  		/* Logout across all FCFs. */  		mcp->mb[0] = MBC_LIP_FULL_LOGIN;  		mcp->mb[1] = BIT_1; @@ -2428,12 +2464,22 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,  int  qla24xx_abort_target(struct fc_port *fcport, unsigned int l, int tag)  { +	struct qla_hw_data *ha = fcport->vha->hw; + +	if ((ql2xasynctmfenable) && IS_FWI2_CAPABLE(ha)) +		return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag); +  	return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l, tag);  }  int  qla24xx_lun_reset(struct fc_port *fcport, unsigned int l, int tag)  { +	struct qla_hw_data *ha = fcport->vha->hw; + +	if ((ql2xasynctmfenable) && IS_FWI2_CAPABLE(ha)) +		return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag); +  	return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l, tag);  } @@ -2740,6 +2786,48 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint16_t addr,  }  int +qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, +	uint16_t *port_speed, uint16_t *mb) +{ +	int rval; +	mbx_cmd_t mc; +	mbx_cmd_t *mcp = &mc; + +	if (!IS_IIDMA_CAPABLE(vha->hw)) +		return QLA_FUNCTION_FAILED; + +	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + +	mcp->mb[0] = MBC_PORT_PARAMS; +	mcp->mb[1] = loop_id; +	mcp->mb[2] = mcp->mb[3] = 0; +	mcp->mb[9] = vha->vp_idx; +	mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; +	mcp->in_mb = MBX_3|MBX_1|MBX_0; +	mcp->tov = MBX_TOV_SECONDS; +	mcp->flags = 0; +	rval = qla2x00_mailbox_command(vha, mcp); + +	/* Return mailbox statuses. */ +	if (mb != NULL) { +		mb[0] = mcp->mb[0]; +		mb[1] = mcp->mb[1]; +		mb[3] = mcp->mb[3]; +	} + +	if (rval != QLA_SUCCESS) { +		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, +		    vha->host_no, rval)); +	} else { +		DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); +		if (port_speed) +			*port_speed = mcp->mb[3]; +	} + +	return rval; +} + +int  qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,      uint16_t port_speed, uint16_t *mb)  { @@ -2755,7 +2843,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,  	mcp->mb[0] = MBC_PORT_PARAMS;  	mcp->mb[1] = loop_id;  	mcp->mb[2] = BIT_0; -	if (IS_QLA81XX(vha->hw)) +	if (IS_QLA8XXX_TYPE(vha->hw))  		mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);  	else  		mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0); @@ -3544,7 +3632,7 @@ qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma,  	mbx_cmd_t mc;  	mbx_cmd_t *mcp = &mc; -	if (!IS_QLA81XX(vha->hw)) +	if (!IS_QLA8XXX_TYPE(vha->hw))  		return QLA_FUNCTION_FAILED;  	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); @@ -3582,7 +3670,7 @@ qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma,  	mbx_cmd_t mc;  	mbx_cmd_t *mcp = &mc; -	if (!IS_QLA81XX(vha->hw)) +	if (!IS_QLA8XXX_TYPE(vha->hw))  		return QLA_FUNCTION_FAILED;  	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); @@ -3643,7 +3731,8 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)  }  int -qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp) +qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, +	uint16_t *mresp)  {  	int rval;  	mbx_cmd_t mc; @@ -3678,7 +3767,7 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *  	mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15|  	    MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0; -	if (IS_QLA81XX(vha->hw)) +	if (IS_QLA8XXX_TYPE(vha->hw))  		mcp->out_mb |= MBX_2;  	mcp->in_mb = MBX_19|MBX_18|MBX_3|MBX_2|MBX_1|MBX_0; @@ -3690,9 +3779,11 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *  	if (rval != QLA_SUCCESS) {  		DEBUG2(printk(KERN_WARNING -		    "(%ld): failed=%x mb[0]=0x%x " -			"mb[1]=0x%x mb[2]=0x%x mb[3]=0x%x mb[18]=0x%x mb[19]=0x%x. \n", vha->host_no, rval, -			mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[18], mcp->mb[19])); +			"(%ld): failed=%x mb[0]=0x%x " +			"mb[1]=0x%x mb[2]=0x%x mb[3]=0x%x mb[18]=0x%x " +			"mb[19]=0x%x.\n", +			vha->host_no, rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], +			mcp->mb[3], mcp->mb[18], mcp->mb[19]));  	} else {  		DEBUG2(printk(KERN_WARNING  		    "scsi(%ld): done.\n", vha->host_no)); @@ -3706,7 +3797,8 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *  }  int -qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp) +qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, +	uint16_t *mresp)  {  	int rval;  	mbx_cmd_t mc; @@ -3718,9 +3810,10 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mres  	memset(mcp->mb, 0 , sizeof(mcp->mb));  	mcp->mb[0] = MBC_DIAGNOSTIC_ECHO;  	mcp->mb[1] = mreq->options | BIT_6;	/* BIT_6 specifies 64bit address */ -	if (IS_QLA81XX(ha)) +	if (IS_QLA8XXX_TYPE(ha)) {  		mcp->mb[1] |= BIT_15; -	mcp->mb[2] = IS_QLA81XX(ha) ? vha->fcoe_fcf_idx : 0; +		mcp->mb[2] = vha->fcoe_fcf_idx; +	}  	mcp->mb[16] = LSW(mreq->rcv_dma);  	mcp->mb[17] = MSW(mreq->rcv_dma);  	mcp->mb[6] = LSW(MSD(mreq->rcv_dma)); @@ -3735,13 +3828,13 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mres  	mcp->out_mb = MBX_21|MBX_20|MBX_17|MBX_16|MBX_15|  	    MBX_14|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0; -	if (IS_QLA81XX(ha)) +	if (IS_QLA8XXX_TYPE(ha))  		mcp->out_mb |= MBX_2;  	mcp->in_mb = MBX_0; -	if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha)) +	if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA8XXX_TYPE(ha))  		mcp->in_mb |= MBX_1; -	if (IS_QLA81XX(ha)) +	if (IS_QLA8XXX_TYPE(ha))  		mcp->in_mb |= MBX_3;  	mcp->tov = MBX_TOV_SECONDS; @@ -3764,8 +3857,7 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mres  	return rval;  }  int -qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic, -    uint16_t *cmd_status) +qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic)  {  	int rval;  	mbx_cmd_t mc; @@ -3782,8 +3874,6 @@ qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic,  	mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;  	rval = qla2x00_mailbox_command(ha, mcp); -	/* Return mailbox statuses. */ -	*cmd_status = mcp->mb[0];  	if (rval != QLA_SUCCESS)  		DEBUG16(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no,  			rval)); @@ -3801,7 +3891,7 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)  	mbx_cmd_t *mcp = &mc;  	if (!IS_FWI2_CAPABLE(vha->hw)) -                return QLA_FUNCTION_FAILED; +		return QLA_FUNCTION_FAILED;  	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); @@ -3836,7 +3926,8 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)  	if (!IS_FWI2_CAPABLE(ha))  		return QLA_FUNCTION_FAILED; -	DEBUG11(printk(KERN_INFO "%s(%ld): entered.\n", __func__, vha->host_no)); +	DEBUG11(qla_printk(KERN_INFO, ha, +		"%s(%ld): entered.\n", __func__, vha->host_no));  	mcp->mb[0] = MBC_DATA_RATE;  	mcp->mb[1] = 0; @@ -3857,3 +3948,122 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)  	return rval;  } + +int +qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority, +		uint16_t *mb) +{ +	int rval; +	mbx_cmd_t mc; +	mbx_cmd_t *mcp = &mc; +	struct qla_hw_data *ha = vha->hw; + +	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) +		return QLA_FUNCTION_FAILED; + +	DEBUG11(printk(KERN_INFO +	    "%s(%ld): entered.\n", __func__, ha->host_no)); + +	mcp->mb[0] = MBC_PORT_PARAMS; +	mcp->mb[1] = loop_id; +	if (ha->flags.fcp_prio_enabled) +		mcp->mb[2] = BIT_1; +	else +		mcp->mb[2] = BIT_2; +	mcp->mb[4] = priority & 0xf; +	mcp->mb[9] = vha->vp_idx; +	mcp->out_mb = MBX_9|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; +	mcp->in_mb = MBX_4|MBX_3|MBX_1|MBX_0; +	mcp->tov = 30; +	mcp->flags = 0; +	rval = qla2x00_mailbox_command(vha, mcp); +	if (mb != NULL) { +		mb[0] = mcp->mb[0]; +		mb[1] = mcp->mb[1]; +		mb[3] = mcp->mb[3]; +		mb[4] = mcp->mb[4]; +	} + +	if (rval != QLA_SUCCESS) { +		DEBUG2_3_11(printk(KERN_WARNING +		    "%s(%ld): failed=%x.\n", __func__, +		    vha->host_no, rval)); +	} else { +		DEBUG11(printk(KERN_INFO +		    "%s(%ld): done.\n", __func__, vha->host_no)); +	} + +	return rval; +} + +int +qla82xx_mbx_intr_enable(scsi_qla_host_t *vha) +{ +	int rval; +	struct qla_hw_data *ha = vha->hw; +	mbx_cmd_t mc; +	mbx_cmd_t *mcp = &mc; + +	if (!IS_FWI2_CAPABLE(ha)) +		return QLA_FUNCTION_FAILED; + +	DEBUG11(qla_printk(KERN_INFO, ha, +		"%s(%ld): entered.\n", __func__, vha->host_no)); + +	memset(mcp, 0, sizeof(mbx_cmd_t)); +	mcp->mb[0] = MBC_TOGGLE_INTR; +	mcp->mb[1] = 1; + +	mcp->out_mb = MBX_1|MBX_0; +	mcp->in_mb = MBX_0; +	mcp->tov = 30; +	mcp->flags = 0; + +	rval = qla2x00_mailbox_command(vha, mcp); +	if (rval != QLA_SUCCESS) { +		DEBUG2_3_11(qla_printk(KERN_WARNING, ha, +			"%s(%ld): failed=%x mb[0]=%x.\n", __func__, +			vha->host_no, rval, mcp->mb[0])); +	} else { +		DEBUG11(qla_printk(KERN_INFO, ha, +			"%s(%ld): done.\n", __func__, vha->host_no)); +	} + +	return rval; +} + +int +qla82xx_mbx_intr_disable(scsi_qla_host_t *vha) +{ +	int rval; +	struct qla_hw_data *ha = vha->hw; +	mbx_cmd_t mc; +	mbx_cmd_t *mcp = &mc; + +	if (!IS_QLA82XX(ha)) +		return QLA_FUNCTION_FAILED; + +	DEBUG11(qla_printk(KERN_INFO, ha, +		"%s(%ld): entered.\n", __func__, vha->host_no)); + +	memset(mcp, 0, sizeof(mbx_cmd_t)); +	mcp->mb[0] = MBC_TOGGLE_INTR; +	mcp->mb[1] = 0; + +	mcp->out_mb = MBX_1|MBX_0; +	mcp->in_mb = MBX_0; +	mcp->tov = 30; +	mcp->flags = 0; + +	rval = qla2x00_mailbox_command(vha, mcp); +	if (rval != QLA_SUCCESS) { +		DEBUG2_3_11(qla_printk(KERN_WARNING, ha, +			"%s(%ld): failed=%x mb[0]=%x.\n", __func__, +			vha->host_no, rval, mcp->mb[0])); +	} else { +		DEBUG11(qla_printk(KERN_INFO, ha, +			"%s(%ld): done.\n", __func__, vha->host_no)); +	} + +	return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c new file mode 100644 index 00000000000..ff562de0e8e --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -0,0 +1,3636 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c)  2003-2008 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ +#include "qla_def.h" +#include <linux/delay.h> +#include <linux/pci.h> + +#define MASK(n)			((1ULL<<(n))-1) +#define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | \ +	((addr >> 25) & 0x3ff)) +#define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | \ +	((addr >> 25) & 0x3ff)) +#define MS_WIN(addr) (addr & 0x0ffc0000) +#define QLA82XX_PCI_MN_2M   (0) +#define QLA82XX_PCI_MS_2M   (0x80000) +#define QLA82XX_PCI_OCM0_2M (0xc0000) +#define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800) +#define GET_MEM_OFFS_2M(addr) (addr & MASK(18)) + +/* CRB window related */ +#define CRB_BLK(off)	((off >> 20) & 0x3f) +#define CRB_SUBBLK(off)	((off >> 16) & 0xf) +#define CRB_WINDOW_2M	(0x130060) +#define QLA82XX_PCI_CAMQM_2M_END	(0x04800800UL) +#define CRB_HI(off)	((qla82xx_crb_hub_agt[CRB_BLK(off)] << 20) | \ +			((off) & 0xf0000)) +#define QLA82XX_PCI_CAMQM_2M_BASE	(0x000ff800UL) +#define CRB_INDIRECT_2M	(0x1e0000UL) + +#define MAX_CRB_XFORM 60 +static unsigned long crb_addr_xform[MAX_CRB_XFORM]; +int qla82xx_crb_table_initialized; + +#define qla82xx_crb_addr_transform(name) \ +	(crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \ +	QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20) + +static void qla82xx_crb_addr_transform_setup(void) +{ +	qla82xx_crb_addr_transform(XDMA); +	qla82xx_crb_addr_transform(TIMR); +	qla82xx_crb_addr_transform(SRE); +	qla82xx_crb_addr_transform(SQN3); +	qla82xx_crb_addr_transform(SQN2); +	qla82xx_crb_addr_transform(SQN1); +	qla82xx_crb_addr_transform(SQN0); +	qla82xx_crb_addr_transform(SQS3); +	qla82xx_crb_addr_transform(SQS2); +	qla82xx_crb_addr_transform(SQS1); +	qla82xx_crb_addr_transform(SQS0); +	qla82xx_crb_addr_transform(RPMX7); +	qla82xx_crb_addr_transform(RPMX6); +	qla82xx_crb_addr_transform(RPMX5); +	qla82xx_crb_addr_transform(RPMX4); +	qla82xx_crb_addr_transform(RPMX3); +	qla82xx_crb_addr_transform(RPMX2); +	qla82xx_crb_addr_transform(RPMX1); +	qla82xx_crb_addr_transform(RPMX0); +	qla82xx_crb_addr_transform(ROMUSB); +	qla82xx_crb_addr_transform(SN); +	qla82xx_crb_addr_transform(QMN); +	qla82xx_crb_addr_transform(QMS); +	qla82xx_crb_addr_transform(PGNI); +	qla82xx_crb_addr_transform(PGND); +	qla82xx_crb_addr_transform(PGN3); +	qla82xx_crb_addr_transform(PGN2); +	qla82xx_crb_addr_transform(PGN1); +	qla82xx_crb_addr_transform(PGN0); +	qla82xx_crb_addr_transform(PGSI); +	qla82xx_crb_addr_transform(PGSD); +	qla82xx_crb_addr_transform(PGS3); +	qla82xx_crb_addr_transform(PGS2); +	qla82xx_crb_addr_transform(PGS1); +	qla82xx_crb_addr_transform(PGS0); +	qla82xx_crb_addr_transform(PS); +	qla82xx_crb_addr_transform(PH); +	qla82xx_crb_addr_transform(NIU); +	qla82xx_crb_addr_transform(I2Q); +	qla82xx_crb_addr_transform(EG); +	qla82xx_crb_addr_transform(MN); +	qla82xx_crb_addr_transform(MS); +	qla82xx_crb_addr_transform(CAS2); +	qla82xx_crb_addr_transform(CAS1); +	qla82xx_crb_addr_transform(CAS0); +	qla82xx_crb_addr_transform(CAM); +	qla82xx_crb_addr_transform(C2C1); +	qla82xx_crb_addr_transform(C2C0); +	qla82xx_crb_addr_transform(SMB); +	qla82xx_crb_addr_transform(OCM0); +	/* +	 * Used only in P3 just define it for P2 also. +	 */ +	qla82xx_crb_addr_transform(I2C0); + +	qla82xx_crb_table_initialized = 1; +} + +struct crb_128M_2M_block_map crb_128M_2M_map[64] = { +	{{{0, 0,         0,         0} } }, +	{{{1, 0x0100000, 0x0102000, 0x120000}, +	{1, 0x0110000, 0x0120000, 0x130000}, +	{1, 0x0120000, 0x0122000, 0x124000}, +	{1, 0x0130000, 0x0132000, 0x126000}, +	{1, 0x0140000, 0x0142000, 0x128000}, +	{1, 0x0150000, 0x0152000, 0x12a000}, +	{1, 0x0160000, 0x0170000, 0x110000}, +	{1, 0x0170000, 0x0172000, 0x12e000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{1, 0x01e0000, 0x01e0800, 0x122000}, +	{0, 0x0000000, 0x0000000, 0x000000} } } , +	{{{1, 0x0200000, 0x0210000, 0x180000} } }, +	{{{0, 0,         0,         0} } }, +	{{{1, 0x0400000, 0x0401000, 0x169000} } }, +	{{{1, 0x0500000, 0x0510000, 0x140000} } }, +	{{{1, 0x0600000, 0x0610000, 0x1c0000} } }, +	{{{1, 0x0700000, 0x0704000, 0x1b8000} } }, +	{{{1, 0x0800000, 0x0802000, 0x170000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{1, 0x08f0000, 0x08f2000, 0x172000} } }, +	{{{1, 0x0900000, 0x0902000, 0x174000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{1, 0x09f0000, 0x09f2000, 0x176000} } }, +	{{{0, 0x0a00000, 0x0a02000, 0x178000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{1, 0x0af0000, 0x0af2000, 0x17a000} } }, +	{{{0, 0x0b00000, 0x0b02000, 0x17c000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{1, 0x0bf0000, 0x0bf2000, 0x17e000} } }, +	{{{1, 0x0c00000, 0x0c04000, 0x1d4000} } }, +	{{{1, 0x0d00000, 0x0d04000, 0x1a4000} } }, +	{{{1, 0x0e00000, 0x0e04000, 0x1a0000} } }, +	{{{1, 0x0f00000, 0x0f01000, 0x164000} } }, +	{{{0, 0x1000000, 0x1004000, 0x1a8000} } }, +	{{{1, 0x1100000, 0x1101000, 0x160000} } }, +	{{{1, 0x1200000, 0x1201000, 0x161000} } }, +	{{{1, 0x1300000, 0x1301000, 0x162000} } }, +	{{{1, 0x1400000, 0x1401000, 0x163000} } }, +	{{{1, 0x1500000, 0x1501000, 0x165000} } }, +	{{{1, 0x1600000, 0x1601000, 0x166000} } }, +	{{{0, 0,         0,         0} } }, +	{{{0, 0,         0,         0} } }, +	{{{0, 0,         0,         0} } }, +	{{{0, 0,         0,         0} } }, +	{{{0, 0,         0,         0} } }, +	{{{0, 0,         0,         0} } }, +	{{{1, 0x1d00000, 0x1d10000, 0x190000} } }, +	{{{1, 0x1e00000, 0x1e01000, 0x16a000} } }, +	{{{1, 0x1f00000, 0x1f10000, 0x150000} } }, +	{{{0} } }, +	{{{1, 0x2100000, 0x2102000, 0x120000}, +	{1, 0x2110000, 0x2120000, 0x130000}, +	{1, 0x2120000, 0x2122000, 0x124000}, +	{1, 0x2130000, 0x2132000, 0x126000}, +	{1, 0x2140000, 0x2142000, 0x128000}, +	{1, 0x2150000, 0x2152000, 0x12a000}, +	{1, 0x2160000, 0x2170000, 0x110000}, +	{1, 0x2170000, 0x2172000, 0x12e000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000}, +	{0, 0x0000000, 0x0000000, 0x000000} } }, +	{{{1, 0x2200000, 0x2204000, 0x1b0000} } }, +	{{{0} } }, +	{{{0} } }, +	{{{0} } }, +	{{{0} } }, +	{{{0} } }, +	{{{1, 0x2800000, 0x2804000, 0x1a4000} } }, +	{{{1, 0x2900000, 0x2901000, 0x16b000} } }, +	{{{1, 0x2a00000, 0x2a00400, 0x1ac400} } }, +	{{{1, 0x2b00000, 0x2b00400, 0x1ac800} } }, +	{{{1, 0x2c00000, 0x2c00400, 0x1acc00} } }, +	{{{1, 0x2d00000, 0x2d00400, 0x1ad000} } }, +	{{{1, 0x2e00000, 0x2e00400, 0x1ad400} } }, +	{{{1, 0x2f00000, 0x2f00400, 0x1ad800} } }, +	{{{1, 0x3000000, 0x3000400, 0x1adc00} } }, +	{{{0, 0x3100000, 0x3104000, 0x1a8000} } }, +	{{{1, 0x3200000, 0x3204000, 0x1d4000} } }, +	{{{1, 0x3300000, 0x3304000, 0x1a0000} } }, +	{{{0} } }, +	{{{1, 0x3500000, 0x3500400, 0x1ac000} } }, +	{{{1, 0x3600000, 0x3600400, 0x1ae000} } }, +	{{{1, 0x3700000, 0x3700400, 0x1ae400} } }, +	{{{1, 0x3800000, 0x3804000, 0x1d0000} } }, +	{{{1, 0x3900000, 0x3904000, 0x1b4000} } }, +	{{{1, 0x3a00000, 0x3a04000, 0x1d8000} } }, +	{{{0} } }, +	{{{0} } }, +	{{{1, 0x3d00000, 0x3d04000, 0x1dc000} } }, +	{{{1, 0x3e00000, 0x3e01000, 0x167000} } }, +	{{{1, 0x3f00000, 0x3f01000, 0x168000} } } +}; + +/* + * top 12 bits of crb internal address (hub, agent) + */ +unsigned qla82xx_crb_hub_agt[64] = { +	0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PS, +	QLA82XX_HW_CRB_HUB_AGT_ADR_MN, +	QLA82XX_HW_CRB_HUB_AGT_ADR_MS, +	0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_SRE, +	QLA82XX_HW_CRB_HUB_AGT_ADR_NIU, +	QLA82XX_HW_CRB_HUB_AGT_ADR_QMN, +	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1, +	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2, +	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3, +	QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q, +	QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR, +	QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4, +	QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGND, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3, +	0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI, +	QLA82XX_HW_CRB_HUB_AGT_ADR_SN, +	0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_EG, +	0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PS, +	QLA82XX_HW_CRB_HUB_AGT_ADR_CAM, +	0, +	0, +	0, +	0, +	0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR, +	0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1, +	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2, +	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3, +	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4, +	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5, +	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6, +	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7, +	QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA, +	QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q, +	QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB, +	0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8, +	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9, +	QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0, +	0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_SMB, +	QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1, +	0, +	QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC, +	0, +}; + +/* Device states */ +char *qdev_state[] = { +	 "Unknown", +	"Cold", +	"Initializing", +	"Ready", +	"Need Reset", +	"Need Quiescent", +	"Failed", +	"Quiescent", +}; + +/* + * In: 'off' is offset from CRB space in 128M pci map + * Out: 'off' is 2M pci map addr + * side effect: lock crb window + */ +static void +qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off) +{ +	u32 win_read; + +	ha->crb_win = CRB_HI(*off); +	writel(ha->crb_win, +		(void *)(CRB_WINDOW_2M + ha->nx_pcibase)); + +	/* Read back value to make sure write has gone through before trying +	 * to use it. +	 */ +	win_read = RD_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase)); +	if (win_read != ha->crb_win) { +		DEBUG2(qla_printk(KERN_INFO, ha, +		    "%s: Written crbwin (0x%x) != Read crbwin (0x%x), " +		    "off=0x%lx\n", __func__, ha->crb_win, win_read, *off)); +	} +	*off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase; +} + +static inline unsigned long +qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off) +{ +	/* See if we are currently pointing to the region we want to use next */ +	if ((off >= QLA82XX_CRB_PCIX_HOST) && (off < QLA82XX_CRB_DDR_NET)) { +		/* No need to change window. PCIX and PCIEregs are in both +		 * regs are in both windows. +		 */ +		return off; +	} + +	if ((off >= QLA82XX_CRB_PCIX_HOST) && (off < QLA82XX_CRB_PCIX_HOST2)) { +		/* We are in first CRB window */ +		if (ha->curr_window != 0) +			WARN_ON(1); +		return off; +	} + +	if ((off > QLA82XX_CRB_PCIX_HOST2) && (off < QLA82XX_CRB_MAX)) { +		/* We are in second CRB window */ +		off = off - QLA82XX_CRB_PCIX_HOST2 + QLA82XX_CRB_PCIX_HOST; + +		if (ha->curr_window != 1) +			return off; + +		/* We are in the QM or direct access +		 * register region - do nothing +		 */ +		if ((off >= QLA82XX_PCI_DIRECT_CRB) && +			(off < QLA82XX_PCI_CAMQM_MAX)) +			return off; +	} +	/* strange address given */ +	qla_printk(KERN_WARNING, ha, +		"%s: Warning: unm_nic_pci_set_crbwindow called with" +		" an unknown address(%llx)\n", QLA2XXX_DRIVER_NAME, off); +	return off; +} + +int +qla82xx_wr_32(struct qla_hw_data *ha, ulong off, u32 data) +{ +	unsigned long flags = 0; +	int rv; + +	rv = qla82xx_pci_get_crb_addr_2M(ha, &off); + +	BUG_ON(rv == -1); + +	if (rv == 1) { +		write_lock_irqsave(&ha->hw_lock, flags); +		qla82xx_crb_win_lock(ha); +		qla82xx_pci_set_crbwindow_2M(ha, &off); +	} + +	writel(data, (void __iomem *)off); + +	if (rv == 1) { +		qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); +		write_unlock_irqrestore(&ha->hw_lock, flags); +	} +	return 0; +} + +int +qla82xx_rd_32(struct qla_hw_data *ha, ulong off) +{ +	unsigned long flags = 0; +	int rv; +	u32 data; + +	rv = qla82xx_pci_get_crb_addr_2M(ha, &off); + +	BUG_ON(rv == -1); + +	if (rv == 1) { +		write_lock_irqsave(&ha->hw_lock, flags); +		qla82xx_crb_win_lock(ha); +		qla82xx_pci_set_crbwindow_2M(ha, &off); +	} +	data = RD_REG_DWORD((void __iomem *)off); + +	if (rv == 1) { +		qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); +		write_unlock_irqrestore(&ha->hw_lock, flags); +	} +	return data; +} + +#define CRB_WIN_LOCK_TIMEOUT 100000000 +int qla82xx_crb_win_lock(struct qla_hw_data *ha) +{ +	int done = 0, timeout = 0; + +	while (!done) { +		/* acquire semaphore3 from PCI HW block */ +		done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); +		if (done == 1) +			break; +		if (timeout >= CRB_WIN_LOCK_TIMEOUT) +			return -1; +		timeout++; +	} +	qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum); +	return 0; +} + +#define IDC_LOCK_TIMEOUT 100000000 +int qla82xx_idc_lock(struct qla_hw_data *ha) +{ +	int i; +	int done = 0, timeout = 0; + +	while (!done) { +		/* acquire semaphore5 from PCI HW block */ +		done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK)); +		if (done == 1) +			break; +		if (timeout >= IDC_LOCK_TIMEOUT) +			return -1; + +		timeout++; + +		/* Yield CPU */ +		if (!in_interrupt()) +			schedule(); +		else { +			for (i = 0; i < 20; i++) +				cpu_relax(); +		} +	} + +	return 0; +} + +void qla82xx_idc_unlock(struct qla_hw_data *ha) +{ +	qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK)); +} + +int +qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong *off) +{ +	struct crb_128M_2M_sub_block_map *m; + +	if (*off >= QLA82XX_CRB_MAX) +		return -1; + +	if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) { +		*off = (*off - QLA82XX_PCI_CAMQM) + +		    QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase; +		return 0; +	} + +	if (*off < QLA82XX_PCI_CRBSPACE) +		return -1; + +	*off -= QLA82XX_PCI_CRBSPACE; + +	/* Try direct map */ +	m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)]; + +	if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) { +		*off = *off + m->start_2M - m->start_128M + ha->nx_pcibase; +		return 0; +	} +	/* Not in direct map, use crb window */ +	return 1; +} + +/*  PCI Windowing for DDR regions.  */ +#define QLA82XX_ADDR_IN_RANGE(addr, low, high) \ +	(((addr) <= (high)) && ((addr) >= (low))) +/* + * check memory access boundary. + * used by test agent. support ddr access only for now + */ +static unsigned long +qla82xx_pci_mem_bound_check(struct qla_hw_data *ha, +	unsigned long long addr, int size) +{ +	if (!QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, +		QLA82XX_ADDR_DDR_NET_MAX) || +		!QLA82XX_ADDR_IN_RANGE(addr + size - 1, QLA82XX_ADDR_DDR_NET, +		QLA82XX_ADDR_DDR_NET_MAX) || +		((size != 1) && (size != 2) && (size != 4) && (size != 8))) +			return 0; +	else +		return 1; +} + +int qla82xx_pci_set_window_warning_count; + +unsigned long +qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr) +{ +	int window; +	u32 win_read; + +	if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, +		QLA82XX_ADDR_DDR_NET_MAX)) { +		/* DDR network side */ +		window = MN_WIN(addr); +		ha->ddr_mn_window = window; +		qla82xx_wr_32(ha, +			ha->mn_win_crb | QLA82XX_PCI_CRBSPACE, window); +		win_read = qla82xx_rd_32(ha, +			ha->mn_win_crb | QLA82XX_PCI_CRBSPACE); +		if ((win_read << 17) != window) { +			qla_printk(KERN_WARNING, ha, +			    "%s: Written MNwin (0x%x) != Read MNwin (0x%x)\n", +			    __func__, window, win_read); +		} +		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET; +	} else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0, +		QLA82XX_ADDR_OCM0_MAX)) { +		unsigned int temp1; +		if ((addr & 0x00ff800) == 0xff800) { +			qla_printk(KERN_WARNING, ha, +			    "%s: QM access not handled.\n", __func__); +			addr = -1UL; +		} +		window = OCM_WIN(addr); +		ha->ddr_mn_window = window; +		qla82xx_wr_32(ha, +			ha->mn_win_crb | QLA82XX_PCI_CRBSPACE, window); +		win_read = qla82xx_rd_32(ha, +			ha->mn_win_crb | QLA82XX_PCI_CRBSPACE); +		temp1 = ((window & 0x1FF) << 7) | +		    ((window & 0x0FFFE0000) >> 17); +		if (win_read != temp1) { +			qla_printk(KERN_WARNING, ha, +			    "%s: Written OCMwin (0x%x) != Read OCMwin (0x%x)\n", +			    __func__, temp1, win_read); +		} +		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M; + +	} else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, +		QLA82XX_P3_ADDR_QDR_NET_MAX)) { +		/* QDR network side */ +		window = MS_WIN(addr); +		ha->qdr_sn_window = window; +		qla82xx_wr_32(ha, +			ha->ms_win_crb | QLA82XX_PCI_CRBSPACE, window); +		win_read = qla82xx_rd_32(ha, +			ha->ms_win_crb | QLA82XX_PCI_CRBSPACE); +		if (win_read != window) { +			qla_printk(KERN_WARNING, ha, +			    "%s: Written MSwin (0x%x) != Read MSwin (0x%x)\n", +			    __func__, window, win_read); +		} +		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET; +	} else { +		/* +		 * peg gdb frequently accesses memory that doesn't exist, +		 * this limits the chit chat so debugging isn't slowed down. +		 */ +		if ((qla82xx_pci_set_window_warning_count++ < 8) || +		    (qla82xx_pci_set_window_warning_count%64 == 0)) { +			qla_printk(KERN_WARNING, ha, +			    "%s: Warning:%s Unknown address range!\n", __func__, +			    QLA2XXX_DRIVER_NAME); +		} +		addr = -1UL; +	} +	return addr; +} + +/* check if address is in the same windows as the previous access */ +static int qla82xx_pci_is_same_window(struct qla_hw_data *ha, +	unsigned long long addr) +{ +	int			window; +	unsigned long long	qdr_max; + +	qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX; + +	/* DDR network side */ +	if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, +		QLA82XX_ADDR_DDR_NET_MAX)) +		BUG(); +	else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0, +		QLA82XX_ADDR_OCM0_MAX)) +		return 1; +	else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM1, +		QLA82XX_ADDR_OCM1_MAX)) +		return 1; +	else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, qdr_max)) { +		/* QDR network side */ +		window = ((addr - QLA82XX_ADDR_QDR_NET) >> 22) & 0x3f; +		if (ha->qdr_sn_window == window) +			return 1; +	} +	return 0; +} + +static int qla82xx_pci_mem_read_direct(struct qla_hw_data *ha, +	u64 off, void *data, int size) +{ +	unsigned long   flags; +	void           *addr = NULL; +	int             ret = 0; +	u64             start; +	uint8_t         *mem_ptr = NULL; +	unsigned long   mem_base; +	unsigned long   mem_page; + +	write_lock_irqsave(&ha->hw_lock, flags); + +	/* +	 * If attempting to access unknown address or straddle hw windows, +	 * do not access. +	 */ +	start = qla82xx_pci_set_window(ha, off); +	if ((start == -1UL) || +		(qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) { +		write_unlock_irqrestore(&ha->hw_lock, flags); +		qla_printk(KERN_ERR, ha, +			"%s out of bound pci memory access. " +			"offset is 0x%llx\n", QLA2XXX_DRIVER_NAME, off); +		return -1; +	} + +	write_unlock_irqrestore(&ha->hw_lock, flags); +	mem_base = pci_resource_start(ha->pdev, 0); +	mem_page = start & PAGE_MASK; +	/* Map two pages whenever user tries to access addresses in two +	* consecutive pages. +	*/ +	if (mem_page != ((start + size - 1) & PAGE_MASK)) +		mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); +	else +		mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); +	if (mem_ptr == 0UL) { +		*(u8  *)data = 0; +		return -1; +	} +	addr = mem_ptr; +	addr += start & (PAGE_SIZE - 1); +	write_lock_irqsave(&ha->hw_lock, flags); + +	switch (size) { +	case 1: +		*(u8  *)data = readb(addr); +		break; +	case 2: +		*(u16 *)data = readw(addr); +		break; +	case 4: +		*(u32 *)data = readl(addr); +		break; +	case 8: +		*(u64 *)data = readq(addr); +		break; +	default: +		ret = -1; +		break; +	} +	write_unlock_irqrestore(&ha->hw_lock, flags); + +	if (mem_ptr) +		iounmap(mem_ptr); +	return ret; +} + +static int +qla82xx_pci_mem_write_direct(struct qla_hw_data *ha, +	u64 off, void *data, int size) +{ +	unsigned long   flags; +	void           *addr = NULL; +	int             ret = 0; +	u64             start; +	uint8_t         *mem_ptr = NULL; +	unsigned long   mem_base; +	unsigned long   mem_page; + +	write_lock_irqsave(&ha->hw_lock, flags); + +	/* +	 * If attempting to access unknown address or straddle hw windows, +	 * do not access. +	 */ +	start = qla82xx_pci_set_window(ha, off); +	if ((start == -1UL) || +		(qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) { +		write_unlock_irqrestore(&ha->hw_lock, flags); +		qla_printk(KERN_ERR, ha, +			"%s out of bound pci memory access. " +			"offset is 0x%llx\n", QLA2XXX_DRIVER_NAME, off); +		return -1; +	} + +	write_unlock_irqrestore(&ha->hw_lock, flags); +	mem_base = pci_resource_start(ha->pdev, 0); +	mem_page = start & PAGE_MASK; +	/* Map two pages whenever user tries to access addresses in two +	 * consecutive pages. +	 */ +	if (mem_page != ((start + size - 1) & PAGE_MASK)) +		mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2); +	else +		mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); +	if (mem_ptr == 0UL) +		return -1; + +	addr = mem_ptr; +	addr += start & (PAGE_SIZE - 1); +	write_lock_irqsave(&ha->hw_lock, flags); + +	switch (size) { +	case 1: +		writeb(*(u8  *)data, addr); +		break; +	case 2: +		writew(*(u16 *)data, addr); +		break; +	case 4: +		writel(*(u32 *)data, addr); +		break; +	case 8: +		writeq(*(u64 *)data, addr); +		break; +	default: +		ret = -1; +		break; +	} +	write_unlock_irqrestore(&ha->hw_lock, flags); +	if (mem_ptr) +		iounmap(mem_ptr); +	return ret; +} + +int +qla82xx_wrmem(struct qla_hw_data *ha, u64 off, void *data, int size) +{ +	int i, j, ret = 0, loop, sz[2], off0; +	u32 temp; +	u64 off8, mem_crb, tmpw, word[2] = {0, 0}; +#define MAX_CTL_CHECK   1000 +	/* +	 * If not MN, go check for MS or invalid. +	 */ +	if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) { +		mem_crb = QLA82XX_CRB_QDR_NET; +	} else { +		mem_crb = QLA82XX_CRB_DDR_NET; +		if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) +			return qla82xx_pci_mem_write_direct(ha, off, +			    data, size); +	} + +	off8 = off & 0xfffffff8; +	off0 = off & 0x7; +	sz[0] = (size < (8 - off0)) ? size : (8 - off0); +	sz[1] = size - sz[0]; +	loop = ((off0 + size - 1) >> 3) + 1; + +	if ((size != 8) || (off0 != 0))  { +		for (i = 0; i < loop; i++) { +			if (qla82xx_rdmem(ha, off8 + (i << 3), &word[i], 8)) +				return -1; +		} +	} + +	switch (size) { +	case 1: +		tmpw = *((u8 *)data); +		break; +	case 2: +		tmpw = *((u16 *)data); +		break; +	case 4: +		tmpw = *((u32 *)data); +		break; +	case 8: +	default: +		tmpw = *((u64 *)data); +		break; +	} + +	word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); +	word[0] |= tmpw << (off0 * 8); + +	if (loop == 2) { +		word[1] &= ~(~0ULL << (sz[1] * 8)); +		word[1] |= tmpw >> (sz[0] * 8); +	} + +	for (i = 0; i < loop; i++) { +		temp = off8 + (i << 3); +		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); +		temp = 0; +		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); +		temp = word[i] & 0xffffffff; +		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); +		temp = (word[i] >> 32) & 0xffffffff; +		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); +		temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; +		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp); +		temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; +		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp); + +		for (j = 0; j < MAX_CTL_CHECK; j++) { +			temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); +			if ((temp & MIU_TA_CTL_BUSY) == 0) +				break; +		} + +		if (j >= MAX_CTL_CHECK) { +			qla_printk(KERN_WARNING, ha, +				"%s: Fail to write through agent\n", +				QLA2XXX_DRIVER_NAME); +			ret = -1; +			break; +		} +	} +	return ret; +} + +int +qla82xx_rdmem(struct qla_hw_data *ha, u64 off, void *data, int size) +{ +	int i, j = 0, k, start, end, loop, sz[2], off0[2]; +	u32 temp; +	u64 off8, val, mem_crb, word[2] = {0, 0}; +#define MAX_CTL_CHECK   1000 + +	/* +	 * If not MN, go check for MS or invalid. +	 */ +	if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) +		mem_crb = QLA82XX_CRB_QDR_NET; +	else { +		mem_crb = QLA82XX_CRB_DDR_NET; +		if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) +			return qla82xx_pci_mem_read_direct(ha, off, +				data, size); +	} + +	off8 = off & 0xfffffff8; +	off0[0] = off & 0x7; +	off0[1] = 0; +	sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]); +	sz[1] = size - sz[0]; +	loop = ((off0[0] + size - 1) >> 3) + 1; + +	for (i = 0; i < loop; i++) { +		temp = off8 + (i << 3); +		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); +		temp = 0; +		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); +		temp = MIU_TA_CTL_ENABLE; +		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); +		temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; +		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); + +		for (j = 0; j < MAX_CTL_CHECK; j++) { +			temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); +			if ((temp & MIU_TA_CTL_BUSY) == 0) +				break; +		} + +		if (j >= MAX_CTL_CHECK) { +			qla_printk(KERN_INFO, ha, +				"%s: Fail to read through agent\n", +				QLA2XXX_DRIVER_NAME); +			break; +		} + +		start = off0[i] >> 2; +		end   = (off0[i] + sz[i] - 1) >> 2; +		for (k = start; k <= end; k++) { +			temp = qla82xx_rd_32(ha, +			    mem_crb + MIU_TEST_AGT_RDDATA(k)); +			word[i] |= ((u64)temp << (32 * k)); +		} +	} + +	if (j >= MAX_CTL_CHECK) +		return -1; + +	if (sz[0] == 8) { +		val = word[0]; +	} else { +		val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) | +			((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8)); +	} + +	switch (size) { +	case 1: +		*(u8  *)data = val; +		break; +	case 2: +		*(u16 *)data = val; +		break; +	case 4: +		*(u32 *)data = val; +		break; +	case 8: +		*(u64 *)data = val; +		break; +	} +	return 0; +} + +#define MTU_FUDGE_FACTOR 100 +unsigned long qla82xx_decode_crb_addr(unsigned long addr) +{ +	int i; +	unsigned long base_addr, offset, pci_base; + +	if (!qla82xx_crb_table_initialized) +		qla82xx_crb_addr_transform_setup(); + +	pci_base = ADDR_ERROR; +	base_addr = addr & 0xfff00000; +	offset = addr & 0x000fffff; + +	for (i = 0; i < MAX_CRB_XFORM; i++) { +		if (crb_addr_xform[i] == base_addr) { +			pci_base = i << 20; +			break; +		} +	} +	if (pci_base == ADDR_ERROR) +		return pci_base; +	return pci_base + offset; +} + +static long rom_max_timeout = 100; +static long qla82xx_rom_lock_timeout = 100; + +int +qla82xx_rom_lock(struct qla_hw_data *ha) +{ +	int done = 0, timeout = 0; + +	while (!done) { +		/* acquire semaphore2 from PCI HW block */ +		done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK)); +		if (done == 1) +			break; +		if (timeout >= qla82xx_rom_lock_timeout) +			return -1; +		timeout++; +	} +	qla82xx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ROM_LOCK_DRIVER); +	return 0; +} + +int +qla82xx_wait_rom_busy(struct qla_hw_data *ha) +{ +	long timeout = 0; +	long done = 0 ; + +	while (done == 0) { +		done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS); +		done &= 4; +		timeout++; +		if (timeout >= rom_max_timeout) { +			DEBUG(qla_printk(KERN_INFO, ha, +				"%s: Timeout reached waiting for rom busy", +				QLA2XXX_DRIVER_NAME)); +			return -1; +		} +	} +	return 0; +} + +int +qla82xx_wait_rom_done(struct qla_hw_data *ha) +{ +	long timeout = 0; +	long done = 0 ; + +	while (done == 0) { +		done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS); +		done &= 2; +		timeout++; +		if (timeout >= rom_max_timeout) { +			DEBUG(qla_printk(KERN_INFO, ha, +				"%s: Timeout reached  waiting for rom done", +				QLA2XXX_DRIVER_NAME)); +			return -1; +		} +	} +	return 0; +} + +int +qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) +{ +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0xb); +	qla82xx_wait_rom_busy(ha); +	if (qla82xx_wait_rom_done(ha)) { +		qla_printk(KERN_WARNING, ha, +			"%s: Error waiting for rom done\n", +			QLA2XXX_DRIVER_NAME); +		return -1; +	} +	/* Reset abyte_cnt and dummy_byte_cnt */ +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); +	udelay(10); +	cond_resched(); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0); +	*valp = qla82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA); +	return 0; +} + +int +qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) +{ +	int ret, loops = 0; + +	while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) { +		udelay(100); +		schedule(); +		loops++; +	} +	if (loops >= 50000) { +		qla_printk(KERN_INFO, ha, +			"%s: qla82xx_rom_lock failed\n", +			QLA2XXX_DRIVER_NAME); +		return -1; +	} +	ret = qla82xx_do_rom_fast_read(ha, addr, valp); +	qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); +	return ret; +} + +int +qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val) +{ +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR); +	qla82xx_wait_rom_busy(ha); +	if (qla82xx_wait_rom_done(ha)) { +		qla_printk(KERN_WARNING, ha, +		    "Error waiting for rom done\n"); +		return -1; +	} +	*val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA); +	return 0; +} + +int +qla82xx_flash_wait_write_finish(struct qla_hw_data *ha) +{ +	long timeout = 0; +	uint32_t done = 1 ; +	uint32_t val; +	int ret = 0; + +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0); +	while ((done != 0) && (ret == 0)) { +		ret = qla82xx_read_status_reg(ha, &val); +		done = val & 1; +		timeout++; +		udelay(10); +		cond_resched(); +		if (timeout >= 50000) { +			qla_printk(KERN_WARNING, ha, +			    "Timeout reached  waiting for write finish"); +			return -1; +		} +	} +	return ret; +} + +int +qla82xx_flash_set_write_enable(struct qla_hw_data *ha) +{ +	uint32_t val; +	qla82xx_wait_rom_busy(ha); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WREN); +	qla82xx_wait_rom_busy(ha); +	if (qla82xx_wait_rom_done(ha)) +		return -1; +	if (qla82xx_read_status_reg(ha, &val) != 0) +		return -1; +	if ((val & 2) != 2) +		return -1; +	return 0; +} + +int +qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val) +{ +	if (qla82xx_flash_set_write_enable(ha)) +		return -1; +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, val); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0x1); +	if (qla82xx_wait_rom_done(ha)) { +		qla_printk(KERN_WARNING, ha, +		    "Error waiting for rom done\n"); +		return -1; +	} +	return qla82xx_flash_wait_write_finish(ha); +} + +int +qla82xx_write_disable_flash(struct qla_hw_data *ha) +{ +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI); +	if (qla82xx_wait_rom_done(ha)) { +		qla_printk(KERN_WARNING, ha, +		    "Error waiting for rom done\n"); +		return -1; +	} +	return 0; +} + +int +ql82xx_rom_lock_d(struct qla_hw_data *ha) +{ +	int loops = 0; +	while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) { +		udelay(100); +		cond_resched(); +		loops++; +	} +	if (loops >= 50000) { +		qla_printk(KERN_WARNING, ha, "ROM lock failed\n"); +		return -1; +	} +	return 0;; +} + +int +qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr, +	uint32_t data) +{ +	int ret = 0; + +	ret = ql82xx_rom_lock_d(ha); +	if (ret < 0) { +		qla_printk(KERN_WARNING, ha, "ROM Lock failed\n"); +		return ret; +	} + +	if (qla82xx_flash_set_write_enable(ha)) +		goto done_write; + +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, data); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, flashaddr); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_PP); +	qla82xx_wait_rom_busy(ha); +	if (qla82xx_wait_rom_done(ha)) { +		qla_printk(KERN_WARNING, ha, +			"Error waiting for rom done\n"); +		ret = -1; +		goto done_write; +	} + +	ret = qla82xx_flash_wait_write_finish(ha); + +done_write: +	qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); +	return ret; +} + +/* This routine does CRB initialize sequence + *  to put the ISP into operational state + */ +int qla82xx_pinit_from_rom(scsi_qla_host_t *vha) +{ +	int addr, val; +	int i ; +	struct crb_addr_pair *buf; +	unsigned long off; +	unsigned offset, n; +	struct qla_hw_data *ha = vha->hw; + +	struct crb_addr_pair { +		long addr; +		long data; +	}; + +	/* Halt all the indiviual PEGs and other blocks of the ISP */ +	qla82xx_rom_lock(ha); +	if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) +		/* don't reset CAM block on reset */ +		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff); +	else +		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff); +	qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + +	/* Read the signature value from the flash. +	 * Offset 0: Contain signature (0xcafecafe) +	 * Offset 4: Offset and number of addr/value pairs +	 * that present in CRB initialize sequence +	 */ +	if (qla82xx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL || +	    qla82xx_rom_fast_read(ha, 4, &n) != 0) { +		qla_printk(KERN_WARNING, ha, +		    "[ERROR] Reading crb_init area: n: %08x\n", n); +		return -1; +	} + +	/* Offset in flash = lower 16 bits +	 * Number of enteries = upper 16 bits +	 */ +	offset = n & 0xffffU; +	n = (n >> 16) & 0xffffU; + +	/* number of addr/value pair should not exceed 1024 enteries */ +	if (n  >= 1024) { +		qla_printk(KERN_WARNING, ha, +		    "%s: %s:n=0x%x [ERROR] Card flash not initialized.\n", +		    QLA2XXX_DRIVER_NAME, __func__, n); +		return -1; +	} + +	qla_printk(KERN_INFO, ha, +	    "%s: %d CRB init values found in ROM.\n", QLA2XXX_DRIVER_NAME, n); + +	buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL); +	if (buf == NULL) { +		qla_printk(KERN_WARNING, ha, +		    "%s: [ERROR] Unable to malloc memory.\n", +		    QLA2XXX_DRIVER_NAME); +		return -1; +	} + +	for (i = 0; i < n; i++) { +		if (qla82xx_rom_fast_read(ha, 8*i + 4*offset, &val) != 0 || +		    qla82xx_rom_fast_read(ha, 8*i + 4*offset + 4, &addr) != 0) { +			kfree(buf); +			return -1; +		} + +		buf[i].addr = addr; +		buf[i].data = val; +	} + +	for (i = 0; i < n; i++) { +		/* Translate internal CRB initialization +		 * address to PCI bus address +		 */ +		off = qla82xx_decode_crb_addr((unsigned long)buf[i].addr) + +		    QLA82XX_PCI_CRBSPACE; +		/* Not all CRB  addr/value pair to be written, +		 * some of them are skipped +		 */ + +		/* skipping cold reboot MAGIC */ +		if (off == QLA82XX_CAM_RAM(0x1fc)) +			continue; + +		/* do not reset PCI */ +		if (off == (ROMUSB_GLB + 0xbc)) +			continue; + +		/* skip core clock, so that firmware can increase the clock */ +		if (off == (ROMUSB_GLB + 0xc8)) +			continue; + +		/* skip the function enable register */ +		if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION)) +			continue; + +		if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION2)) +			continue; + +		if ((off & 0x0ff00000) == QLA82XX_CRB_SMB) +			continue; + +		if ((off & 0x0ff00000) == QLA82XX_CRB_DDR_NET) +			continue; + +		if (off == ADDR_ERROR) { +			qla_printk(KERN_WARNING, ha, +			    "%s: [ERROR] Unknown addr: 0x%08lx\n", +			    QLA2XXX_DRIVER_NAME, buf[i].addr); +			continue; +		} + +		if (off == (QLA82XX_CRB_PEG_NET_1 + 0x18)) { +			if (!QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) +				buf[i].data = 0x1020; +		} + +		qla82xx_wr_32(ha, off, buf[i].data); + +		/* ISP requires much bigger delay to settle down, +		 * else crb_window returns 0xffffffff +		 */ +		if (off == QLA82XX_ROMUSB_GLB_SW_RESET) +			msleep(1000); + +		/* ISP requires millisec delay between +		 * successive CRB register updation +		 */ +		msleep(1); +	} + +	kfree(buf); + +	/* Resetting the data and instruction cache */ +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0xec, 0x1e); +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0x4c, 8); +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_I+0x4c, 8); + +	/* Clear all protocol processing engines */ +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0x8, 0); +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0xc, 0); +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0x8, 0); +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0xc, 0); +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0x8, 0); +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0xc, 0); +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0x8, 0); +	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0xc, 0); +	return 0; +} + +int qla82xx_check_for_bad_spd(struct qla_hw_data *ha) +{ +	u32 val = 0; +	val = qla82xx_rd_32(ha, BOOT_LOADER_DIMM_STATUS); +	val &= QLA82XX_BOOT_LOADER_MN_ISSUE; +	if (val & QLA82XX_PEG_TUNE_MN_SPD_ZEROED) { +		qla_printk(KERN_INFO, ha, +			"Memory DIMM SPD not programmed. " +			" Assumed valid.\n"); +		return 1; +	} else if (val) { +		qla_printk(KERN_INFO, ha, +			"Memory DIMM type incorrect.Info:%08X.\n", val); +		return 2; +	} +	return 0; +} + +int +qla82xx_fw_load_from_flash(struct qla_hw_data *ha) +{ +	int  i; +	long size = 0; +	long flashaddr = BOOTLD_START, memaddr = BOOTLD_START; +	u64 data; +	u32 high, low; +	size = (IMAGE_START - BOOTLD_START) / 8; + +	for (i = 0; i < size; i++) { +		if ((qla82xx_rom_fast_read(ha, flashaddr, (int *)&low)) || +		    (qla82xx_rom_fast_read(ha, flashaddr + 4, (int *)&high))) { +			return -1; +		} +		data = ((u64)high << 32) | low ; +		qla82xx_pci_mem_write_2M(ha, memaddr, &data, 8); +		flashaddr += 8; +		memaddr += 8; + +		if (i % 0x1000 == 0) +			msleep(1); +	} +	udelay(100); +	read_lock(&ha->hw_lock); +	if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { +		qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); +		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); +	} else { +		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d); +	} +	read_unlock(&ha->hw_lock); +	return 0; +} + +int +qla82xx_pci_mem_read_2M(struct qla_hw_data *ha, +		u64 off, void *data, int size) +{ +	int i, j = 0, k, start, end, loop, sz[2], off0[2]; +	int	      shift_amount; +	uint32_t      temp; +	uint64_t      off8, val, mem_crb, word[2] = {0, 0}; + +	/* +	 * If not MN, go check for MS or invalid. +	 */ + +	if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) +		mem_crb = QLA82XX_CRB_QDR_NET; +	else { +		mem_crb = QLA82XX_CRB_DDR_NET; +		if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) +			return qla82xx_pci_mem_read_direct(ha, +			    off, data, size); +	} + +	if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { +		off8 = off & 0xfffffff0; +		off0[0] = off & 0xf; +		sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]); +		shift_amount = 4; +	} else { +		off8 = off & 0xfffffff8; +		off0[0] = off & 0x7; +		sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]); +		shift_amount = 4; +	} +	loop = ((off0[0] + size - 1) >> shift_amount) + 1; +	off0[1] = 0; +	sz[1] = size - sz[0]; + +	/* +	 * don't lock here - write_wx gets the lock if each time +	 * write_lock_irqsave(&adapter->adapter_lock, flags); +	 * netxen_nic_pci_change_crbwindow_128M(adapter, 0); +	 */ + +	for (i = 0; i < loop; i++) { +		temp = off8 + (i << shift_amount); +		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); +		temp = 0; +		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); +		temp = MIU_TA_CTL_ENABLE; +		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); +		temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; +		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); + +		for (j = 0; j < MAX_CTL_CHECK; j++) { +			temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); +			if ((temp & MIU_TA_CTL_BUSY) == 0) +				break; +		} + +		if (j >= MAX_CTL_CHECK) { +			if (printk_ratelimit()) +				dev_err(&ha->pdev->dev, +				    "failed to read through agent\n"); +			break; +		} + +		start = off0[i] >> 2; +		end   = (off0[i] + sz[i] - 1) >> 2; +		for (k = start; k <= end; k++) { +			temp = qla82xx_rd_32(ha, +					mem_crb + MIU_TEST_AGT_RDDATA(k)); +			word[i] |= ((uint64_t)temp << (32 * (k & 1))); +		} +	} + +	/* +	 * netxen_nic_pci_change_crbwindow_128M(adapter, 1); +	 * write_unlock_irqrestore(&adapter->adapter_lock, flags); +	 */ + +	if (j >= MAX_CTL_CHECK) +		return -1; + +	if ((off0[0] & 7) == 0) { +		val = word[0]; +	} else { +		val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) | +			((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8)); +	} + +	switch (size) { +	case 1: +		*(uint8_t  *)data = val; +		break; +	case 2: +		*(uint16_t *)data = val; +		break; +	case 4: +		*(uint32_t *)data = val; +		break; +	case 8: +		*(uint64_t *)data = val; +		break; +	} +	return 0; +} + +int +qla82xx_pci_mem_write_2M(struct qla_hw_data *ha, +		u64 off, void *data, int size) +{ +	int i, j, ret = 0, loop, sz[2], off0; +	int scale, shift_amount, p3p, startword; +	uint32_t temp; +	uint64_t off8, mem_crb, tmpw, word[2] = {0, 0}; + +	/* +	 * If not MN, go check for MS or invalid. +	 */ +	if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) +		mem_crb = QLA82XX_CRB_QDR_NET; +	else { +		mem_crb = QLA82XX_CRB_DDR_NET; +		if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) +			return qla82xx_pci_mem_write_direct(ha, +			    off, data, size); +	} + +	off0 = off & 0x7; +	sz[0] = (size < (8 - off0)) ? size : (8 - off0); +	sz[1] = size - sz[0]; + +	if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { +		off8 = off & 0xfffffff0; +		loop = (((off & 0xf) + size - 1) >> 4) + 1; +		shift_amount = 4; +		scale = 2; +		p3p = 1; +		startword = (off & 0xf)/8; +	} else { +		off8 = off & 0xfffffff8; +		loop = ((off0 + size - 1) >> 3) + 1; +		shift_amount = 3; +		scale = 1; +		p3p = 0; +		startword = 0; +	} + +	if (p3p || (size != 8) || (off0 != 0)) { +		for (i = 0; i < loop; i++) { +			if (qla82xx_pci_mem_read_2M(ha, off8 + +			    (i << shift_amount), &word[i * scale], 8)) +				return -1; +		} +	} + +	switch (size) { +	case 1: +		tmpw = *((uint8_t *)data); +		break; +	case 2: +		tmpw = *((uint16_t *)data); +		break; +	case 4: +		tmpw = *((uint32_t *)data); +		break; +	case 8: +	default: +		tmpw = *((uint64_t *)data); +		break; +	} + +	if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { +		if (sz[0] == 8) { +			word[startword] = tmpw; +		} else { +			word[startword] &= +				~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); +			word[startword] |= tmpw << (off0 * 8); +		} +		if (sz[1] != 0) { +			word[startword+1] &= ~(~0ULL << (sz[1] * 8)); +			word[startword+1] |= tmpw >> (sz[0] * 8); +		} +	} else { +		word[startword] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); +		word[startword] |= tmpw << (off0 * 8); + +		if (loop == 2) { +			word[1] &= ~(~0ULL << (sz[1] * 8)); +			word[1] |= tmpw >> (sz[0] * 8); +		} +	} + +	/* +	 * don't lock here - write_wx gets the lock if each time +	 * write_lock_irqsave(&adapter->adapter_lock, flags); +	 * netxen_nic_pci_change_crbwindow_128M(adapter, 0); +	 */ +	for (i = 0; i < loop; i++) { +		temp = off8 + (i << shift_amount); +		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); +		temp = 0; +		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); +		temp = word[i * scale] & 0xffffffff; +		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); +		temp = (word[i * scale] >> 32) & 0xffffffff; +		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); +		if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { +			temp = word[i*scale + 1] & 0xffffffff; +			qla82xx_wr_32(ha, mem_crb + +			    MIU_TEST_AGT_WRDATA_UPPER_LO, temp); +			temp = (word[i*scale + 1] >> 32) & 0xffffffff; +			qla82xx_wr_32(ha, mem_crb + +			    MIU_TEST_AGT_WRDATA_UPPER_HI, temp); +		} + +		temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; +		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); +		temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; +		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); + +		for (j = 0; j < MAX_CTL_CHECK; j++) { +			temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); +			if ((temp & MIU_TA_CTL_BUSY) == 0) +				break; +		} + +		if (j >= MAX_CTL_CHECK) { +			if (printk_ratelimit()) +				dev_err(&ha->pdev->dev, +				    "failed to write through agent\n"); +			ret = -1; +			break; +		} +	} + +	return ret; +} + +/* PCI related functions */ +char * +qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str) +{ +	int pcie_reg; +	struct qla_hw_data *ha = vha->hw; +	char lwstr[6]; +	uint16_t lnk; + +	pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP); +	pci_read_config_word(ha->pdev, pcie_reg + PCI_EXP_LNKSTA, &lnk); +	ha->link_width = (lnk >> 4) & 0x3f; + +	strcpy(str, "PCIe ("); +	strcat(str, "2.5Gb/s "); +	snprintf(lwstr, sizeof(lwstr), "x%d)", ha->link_width); +	strcat(str, lwstr); +	return str; +} + +int qla82xx_pci_region_offset(struct pci_dev *pdev, int region) +{ +	unsigned long val = 0; +	u32 control; + +	switch (region) { +	case 0: +		val = 0; +		break; +	case 1: +		pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control); +		val = control + QLA82XX_MSIX_TBL_SPACE; +		break; +	} +	return val; +} + +int qla82xx_pci_region_len(struct pci_dev *pdev, int region) +{ +	unsigned long val = 0; +	u32 control; +	switch (region) { +	case 0: +		pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control); +		val = control; +		break; +	case 1: +		val = pci_resource_len(pdev, 0) - +		    qla82xx_pci_region_offset(pdev, 1); +		break; +	} +	return val; +} + +int +qla82xx_iospace_config(struct qla_hw_data *ha) +{ +	uint32_t len = 0; + +	if (pci_request_regions(ha->pdev, QLA2XXX_DRIVER_NAME)) { +		qla_printk(KERN_WARNING, ha, +			"Failed to reserve selected regions (%s)\n", +			pci_name(ha->pdev)); +		goto iospace_error_exit; +	} + +	/* Use MMIO operations for all accesses. */ +	if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) { +		qla_printk(KERN_ERR, ha, +			"region #0 not an MMIO resource (%s), aborting\n", +			pci_name(ha->pdev)); +		goto iospace_error_exit; +	} + +	len = pci_resource_len(ha->pdev, 0); +	ha->nx_pcibase = +	    (unsigned long)ioremap(pci_resource_start(ha->pdev, 0), len); +	if (!ha->nx_pcibase) { +		qla_printk(KERN_ERR, ha, +		    "cannot remap pcibase MMIO (%s), aborting\n", +		    pci_name(ha->pdev)); +		pci_release_regions(ha->pdev); +		goto iospace_error_exit; +	} + +	/* Mapping of IO base pointer */ +	ha->iobase = (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase + +	    0xbc000 + (ha->pdev->devfn << 11)); + +	if (!ql2xdbwr) { +		ha->nxdb_wr_ptr = +		    (unsigned long)ioremap((pci_resource_start(ha->pdev, 4) + +		    (ha->pdev->devfn << 12)), 4); +		if (!ha->nxdb_wr_ptr) { +			qla_printk(KERN_ERR, ha, +			    "cannot remap MMIO (%s), aborting\n", +			    pci_name(ha->pdev)); +			pci_release_regions(ha->pdev); +			goto iospace_error_exit; +		} + +		/* Mapping of IO base pointer, +		 * door bell read and write pointer +		 */ +		ha->nxdb_rd_ptr = (uint8_t *) ha->nx_pcibase + (512 * 1024) + +		    (ha->pdev->devfn * 8); +	} else { +		ha->nxdb_wr_ptr = (ha->pdev->devfn == 6 ? +			QLA82XX_CAMRAM_DB1 : +			QLA82XX_CAMRAM_DB2); +	} + +	ha->max_req_queues = ha->max_rsp_queues = 1; +	ha->msix_count = ha->max_rsp_queues + 1; +	return 0; + +iospace_error_exit: +	return -ENOMEM; +} + +/* GS related functions */ + +/* Initialization related functions */ + +/** + * qla82xx_pci_config() - Setup ISP82xx PCI configuration registers. + * @ha: HA context + * + * Returns 0 on success. +*/ +int +qla82xx_pci_config(scsi_qla_host_t *vha) +{ +	struct qla_hw_data *ha = vha->hw; +	int ret; + +	pci_set_master(ha->pdev); +	ret = pci_set_mwi(ha->pdev); +	ha->chip_revision = ha->pdev->revision; +	return 0; +} + +/** + * qla82xx_reset_chip() - Setup ISP82xx PCI configuration registers. + * @ha: HA context + * + * Returns 0 on success. + */ +void +qla82xx_reset_chip(scsi_qla_host_t *vha) +{ +	struct qla_hw_data *ha = vha->hw; +	ha->isp_ops->disable_intrs(ha); +} + +void qla82xx_config_rings(struct scsi_qla_host *vha) +{ +	struct qla_hw_data *ha = vha->hw; +	struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; +	struct init_cb_81xx *icb; +	struct req_que *req = ha->req_q_map[0]; +	struct rsp_que *rsp = ha->rsp_q_map[0]; + +	/* Setup ring parameters in initialization control block. */ +	icb = (struct init_cb_81xx *)ha->init_cb; +	icb->request_q_outpointer = __constant_cpu_to_le16(0); +	icb->response_q_inpointer = __constant_cpu_to_le16(0); +	icb->request_q_length = cpu_to_le16(req->length); +	icb->response_q_length = cpu_to_le16(rsp->length); +	icb->request_q_address[0] = cpu_to_le32(LSD(req->dma)); +	icb->request_q_address[1] = cpu_to_le32(MSD(req->dma)); +	icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); +	icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); + +	icb->version = 1; +	icb->frame_payload_size = 2112; +	icb->execution_throttle = 8; +	icb->exchange_count = 128; +	icb->login_retry_count = 8; + +	WRT_REG_DWORD((unsigned long  __iomem *)®->req_q_out[0], 0); +	WRT_REG_DWORD((unsigned long  __iomem *)®->rsp_q_in[0], 0); +	WRT_REG_DWORD((unsigned long  __iomem *)®->rsp_q_out[0], 0); +} + +void qla82xx_reset_adapter(struct scsi_qla_host *vha) +{ +	struct qla_hw_data *ha = vha->hw; +	vha->flags.online = 0; +	qla2x00_try_to_stop_firmware(vha); +	ha->isp_ops->disable_intrs(ha); +} + +int qla82xx_fw_load_from_blob(struct qla_hw_data *ha) +{ +	u64 *ptr64; +	u32 i, flashaddr, size; +	__le64 data; + +	size = (IMAGE_START - BOOTLD_START) / 8; + +	ptr64 = (u64 *)&ha->hablob->fw->data[BOOTLD_START]; +	flashaddr = BOOTLD_START; + +	for (i = 0; i < size; i++) { +		data = cpu_to_le64(ptr64[i]); +		qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8); +		flashaddr += 8; +	} + +	size = *(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]; +	size = (__force u32)cpu_to_le32(size) / 8; +	ptr64 = (u64 *)&ha->hablob->fw->data[IMAGE_START]; +	flashaddr = FLASH_ADDR_START; + +	for (i = 0; i < size; i++) { +		data = cpu_to_le64(ptr64[i]); + +		if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8)) +			return -EIO; +		flashaddr += 8; +	} + +	/* Write a magic value to CAMRAM register +	 * at a specified offset to indicate +	 * that all data is written and +	 * ready for firmware to initialize. +	 */ +	qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), 0x12345678); + +	if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { +		qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); +		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); +	} else +		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d); +	return 0; +} + +int qla82xx_check_cmdpeg_state(struct qla_hw_data *ha) +{ +	u32 val = 0; +	int retries = 60; + +	do { +		read_lock(&ha->hw_lock); +		val = qla82xx_rd_32(ha, CRB_CMDPEG_STATE); +		read_unlock(&ha->hw_lock); + +		switch (val) { +		case PHAN_INITIALIZE_COMPLETE: +		case PHAN_INITIALIZE_ACK: +			return QLA_SUCCESS; +		case PHAN_INITIALIZE_FAILED: +			break; +		default: +			break; +		} +		qla_printk(KERN_WARNING, ha, +			"CRB_CMDPEG_STATE: 0x%x and retries: 0x%x\n", +			val, retries); + +		msleep(500); + +	} while (--retries); + +	qla_printk(KERN_INFO, ha, +	    "Cmd Peg initialization failed: 0x%x.\n", val); + +	qla82xx_check_for_bad_spd(ha); +	val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_PEGTUNE_DONE); +	read_lock(&ha->hw_lock); +	qla82xx_wr_32(ha, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED); +	read_unlock(&ha->hw_lock); +	return QLA_FUNCTION_FAILED; +} + +int qla82xx_check_rcvpeg_state(struct qla_hw_data *ha) +{ +	u32 val = 0; +	int retries = 60; + +	do { +		read_lock(&ha->hw_lock); +		val = qla82xx_rd_32(ha, CRB_RCVPEG_STATE); +		read_unlock(&ha->hw_lock); + +		switch (val) { +		case PHAN_INITIALIZE_COMPLETE: +		case PHAN_INITIALIZE_ACK: +			return QLA_SUCCESS; +		case PHAN_INITIALIZE_FAILED: +			break; +		default: +			break; +		} + +		qla_printk(KERN_WARNING, ha, +			"CRB_RCVPEG_STATE: 0x%x and retries: 0x%x\n", +			val, retries); + +		msleep(500); + +	} while (--retries); + +	qla_printk(KERN_INFO, ha, +		"Rcv Peg initialization failed: 0x%x.\n", val); +	read_lock(&ha->hw_lock); +	qla82xx_wr_32(ha, CRB_RCVPEG_STATE, PHAN_INITIALIZE_FAILED); +	read_unlock(&ha->hw_lock); +	return QLA_FUNCTION_FAILED; +} + +/* ISR related functions */ +uint32_t qla82xx_isr_int_target_mask_enable[8] = { +	ISR_INT_TARGET_MASK, ISR_INT_TARGET_MASK_F1, +	ISR_INT_TARGET_MASK_F2, ISR_INT_TARGET_MASK_F3, +	ISR_INT_TARGET_MASK_F4, ISR_INT_TARGET_MASK_F5, +	ISR_INT_TARGET_MASK_F7, ISR_INT_TARGET_MASK_F7 +}; + +uint32_t qla82xx_isr_int_target_status[8] = { +	ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1, +	ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3, +	ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5, +	ISR_INT_TARGET_STATUS_F7, ISR_INT_TARGET_STATUS_F7 +}; + +static struct qla82xx_legacy_intr_set legacy_intr[] = \ +	QLA82XX_LEGACY_INTR_CONFIG; + +/* + * qla82xx_mbx_completion() - Process mailbox command completions. + * @ha: SCSI driver HA context + * @mb0: Mailbox0 register + */ +void +qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) +{ +	uint16_t	cnt; +	uint16_t __iomem *wptr; +	struct qla_hw_data *ha = vha->hw; +	struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; +	wptr = (uint16_t __iomem *)®->mailbox_out[1]; + +	/* Load return mailbox registers. */ +	ha->flags.mbox_int = 1; +	ha->mailbox_out[0] = mb0; + +	for (cnt = 1; cnt < ha->mbx_count; cnt++) { +		ha->mailbox_out[cnt] = RD_REG_WORD(wptr); +		wptr++; +	} + +	if (ha->mcp) { +		DEBUG3_11(printk(KERN_INFO "%s(%ld): " +			"Got mailbox completion. cmd=%x.\n", +			__func__, vha->host_no, ha->mcp->mb[0])); +	} else { +		qla_printk(KERN_INFO, ha, +			"%s(%ld): MBX pointer ERROR!\n", +			__func__, vha->host_no); +	} +} + +/* + * qla82xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. + * @irq: + * @dev_id: SCSI driver HA context + * @regs: + * + * Called by system whenever the host adapter generates an interrupt. + * + * Returns handled flag. + */ +irqreturn_t +qla82xx_intr_handler(int irq, void *dev_id) +{ +	scsi_qla_host_t	*vha; +	struct qla_hw_data *ha; +	struct rsp_que *rsp; +	struct device_reg_82xx __iomem *reg; +	int status = 0, status1 = 0; +	unsigned long	flags; +	unsigned long	iter; +	uint32_t	stat; +	uint16_t	mb[4]; + +	rsp = (struct rsp_que *) dev_id; +	if (!rsp) { +		printk(KERN_INFO +			"%s(): NULL response queue pointer\n", __func__); +		return IRQ_NONE; +	} +	ha = rsp->hw; + +	if (!ha->flags.msi_enabled) { +		status = qla82xx_rd_32(ha, ISR_INT_VECTOR); +		if (!(status & ha->nx_legacy_intr.int_vec_bit)) +			return IRQ_NONE; + +		status1 = qla82xx_rd_32(ha, ISR_INT_STATE_REG); +		if (!ISR_IS_LEGACY_INTR_TRIGGERED(status1)) +			return IRQ_NONE; +	} + +	/* clear the interrupt */ +	qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff); + +	/* read twice to ensure write is flushed */ +	qla82xx_rd_32(ha, ISR_INT_VECTOR); +	qla82xx_rd_32(ha, ISR_INT_VECTOR); + +	reg = &ha->iobase->isp82; + +	spin_lock_irqsave(&ha->hardware_lock, flags); +	vha = pci_get_drvdata(ha->pdev); +	for (iter = 1; iter--; ) { + +		if (RD_REG_DWORD(®->host_int)) { +			stat = RD_REG_DWORD(®->host_status); +			if ((stat & HSRX_RISC_INT) == 0) +				break; + +			switch (stat & 0xff) { +			case 0x1: +			case 0x2: +			case 0x10: +			case 0x11: +				qla82xx_mbx_completion(vha, MSW(stat)); +				status |= MBX_INTERRUPT; +				break; +			case 0x12: +				mb[0] = MSW(stat); +				mb[1] = RD_REG_WORD(®->mailbox_out[1]); +				mb[2] = RD_REG_WORD(®->mailbox_out[2]); +				mb[3] = RD_REG_WORD(®->mailbox_out[3]); +				qla2x00_async_event(vha, rsp, mb); +				break; +			case 0x13: +				qla24xx_process_response_queue(vha, rsp); +				break; +			default: +				DEBUG2(printk("scsi(%ld): " +					" Unrecognized interrupt type (%d).\n", +					vha->host_no, stat & 0xff)); +				break; +			} +		} +		WRT_REG_DWORD(®->host_int, 0); +	} +	spin_unlock_irqrestore(&ha->hardware_lock, flags); +	if (!ha->flags.msi_enabled) +		qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff); + +#ifdef QL_DEBUG_LEVEL_17 +	if (!irq && ha->flags.eeh_busy) +		qla_printk(KERN_WARNING, ha, +		    "isr: status %x, cmd_flags %lx, mbox_int %x, stat %x\n", +		    status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat); +#endif + +	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && +	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) { +		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); +		complete(&ha->mbx_intr_comp); +	} +	return IRQ_HANDLED; +} + +irqreturn_t +qla82xx_msix_default(int irq, void *dev_id) +{ +	scsi_qla_host_t	*vha; +	struct qla_hw_data *ha; +	struct rsp_que *rsp; +	struct device_reg_82xx __iomem *reg; +	int status = 0; +	unsigned long flags; +	uint32_t stat; +	uint16_t mb[4]; + +	rsp = (struct rsp_que *) dev_id; +	if (!rsp) { +		printk(KERN_INFO +			"%s(): NULL response queue pointer\n", __func__); +		return IRQ_NONE; +	} +	ha = rsp->hw; + +	reg = &ha->iobase->isp82; + +	spin_lock_irqsave(&ha->hardware_lock, flags); +	vha = pci_get_drvdata(ha->pdev); +	do { +		if (RD_REG_DWORD(®->host_int)) { +			stat = RD_REG_DWORD(®->host_status); +			if ((stat & HSRX_RISC_INT) == 0) +				break; + +			switch (stat & 0xff) { +			case 0x1: +			case 0x2: +			case 0x10: +			case 0x11: +				qla82xx_mbx_completion(vha, MSW(stat)); +				status |= MBX_INTERRUPT; +				break; +			case 0x12: +				mb[0] = MSW(stat); +				mb[1] = RD_REG_WORD(®->mailbox_out[1]); +				mb[2] = RD_REG_WORD(®->mailbox_out[2]); +				mb[3] = RD_REG_WORD(®->mailbox_out[3]); +				qla2x00_async_event(vha, rsp, mb); +				break; +			case 0x13: +				qla24xx_process_response_queue(vha, rsp); +				break; +			default: +				DEBUG2(printk("scsi(%ld): " +					" Unrecognized interrupt type (%d).\n", +					vha->host_no, stat & 0xff)); +				break; +			} +		} +		WRT_REG_DWORD(®->host_int, 0); +	} while (0); + +	spin_unlock_irqrestore(&ha->hardware_lock, flags); + +#ifdef QL_DEBUG_LEVEL_17 +	if (!irq && ha->flags.eeh_busy) +		qla_printk(KERN_WARNING, ha, +			"isr: status %x, cmd_flags %lx, mbox_int %x, stat %x\n", +			status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat); +#endif + +	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && +		(status & MBX_INTERRUPT) && ha->flags.mbox_int) { +			set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); +			complete(&ha->mbx_intr_comp); +	} +	return IRQ_HANDLED; +} + +irqreturn_t +qla82xx_msix_rsp_q(int irq, void *dev_id) +{ +	scsi_qla_host_t	*vha; +	struct qla_hw_data *ha; +	struct rsp_que *rsp; +	struct device_reg_82xx __iomem *reg; + +	rsp = (struct rsp_que *) dev_id; +	if (!rsp) { +		printk(KERN_INFO +			"%s(): NULL response queue pointer\n", __func__); +		return IRQ_NONE; +	} + +	ha = rsp->hw; +	reg = &ha->iobase->isp82; +	spin_lock_irq(&ha->hardware_lock); +	vha = pci_get_drvdata(ha->pdev); +	qla24xx_process_response_queue(vha, rsp); +	WRT_REG_DWORD(®->host_int, 0); +	spin_unlock_irq(&ha->hardware_lock); +	return IRQ_HANDLED; +} + +void +qla82xx_poll(int irq, void *dev_id) +{ +	scsi_qla_host_t	*vha; +	struct qla_hw_data *ha; +	struct rsp_que *rsp; +	struct device_reg_82xx __iomem *reg; +	int status = 0; +	uint32_t stat; +	uint16_t mb[4]; +	unsigned long flags; + +	rsp = (struct rsp_que *) dev_id; +	if (!rsp) { +		printk(KERN_INFO +			"%s(): NULL response queue pointer\n", __func__); +		return; +	} +	ha = rsp->hw; + +	reg = &ha->iobase->isp82; +	spin_lock_irqsave(&ha->hardware_lock, flags); +	vha = pci_get_drvdata(ha->pdev); + +	if (RD_REG_DWORD(®->host_int)) { +		stat = RD_REG_DWORD(®->host_status); +		switch (stat & 0xff) { +		case 0x1: +		case 0x2: +		case 0x10: +		case 0x11: +			qla82xx_mbx_completion(vha, MSW(stat)); +			status |= MBX_INTERRUPT; +			break; +		case 0x12: +			mb[0] = MSW(stat); +			mb[1] = RD_REG_WORD(®->mailbox_out[1]); +			mb[2] = RD_REG_WORD(®->mailbox_out[2]); +			mb[3] = RD_REG_WORD(®->mailbox_out[3]); +			qla2x00_async_event(vha, rsp, mb); +			break; +		case 0x13: +			qla24xx_process_response_queue(vha, rsp); +			break; +		default: +			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type " +				"(%d).\n", +				vha->host_no, stat & 0xff)); +			break; +		} +	} +	WRT_REG_DWORD(®->host_int, 0); +	spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +void +qla82xx_enable_intrs(struct qla_hw_data *ha) +{ +	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); +	qla82xx_mbx_intr_enable(vha); +	spin_lock_irq(&ha->hardware_lock); +	qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff); +	spin_unlock_irq(&ha->hardware_lock); +	ha->interrupts_on = 1; +} + +void +qla82xx_disable_intrs(struct qla_hw_data *ha) +{ +	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); +	qla82xx_mbx_intr_disable(vha); +	spin_lock_irq(&ha->hardware_lock); +	qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400); +	spin_unlock_irq(&ha->hardware_lock); +	ha->interrupts_on = 0; +} + +void qla82xx_init_flags(struct qla_hw_data *ha) +{ +	struct qla82xx_legacy_intr_set *nx_legacy_intr; + +	/* ISP 8021 initializations */ +	rwlock_init(&ha->hw_lock); +	ha->qdr_sn_window = -1; +	ha->ddr_mn_window = -1; +	ha->curr_window = 255; +	ha->portnum = PCI_FUNC(ha->pdev->devfn); +	nx_legacy_intr = &legacy_intr[ha->portnum]; +	ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; +	ha->nx_legacy_intr.tgt_status_reg = nx_legacy_intr->tgt_status_reg; +	ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; +	ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; +} + +static inline void +qla82xx_set_drv_active(scsi_qla_host_t *vha) +{ +	uint32_t drv_active; +	struct qla_hw_data *ha = vha->hw; + +	drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); + +	/* If reset value is all FF's, initialize DRV_ACTIVE */ +	if (drv_active == 0xffffffff) { +		qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, 0); +		drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); +	} +	drv_active |= (1 << (ha->portnum * 4)); +	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); +} + +inline void +qla82xx_clear_drv_active(struct qla_hw_data *ha) +{ +	uint32_t drv_active; + +	drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); +	drv_active &= ~(1 << (ha->portnum * 4)); +	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); +} + +static inline int +qla82xx_need_reset(struct qla_hw_data *ha) +{ +	uint32_t drv_state; +	int rval; + +	drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); +	rval = drv_state & (1 << (ha->portnum * 4)); +	return rval; +} + +static inline void +qla82xx_set_rst_ready(struct qla_hw_data *ha) +{ +	uint32_t drv_state; +	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); + +	drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); + +	/* If reset value is all FF's, initialize DRV_STATE */ +	if (drv_state == 0xffffffff) { +		qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); +		drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); +	} +	drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); +	qla_printk(KERN_INFO, ha, +		"%s(%ld):drv_state = 0x%x\n", +		__func__, vha->host_no, drv_state); +	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); +} + +static inline void +qla82xx_clear_rst_ready(struct qla_hw_data *ha) +{ +	uint32_t drv_state; + +	drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); +	drv_state &= ~(QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); +	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); +} + +static inline void +qla82xx_set_qsnt_ready(struct qla_hw_data *ha) +{ +	uint32_t qsnt_state; + +	qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); +	qsnt_state |= (QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4)); +	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state); +} + +int qla82xx_load_fw(scsi_qla_host_t *vha) +{ +	int rst; +	struct fw_blob *blob; +	struct qla_hw_data *ha = vha->hw; + +	/* Put both the PEG CMD and RCV PEG to default state +	 * of 0 before resetting the hardware +	 */ +	qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0); +	qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0); + +	if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) { +		qla_printk(KERN_ERR, ha, +			"%s: Error during CRB Initialization\n", __func__); +		return QLA_FUNCTION_FAILED; +	} +	udelay(500); + +	/* Bring QM and CAMRAM out of reset */ +	rst = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET); +	rst &= ~((1 << 28) | (1 << 24)); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, rst); + +	/* +	 * FW Load priority: +	 * 1) Operational firmware residing in flash. +	 * 2) Firmware via request-firmware interface (.bin file). +	 */ +	if (ql2xfwloadbin == 2) +		goto try_blob_fw; + +	qla_printk(KERN_INFO, ha, +		"Attempting to load firmware from flash\n"); + +	if (qla82xx_fw_load_from_flash(ha) == QLA_SUCCESS) { +		qla_printk(KERN_ERR, ha, +			"Firmware loaded successfully from flash\n"); +		return QLA_SUCCESS; +	} +try_blob_fw: +	qla_printk(KERN_INFO, ha, +	    "Attempting to load firmware from blob\n"); + +	/* Load firmware blob. */ +	blob = ha->hablob = qla2x00_request_firmware(vha); +	if (!blob) { +		qla_printk(KERN_ERR, ha, +			"Firmware image not present.\n"); +		goto fw_load_failed; +	} + +	if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) { +		qla_printk(KERN_ERR, ha, +			"%s: Firmware loaded successfully " +			" from binary blob\n", __func__); +		return QLA_SUCCESS; +	} else { +		qla_printk(KERN_ERR, ha, +		    "Firmware load failed from binary blob\n"); +		blob->fw = NULL; +		blob = NULL; +		goto fw_load_failed; +	} +	return QLA_SUCCESS; + +fw_load_failed: +	return QLA_FUNCTION_FAILED; +} + +static int +qla82xx_start_firmware(scsi_qla_host_t *vha) +{ +	int           pcie_cap; +	uint16_t      lnk; +	struct qla_hw_data *ha = vha->hw; + +	/* scrub dma mask expansion register */ +	qla82xx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555); + +	/* Overwrite stale initialization register values */ +	qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0); +	qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0); + +	if (qla82xx_load_fw(vha) != QLA_SUCCESS) { +		qla_printk(KERN_INFO, ha, +			"%s: Error trying to start fw!\n", __func__); +		return QLA_FUNCTION_FAILED; +	} + +	/* Handshake with the card before we register the devices. */ +	if (qla82xx_check_cmdpeg_state(ha) != QLA_SUCCESS) { +		qla_printk(KERN_INFO, ha, +			"%s: Error during card handshake!\n", __func__); +		return QLA_FUNCTION_FAILED; +	} + +	/* Negotiated Link width */ +	pcie_cap = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP); +	pci_read_config_word(ha->pdev, pcie_cap + PCI_EXP_LNKSTA, &lnk); +	ha->link_width = (lnk >> 4) & 0x3f; + +	/* Synchronize with Receive peg */ +	return qla82xx_check_rcvpeg_state(ha); +} + +static inline int +qla2xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, +	uint16_t tot_dsds) +{ +	uint32_t *cur_dsd = NULL; +	scsi_qla_host_t	*vha; +	struct qla_hw_data *ha; +	struct scsi_cmnd *cmd; +	struct	scatterlist *cur_seg; +	uint32_t *dsd_seg; +	void *next_dsd; +	uint8_t avail_dsds; +	uint8_t first_iocb = 1; +	uint32_t dsd_list_len; +	struct dsd_dma *dsd_ptr; +	struct ct6_dsd *ctx; + +	cmd = sp->cmd; + +	/* Update entry type to indicate Command Type 3 IOCB */ +	*((uint32_t *)(&cmd_pkt->entry_type)) = +		__constant_cpu_to_le32(COMMAND_TYPE_6); + +	/* No data transfer */ +	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { +		cmd_pkt->byte_count = __constant_cpu_to_le32(0); +		return 0; +	} + +	vha = sp->fcport->vha; +	ha = vha->hw; + +	/* Set transfer direction */ +	if (cmd->sc_data_direction == DMA_TO_DEVICE) { +		cmd_pkt->control_flags = +		    __constant_cpu_to_le16(CF_WRITE_DATA); +		ha->qla_stats.output_bytes += scsi_bufflen(cmd); +	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { +		cmd_pkt->control_flags = +		    __constant_cpu_to_le16(CF_READ_DATA); +		ha->qla_stats.input_bytes += scsi_bufflen(cmd); +	} + +	cur_seg = scsi_sglist(cmd); +	ctx = sp->ctx; + +	while (tot_dsds) { +		avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ? +		    QLA_DSDS_PER_IOCB : tot_dsds; +		tot_dsds -= avail_dsds; +		dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE; + +		dsd_ptr = list_first_entry(&ha->gbl_dsd_list, +		    struct dsd_dma, list); +		next_dsd = dsd_ptr->dsd_addr; +		list_del(&dsd_ptr->list); +		ha->gbl_dsd_avail--; +		list_add_tail(&dsd_ptr->list, &ctx->dsd_list); +		ctx->dsd_use_cnt++; +		ha->gbl_dsd_inuse++; + +		if (first_iocb) { +			first_iocb = 0; +			dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address; +			*dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); +			*dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); +			*dsd_seg++ = dsd_list_len; +		} else { +			*cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); +			*cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); +			*cur_dsd++ = dsd_list_len; +		} +		cur_dsd = (uint32_t *)next_dsd; +		while (avail_dsds) { +			dma_addr_t	sle_dma; + +			sle_dma = sg_dma_address(cur_seg); +			*cur_dsd++ = cpu_to_le32(LSD(sle_dma)); +			*cur_dsd++ = cpu_to_le32(MSD(sle_dma)); +			*cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg)); +			cur_seg++; +			avail_dsds--; +		} +	} + +	/* Null termination */ +	*cur_dsd++ =  0; +	*cur_dsd++ = 0; +	*cur_dsd++ = 0; +	cmd_pkt->control_flags |= CF_DATA_SEG_DESCR_ENABLE; +	return 0; +} + +/* + * qla82xx_calc_dsd_lists() - Determine number of DSD list required + * for Command Type 6. + * + * @dsds: number of data segment decriptors needed + * + * Returns the number of dsd list needed to store @dsds. + */ +inline uint16_t +qla82xx_calc_dsd_lists(uint16_t dsds) +{ +	uint16_t dsd_lists = 0; + +	dsd_lists = (dsds/QLA_DSDS_PER_IOCB); +	if (dsds % QLA_DSDS_PER_IOCB) +		dsd_lists++; +	return dsd_lists; +} + +/* + * qla82xx_start_scsi() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * + * Returns non-zero if a failure occured, else zero. + */ +int +qla82xx_start_scsi(srb_t *sp) +{ +	int		ret, nseg; +	unsigned long   flags; +	struct scsi_cmnd *cmd; +	uint32_t	*clr_ptr; +	uint32_t        index; +	uint32_t	handle; +	uint16_t	cnt; +	uint16_t	req_cnt; +	uint16_t	tot_dsds; +	struct device_reg_82xx __iomem *reg; +	uint32_t dbval; +	uint32_t *fcp_dl; +	uint8_t additional_cdb_len; +	struct ct6_dsd *ctx; +	struct scsi_qla_host *vha = sp->fcport->vha; +	struct qla_hw_data *ha = vha->hw; +	struct req_que *req = NULL; +	struct rsp_que *rsp = NULL; + +	/* Setup device pointers. */ +	ret = 0; +	reg = &ha->iobase->isp82; +	cmd = sp->cmd; +	req = vha->req; +	rsp = ha->rsp_q_map[0]; + +	/* So we know we haven't pci_map'ed anything yet */ +	tot_dsds = 0; + +	dbval = 0x04 | (ha->portnum << 5); + +	/* Send marker if required */ +	if (vha->marker_needed != 0) { +		if (qla2x00_marker(vha, req, +			rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) +			return QLA_FUNCTION_FAILED; +		vha->marker_needed = 0; +	} + +	/* Acquire ring specific lock */ +	spin_lock_irqsave(&ha->hardware_lock, flags); + +	/* Check for room in outstanding command list. */ +	handle = req->current_outstanding_cmd; +	for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { +		handle++; +		if (handle == MAX_OUTSTANDING_COMMANDS) +			handle = 1; +		if (!req->outstanding_cmds[handle]) +			break; +	} +	if (index == MAX_OUTSTANDING_COMMANDS) +		goto queuing_error; + +	/* Map the sg table so we have an accurate count of sg entries needed */ +	if (scsi_sg_count(cmd)) { +		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), +		    scsi_sg_count(cmd), cmd->sc_data_direction); +		if (unlikely(!nseg)) +			goto queuing_error; +	} else +		nseg = 0; + +	tot_dsds = nseg; + +	if (tot_dsds > ql2xshiftctondsd) { +		struct cmd_type_6 *cmd_pkt; +		uint16_t more_dsd_lists = 0; +		struct dsd_dma *dsd_ptr; +		uint16_t i; + +		more_dsd_lists = qla82xx_calc_dsd_lists(tot_dsds); +		if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN) +			goto queuing_error; + +		if (more_dsd_lists <= ha->gbl_dsd_avail) +			goto sufficient_dsds; +		else +			more_dsd_lists -= ha->gbl_dsd_avail; + +		for (i = 0; i < more_dsd_lists; i++) { +			dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); +			if (!dsd_ptr) +				goto queuing_error; + +			dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool, +				GFP_ATOMIC, &dsd_ptr->dsd_list_dma); +			if (!dsd_ptr->dsd_addr) { +				kfree(dsd_ptr); +				goto queuing_error; +			} +			list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list); +			ha->gbl_dsd_avail++; +		} + +sufficient_dsds: +		req_cnt = 1; + +		ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC); +		if (!sp->ctx) { +			DEBUG(printk(KERN_INFO +				"%s(%ld): failed to allocate" +				" ctx.\n", __func__, vha->host_no)); +			goto queuing_error; +		} +		memset(ctx, 0, sizeof(struct ct6_dsd)); +		ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool, +			GFP_ATOMIC, &ctx->fcp_cmnd_dma); +		if (!ctx->fcp_cmnd) { +			DEBUG2_3(printk("%s(%ld): failed to allocate" +				" fcp_cmnd.\n", __func__, vha->host_no)); +			goto queuing_error_fcp_cmnd; +		} + +		/* Initialize the DSD list and dma handle */ +		INIT_LIST_HEAD(&ctx->dsd_list); +		ctx->dsd_use_cnt = 0; + +		if (cmd->cmd_len > 16) { +			additional_cdb_len = cmd->cmd_len - 16; +			if ((cmd->cmd_len % 4) != 0) { +				/* SCSI command bigger than 16 bytes must be +				 * multiple of 4 +				 */ +				goto queuing_error_fcp_cmnd; +			} +			ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4; +		} else { +			additional_cdb_len = 0; +			ctx->fcp_cmnd_len = 12 + 16 + 4; +		} + +		cmd_pkt = (struct cmd_type_6 *)req->ring_ptr; +		cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + +		/* Zero out remaining portion of packet. */ +		/*    tagged queuing modifier -- default is TSK_SIMPLE (0). */ +		clr_ptr = (uint32_t *)cmd_pkt + 2; +		memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); +		cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + +		/* Set NPORT-ID and LUN number*/ +		cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); +		cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; +		cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; +		cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; +		cmd_pkt->vp_index = sp->fcport->vp_idx; + +		/* Build IOCB segments */ +		if (qla2xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds)) +			goto queuing_error_fcp_cmnd; + +		int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); + +		/* build FCP_CMND IU */ +		memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); +		int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun); +		ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; + +		if (cmd->sc_data_direction == DMA_TO_DEVICE) +			ctx->fcp_cmnd->additional_cdb_len |= 1; +		else if (cmd->sc_data_direction == DMA_FROM_DEVICE) +			ctx->fcp_cmnd->additional_cdb_len |= 2; + +		memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); + +		fcp_dl = (uint32_t *)(ctx->fcp_cmnd->cdb + 16 + +		    additional_cdb_len); +		*fcp_dl = htonl((uint32_t)scsi_bufflen(cmd)); + +		cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len); +		cmd_pkt->fcp_cmnd_dseg_address[0] = +		    cpu_to_le32(LSD(ctx->fcp_cmnd_dma)); +		cmd_pkt->fcp_cmnd_dseg_address[1] = +		    cpu_to_le32(MSD(ctx->fcp_cmnd_dma)); + +		sp->flags |= SRB_FCP_CMND_DMA_VALID; +		cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); +		/* Set total data segment count. */ +		cmd_pkt->entry_count = (uint8_t)req_cnt; +		/* Specify response queue number where +		 * completion should happen +		 */ +		cmd_pkt->entry_status = (uint8_t) rsp->id; +	} else { +		struct cmd_type_7 *cmd_pkt; +		req_cnt = qla24xx_calc_iocbs(tot_dsds); +		if (req->cnt < (req_cnt + 2)) { +			cnt = (uint16_t)RD_REG_DWORD_RELAXED( +			    ®->req_q_out[0]); +			if (req->ring_index < cnt) +				req->cnt = cnt - req->ring_index; +			else +				req->cnt = req->length - +					(req->ring_index - cnt); +		} +		if (req->cnt < (req_cnt + 2)) +			goto queuing_error; + +		cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; +		cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + +		/* Zero out remaining portion of packet. */ +		/* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ +		clr_ptr = (uint32_t *)cmd_pkt + 2; +		memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); +		cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + +		/* Set NPORT-ID and LUN number*/ +		cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); +		cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; +		cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; +		cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; +		cmd_pkt->vp_index = sp->fcport->vp_idx; + +		int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); +		host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, +			sizeof(cmd_pkt->lun)); + +		/* Load SCSI command packet. */ +		memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); +		host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); + +		cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); + +		/* Build IOCB segments */ +		qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds); + +		/* Set total data segment count. */ +		cmd_pkt->entry_count = (uint8_t)req_cnt; +		/* Specify response queue number where +		 * completion should happen. +		 */ +		cmd_pkt->entry_status = (uint8_t) rsp->id; + +	} +	/* Build command packet. */ +	req->current_outstanding_cmd = handle; +	req->outstanding_cmds[handle] = sp; +	sp->handle = handle; +	sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; +	req->cnt -= req_cnt; +	wmb(); + +	/* Adjust ring index. */ +	req->ring_index++; +	if (req->ring_index == req->length) { +		req->ring_index = 0; +		req->ring_ptr = req->ring; +	} else +		req->ring_ptr++; + +	sp->flags |= SRB_DMA_VALID; + +	/* Set chip new ring index. */ +	/* write, read and verify logic */ +	dbval = dbval | (req->id << 8) | (req->ring_index << 16); +	if (ql2xdbwr) +		qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval); +	else { +		WRT_REG_DWORD( +			(unsigned long __iomem *)ha->nxdb_wr_ptr, +			dbval); +		wmb(); +		while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { +			WRT_REG_DWORD( +				(unsigned long __iomem *)ha->nxdb_wr_ptr, +				dbval); +			wmb(); +		} +	} + +	/* Manage unprocessed RIO/ZIO commands in response queue. */ +	if (vha->flags.process_response_queue && +	    rsp->ring_ptr->signature != RESPONSE_PROCESSED) +		qla24xx_process_response_queue(vha, rsp); + +	spin_unlock_irqrestore(&ha->hardware_lock, flags); +	return QLA_SUCCESS; + +queuing_error_fcp_cmnd: +	dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma); +queuing_error: +	if (tot_dsds) +		scsi_dma_unmap(cmd); + +	if (sp->ctx) { +		mempool_free(sp->ctx, ha->ctx_mempool); +		sp->ctx = NULL; +	} +	spin_unlock_irqrestore(&ha->hardware_lock, flags); + +	return QLA_FUNCTION_FAILED; +} + +uint32_t * +qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, +	uint32_t length) +{ +	uint32_t i; +	uint32_t val; +	struct qla_hw_data *ha = vha->hw; + +	/* Dword reads to flash. */ +	for (i = 0; i < length/4; i++, faddr += 4) { +		if (qla82xx_rom_fast_read(ha, faddr, &val)) { +			qla_printk(KERN_WARNING, ha, +			    "Do ROM fast read failed\n"); +			goto done_read; +		} +		dwptr[i] = __constant_cpu_to_le32(val); +	} +done_read: +	return dwptr; +} + +int +qla82xx_unprotect_flash(struct qla_hw_data *ha) +{ +	int ret; +	uint32_t val; + +	ret = ql82xx_rom_lock_d(ha); +	if (ret < 0) { +		qla_printk(KERN_WARNING, ha, "ROM Lock failed\n"); +		return ret; +	} + +	ret = qla82xx_read_status_reg(ha, &val); +	if (ret < 0) +		goto done_unprotect; + +	val &= ~(0x7 << 2); +	ret = qla82xx_write_status_reg(ha, val); +	if (ret < 0) { +		val |= (0x7 << 2); +		qla82xx_write_status_reg(ha, val); +	} + +	if (qla82xx_write_disable_flash(ha) != 0) +		qla_printk(KERN_WARNING, ha, "Write disable failed\n"); + +done_unprotect: +	qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); +	return ret; +} + +int +qla82xx_protect_flash(struct qla_hw_data *ha) +{ +	int ret; +	uint32_t val; + +	ret = ql82xx_rom_lock_d(ha); +	if (ret < 0) { +		qla_printk(KERN_WARNING, ha, "ROM Lock failed\n"); +		return ret; +	} + +	ret = qla82xx_read_status_reg(ha, &val); +	if (ret < 0) +		goto done_protect; + +	val |= (0x7 << 2); +	/* LOCK all sectors */ +	ret = qla82xx_write_status_reg(ha, val); +	if (ret < 0) +		qla_printk(KERN_WARNING, ha, "Write status register failed\n"); + +	if (qla82xx_write_disable_flash(ha) != 0) +		qla_printk(KERN_WARNING, ha, "Write disable failed\n"); +done_protect: +	qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); +	return ret; +} + +int +qla82xx_erase_sector(struct qla_hw_data *ha, int addr) +{ +	int ret = 0; + +	ret = ql82xx_rom_lock_d(ha); +	if (ret < 0) { +		qla_printk(KERN_WARNING, ha, "ROM Lock failed\n"); +		return ret; +	} + +	qla82xx_flash_set_write_enable(ha); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3); +	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_SE); + +	if (qla82xx_wait_rom_done(ha)) { +		qla_printk(KERN_WARNING, ha, +		    "Error waiting for rom done\n"); +		ret = -1; +		goto done; +	} +	ret = qla82xx_flash_wait_write_finish(ha); +done: +	qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); +	return ret; +} + +/* + * Address and length are byte address + */ +uint8_t * +qla82xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +	uint32_t offset, uint32_t length) +{ +	scsi_block_requests(vha->host); +	qla82xx_read_flash_data(vha, (uint32_t *)buf, offset, length); +	scsi_unblock_requests(vha->host); +	return buf; +} + +static int +qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr, +	uint32_t faddr, uint32_t dwords) +{ +	int ret; +	uint32_t liter; +	uint32_t sec_mask, rest_addr; +	dma_addr_t optrom_dma; +	void *optrom = NULL; +	int page_mode = 0; +	struct qla_hw_data *ha = vha->hw; + +	ret = -1; + +	/* Prepare burst-capable write on supported ISPs. */ +	if (page_mode && !(faddr & 0xfff) && +	    dwords > OPTROM_BURST_DWORDS) { +		optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, +		    &optrom_dma, GFP_KERNEL); +		if (!optrom) { +			qla_printk(KERN_DEBUG, ha, +				"Unable to allocate memory for optrom " +				"burst write (%x KB).\n", +				OPTROM_BURST_SIZE / 1024); +		} +	} + +	rest_addr = ha->fdt_block_size - 1; +	sec_mask = ~rest_addr; + +	ret = qla82xx_unprotect_flash(ha); +	if (ret) { +		qla_printk(KERN_WARNING, ha, +			"Unable to unprotect flash for update.\n"); +		goto write_done; +	} + +	for (liter = 0; liter < dwords; liter++, faddr += 4, dwptr++) { +		/* Are we at the beginning of a sector? */ +		if ((faddr & rest_addr) == 0) { + +			ret = qla82xx_erase_sector(ha, faddr); +			if (ret) { +				DEBUG9(qla_printk(KERN_ERR, ha, +				    "Unable to erase sector: " +				    "address=%x.\n", faddr)); +				break; +			} +		} + +		/* Go with burst-write. */ +		if (optrom && (liter + OPTROM_BURST_DWORDS) <= dwords) { +			/* Copy data to DMA'ble buffer. */ +			memcpy(optrom, dwptr, OPTROM_BURST_SIZE); + +			ret = qla2x00_load_ram(vha, optrom_dma, +			    (ha->flash_data_off | faddr), +			    OPTROM_BURST_DWORDS); +			if (ret != QLA_SUCCESS) { +				qla_printk(KERN_WARNING, ha, +				    "Unable to burst-write optrom segment " +				    "(%x/%x/%llx).\n", ret, +				    (ha->flash_data_off | faddr), +				    (unsigned long long)optrom_dma); +				qla_printk(KERN_WARNING, ha, +				    "Reverting to slow-write.\n"); + +				dma_free_coherent(&ha->pdev->dev, +				    OPTROM_BURST_SIZE, optrom, optrom_dma); +				optrom = NULL; +			} else { +				liter += OPTROM_BURST_DWORDS - 1; +				faddr += OPTROM_BURST_DWORDS - 1; +				dwptr += OPTROM_BURST_DWORDS - 1; +				continue; +			} +		} + +		ret = qla82xx_write_flash_dword(ha, faddr, +		    cpu_to_le32(*dwptr)); +		if (ret) { +			DEBUG9(printk(KERN_DEBUG "%s(%ld) Unable to program" +			    "flash address=%x data=%x.\n", __func__, +			    ha->host_no, faddr, *dwptr)); +			break; +		} +	} + +	ret = qla82xx_protect_flash(ha); +	if (ret) +		qla_printk(KERN_WARNING, ha, +		    "Unable to protect flash after update.\n"); +write_done: +	if (optrom) +		dma_free_coherent(&ha->pdev->dev, +		    OPTROM_BURST_SIZE, optrom, optrom_dma); +	return ret; +} + +int +qla82xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +	uint32_t offset, uint32_t length) +{ +	int rval; + +	/* Suspend HBA. */ +	scsi_block_requests(vha->host); +	rval = qla82xx_write_flash_data(vha, (uint32_t *)buf, offset, +		length >> 2); +	scsi_unblock_requests(vha->host); + +	/* Convert return ISP82xx to generic */ +	if (rval) +		rval = QLA_FUNCTION_FAILED; +	else +		rval = QLA_SUCCESS; +	return rval; +} + +void +qla82xx_start_iocbs(srb_t *sp) +{ +	struct qla_hw_data *ha = sp->fcport->vha->hw; +	struct req_que *req = ha->req_q_map[0]; +	struct device_reg_82xx __iomem *reg; +	uint32_t dbval; + +	/* Adjust ring index. */ +	req->ring_index++; +	if (req->ring_index == req->length) { +		req->ring_index = 0; +		req->ring_ptr = req->ring; +	} else +		req->ring_ptr++; + +	reg = &ha->iobase->isp82; +	dbval = 0x04 | (ha->portnum << 5); + +	dbval = dbval | (req->id << 8) | (req->ring_index << 16); +	WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval); +	wmb(); +	while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { +		WRT_REG_DWORD((unsigned long  __iomem *)ha->nxdb_wr_ptr, dbval); +		wmb(); +	} +} + +/* + * qla82xx_device_bootstrap + *    Initialize device, set DEV_READY, start fw + * + * Note: + *      IDC lock must be held upon entry + * + * Return: + *    Success : 0 + *    Failed  : 1 + */ +static int +qla82xx_device_bootstrap(scsi_qla_host_t *vha) +{ +	int rval, i, timeout; +	uint32_t old_count, count; +	struct qla_hw_data *ha = vha->hw; + +	if (qla82xx_need_reset(ha)) +		goto dev_initialize; + +	old_count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); + +	for (i = 0; i < 10; i++) { +		timeout = msleep_interruptible(200); +		if (timeout) { +			qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, +				QLA82XX_DEV_FAILED); +			return QLA_FUNCTION_FAILED; +		} + +		count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); +		if (count != old_count) +			goto dev_ready; +	} + +dev_initialize: +	/* set to DEV_INITIALIZING */ +	qla_printk(KERN_INFO, ha, "HW State: INITIALIZING\n"); +	qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING); + +	/* Driver that sets device state to initializating sets IDC version */ +	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION); + +	qla82xx_idc_unlock(ha); +	rval = qla82xx_start_firmware(vha); +	qla82xx_idc_lock(ha); + +	if (rval != QLA_SUCCESS) { +		qla_printk(KERN_INFO, ha, "HW State: FAILED\n"); +		qla82xx_clear_drv_active(ha); +		qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED); +		return rval; +	} + +dev_ready: +	qla_printk(KERN_INFO, ha, "HW State: READY\n"); +	qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY); + +	return QLA_SUCCESS; +} + +static void +qla82xx_dev_failed_handler(scsi_qla_host_t *vha) +{ +	struct qla_hw_data *ha = vha->hw; + +	/* Disable the board */ +	qla_printk(KERN_INFO, ha, "Disabling the board\n"); + +	/* Set DEV_FAILED flag to disable timer */ +	vha->device_flags |= DFLG_DEV_FAILED; +	qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); +	qla2x00_mark_all_devices_lost(vha, 0); +	vha->flags.online = 0; +	vha->flags.init_done = 0; +} + +/* + * qla82xx_need_reset_handler + *    Code to start reset sequence + * + * Note: + *      IDC lock must be held upon entry + * + * Return: + *    Success : 0 + *    Failed  : 1 + */ +static void +qla82xx_need_reset_handler(scsi_qla_host_t *vha) +{ +	uint32_t dev_state, drv_state, drv_active; +	unsigned long reset_timeout; +	struct qla_hw_data *ha = vha->hw; +	struct req_que *req = ha->req_q_map[0]; + +	if (vha->flags.online) { +		qla82xx_idc_unlock(ha); +		qla2x00_abort_isp_cleanup(vha); +		ha->isp_ops->get_flash_version(vha, req->ring); +		ha->isp_ops->nvram_config(vha); +		qla82xx_idc_lock(ha); +	} + +	qla82xx_set_rst_ready(ha); + +	/* wait for 10 seconds for reset ack from all functions */ +	reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); + +	drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); +	drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); + +	while (drv_state != drv_active) { +		if (time_after_eq(jiffies, reset_timeout)) { +			qla_printk(KERN_INFO, ha, +				"%s: RESET TIMEOUT!\n", QLA2XXX_DRIVER_NAME); +			break; +		} +		qla82xx_idc_unlock(ha); +		msleep(1000); +		qla82xx_idc_lock(ha); +		drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); +		drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); +	} + +	dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); +	qla_printk(KERN_INFO, ha, "3:Device state is 0x%x = %s\n", dev_state, +		dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); + +	/* Force to DEV_COLD unless someone else is starting a reset */ +	if (dev_state != QLA82XX_DEV_INITIALIZING) { +		qla_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n"); +		qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD); +	} +} + +static void +qla82xx_check_fw_alive(scsi_qla_host_t *vha) +{ +	uint32_t fw_heartbeat_counter, halt_status; +	struct qla_hw_data *ha = vha->hw; + +	fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); +	if (vha->fw_heartbeat_counter == fw_heartbeat_counter) { +		vha->seconds_since_last_heartbeat++; +		/* FW not alive after 2 seconds */ +		if (vha->seconds_since_last_heartbeat == 2) { +			vha->seconds_since_last_heartbeat = 0; +			halt_status = qla82xx_rd_32(ha, +				QLA82XX_PEG_HALT_STATUS1); +			if (halt_status & HALT_STATUS_UNRECOVERABLE) { +				set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); +			} else { +				qla_printk(KERN_INFO, ha, +					"scsi(%ld): %s - detect abort needed\n", +					vha->host_no, __func__); +				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); +			} +			qla2xxx_wake_dpc(vha); +		} +	} +	vha->fw_heartbeat_counter = fw_heartbeat_counter; +} + +/* + * qla82xx_device_state_handler + *	Main state handler + * + * Note: + *      IDC lock must be held upon entry + * + * Return: + *    Success : 0 + *    Failed  : 1 + */ +int +qla82xx_device_state_handler(scsi_qla_host_t *vha) +{ +	uint32_t dev_state; +	int rval = QLA_SUCCESS; +	unsigned long dev_init_timeout; +	struct qla_hw_data *ha = vha->hw; + +	qla82xx_idc_lock(ha); +	if (!vha->flags.init_done) +		qla82xx_set_drv_active(vha); + +	dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); +	qla_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state, +		dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); + +	/* wait for 30 seconds for device to go ready */ +	dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); + +	while (1) { + +		if (time_after_eq(jiffies, dev_init_timeout)) { +			DEBUG(qla_printk(KERN_INFO, ha, +				"%s: device init failed!\n", +				QLA2XXX_DRIVER_NAME)); +			rval = QLA_FUNCTION_FAILED; +			break; +		} +		dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); +		qla_printk(KERN_INFO, ha, +			"2:Device state is 0x%x = %s\n", dev_state, +			dev_state < MAX_STATES ? +			qdev_state[dev_state] : "Unknown"); + +		switch (dev_state) { +		case QLA82XX_DEV_READY: +			goto exit; +		case QLA82XX_DEV_COLD: +			rval = qla82xx_device_bootstrap(vha); +			goto exit; +		case QLA82XX_DEV_INITIALIZING: +			qla82xx_idc_unlock(ha); +			msleep(1000); +			qla82xx_idc_lock(ha); +			break; +		case QLA82XX_DEV_NEED_RESET: +			if (!ql2xdontresethba) +				qla82xx_need_reset_handler(vha); +			break; +		case QLA82XX_DEV_NEED_QUIESCENT: +			qla82xx_set_qsnt_ready(ha); +		case QLA82XX_DEV_QUIESCENT: +			qla82xx_idc_unlock(ha); +			msleep(1000); +			qla82xx_idc_lock(ha); +			break; +		case QLA82XX_DEV_FAILED: +			qla82xx_dev_failed_handler(vha); +			rval = QLA_FUNCTION_FAILED; +			goto exit; +		default: +			qla82xx_idc_unlock(ha); +			msleep(1000); +			qla82xx_idc_lock(ha); +		} +	} +exit: +	qla82xx_idc_unlock(ha); +	return rval; +} + +void qla82xx_watchdog(scsi_qla_host_t *vha) +{ +	uint32_t dev_state; +	struct qla_hw_data *ha = vha->hw; + +	dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + +	/* don't poll if reset is going on */ +	if (!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || +		test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || +		test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))) { +		if (dev_state == QLA82XX_DEV_NEED_RESET) { +			qla_printk(KERN_WARNING, ha, +				"%s(): Adapter reset needed!\n", __func__); +			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); +			qla2xxx_wake_dpc(vha); +		} else { +			qla82xx_check_fw_alive(vha); +		} +	} +} + +int qla82xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) +{ +	int rval; +	rval = qla82xx_device_state_handler(vha); +	return rval; +} + +/* + *  qla82xx_abort_isp + *      Resets ISP and aborts all outstanding commands. + * + * Input: + *      ha           = adapter block pointer. + * + * Returns: + *      0 = success + */ +int +qla82xx_abort_isp(scsi_qla_host_t *vha) +{ +	int rval; +	struct qla_hw_data *ha = vha->hw; +	uint32_t dev_state; + +	if (vha->device_flags & DFLG_DEV_FAILED) { +		qla_printk(KERN_WARNING, ha, +			"%s(%ld): Device in failed state, " +			"Exiting.\n", __func__, vha->host_no); +		return QLA_SUCCESS; +	} + +	qla82xx_idc_lock(ha); +	dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); +	if (dev_state == QLA82XX_DEV_READY) { +		qla_printk(KERN_INFO, ha, "HW State: NEED RESET\n"); +		qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, +			QLA82XX_DEV_NEED_RESET); +	} else +		qla_printk(KERN_INFO, ha, "HW State: %s\n", +			dev_state < MAX_STATES ? +			qdev_state[dev_state] : "Unknown"); +	qla82xx_idc_unlock(ha); + +	rval = qla82xx_device_state_handler(vha); + +	qla82xx_idc_lock(ha); +	qla82xx_clear_rst_ready(ha); +	qla82xx_idc_unlock(ha); + +	if (rval == QLA_SUCCESS) +		qla82xx_restart_isp(vha); + +	if (rval) { +		vha->flags.online = 1; +		if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { +			if (ha->isp_abort_cnt == 0) { +				qla_printk(KERN_WARNING, ha, +				    "ISP error recovery failed - " +				    "board disabled\n"); +				/* +				 * The next call disables the board +				 * completely. +				 */ +				ha->isp_ops->reset_adapter(vha); +				vha->flags.online = 0; +				clear_bit(ISP_ABORT_RETRY, +				    &vha->dpc_flags); +				rval = QLA_SUCCESS; +			} else { /* schedule another ISP abort */ +				ha->isp_abort_cnt--; +				DEBUG(qla_printk(KERN_INFO, ha, +				    "qla%ld: ISP abort - retry remaining %d\n", +				    vha->host_no, ha->isp_abort_cnt)); +				rval = QLA_FUNCTION_FAILED; +			} +		} else { +			ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT; +			DEBUG(qla_printk(KERN_INFO, ha, +			    "(%ld): ISP error recovery - retrying (%d) " +			    "more times\n", vha->host_no, ha->isp_abort_cnt)); +			set_bit(ISP_ABORT_RETRY, &vha->dpc_flags); +			rval = QLA_FUNCTION_FAILED; +		} +	} +	return rval; +} + +/* + *  qla82xx_fcoe_ctx_reset + *      Perform a quick reset and aborts all outstanding commands. + *      This will only perform an FCoE context reset and avoids a full blown + *      chip reset. + * + * Input: + *      ha = adapter block pointer. + *      is_reset_path = flag for identifying the reset path. + * + * Returns: + *      0 = success + */ +int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *vha) +{ +	int rval = QLA_FUNCTION_FAILED; + +	if (vha->flags.online) { +		/* Abort all outstanding commands, so as to be requeued later */ +		qla2x00_abort_isp_cleanup(vha); +	} + +	/* Stop currently executing firmware. +	 * This will destroy existing FCoE context at the F/W end. +	 */ +	qla2x00_try_to_stop_firmware(vha); + +	/* Restart. Creates a new FCoE context on INIT_FIRMWARE. */ +	rval = qla82xx_restart_isp(vha); + +	return rval; +} + +/* + * qla2x00_wait_for_fcoe_ctx_reset + *    Wait till the FCoE context is reset. + * + * Note: + *    Does context switching here. + *    Release SPIN_LOCK (if any) before calling this routine. + * + * Return: + *    Success (fcoe_ctx reset is done) : 0 + *    Failed  (fcoe_ctx reset not completed within max loop timout ) : 1 + */ +int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha) +{ +	int status = QLA_FUNCTION_FAILED; +	unsigned long wait_reset; + +	wait_reset = jiffies + (MAX_LOOP_TIMEOUT * HZ); +	while ((test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) || +	    test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) +	    && time_before(jiffies, wait_reset)) { + +		set_current_state(TASK_UNINTERRUPTIBLE); +		schedule_timeout(HZ); + +		if (!test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) && +		    !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) { +			status = QLA_SUCCESS; +			break; +		} +	} +	DEBUG2(printk(KERN_INFO +	    "%s status=%d\n", __func__, status)); + +	return status; +} diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h new file mode 100644 index 00000000000..f8f99a5ea53 --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -0,0 +1,889 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c)  2003-2008 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ +#ifndef __QLA_NX_H +#define __QLA_NX_H + +/* + * Following are the states of the Phantom. Phantom will set them and + * Host will read to check if the fields are correct. +*/ +#define PHAN_INITIALIZE_FAILED	      0xffff +#define PHAN_INITIALIZE_COMPLETE      0xff01 + +/* Host writes the following to notify that it has done the init-handshake */ +#define PHAN_INITIALIZE_ACK	      0xf00f +#define PHAN_PEG_RCV_INITIALIZED      0xff01 + +/*CRB_RELATED*/ +#define QLA82XX_CRB_BASE	QLA82XX_CAM_RAM(0x200) +#define QLA82XX_REG(X)		(QLA82XX_CRB_BASE+(X)) + +#define CRB_CMDPEG_STATE		QLA82XX_REG(0x50) +#define CRB_RCVPEG_STATE		QLA82XX_REG(0x13c) +#define BOOT_LOADER_DIMM_STATUS		QLA82XX_REG(0x54) +#define CRB_DMA_SHIFT			QLA82XX_REG(0xcc) + +#define QLA82XX_HW_H0_CH_HUB_ADR    0x05 +#define QLA82XX_HW_H1_CH_HUB_ADR    0x0E +#define QLA82XX_HW_H2_CH_HUB_ADR    0x03 +#define QLA82XX_HW_H3_CH_HUB_ADR    0x01 +#define QLA82XX_HW_H4_CH_HUB_ADR    0x06 +#define QLA82XX_HW_H5_CH_HUB_ADR    0x07 +#define QLA82XX_HW_H6_CH_HUB_ADR    0x08 + +/*  Hub 0 */ +#define QLA82XX_HW_MN_CRB_AGT_ADR   0x15 +#define QLA82XX_HW_MS_CRB_AGT_ADR   0x25 + +/*  Hub 1 */ +#define QLA82XX_HW_PS_CRB_AGT_ADR	0x73 +#define QLA82XX_HW_QMS_CRB_AGT_ADR	0x00 +#define QLA82XX_HW_RPMX3_CRB_AGT_ADR	0x0b +#define QLA82XX_HW_SQGS0_CRB_AGT_ADR	0x01 +#define QLA82XX_HW_SQGS1_CRB_AGT_ADR	0x02 +#define QLA82XX_HW_SQGS2_CRB_AGT_ADR	0x03 +#define QLA82XX_HW_SQGS3_CRB_AGT_ADR	0x04 +#define QLA82XX_HW_C2C0_CRB_AGT_ADR	0x58 +#define QLA82XX_HW_C2C1_CRB_AGT_ADR	0x59 +#define QLA82XX_HW_C2C2_CRB_AGT_ADR	0x5a +#define QLA82XX_HW_RPMX2_CRB_AGT_ADR	0x0a +#define QLA82XX_HW_RPMX4_CRB_AGT_ADR	0x0c +#define QLA82XX_HW_RPMX7_CRB_AGT_ADR	0x0f +#define QLA82XX_HW_RPMX9_CRB_AGT_ADR	0x12 +#define QLA82XX_HW_SMB_CRB_AGT_ADR	0x18 + +/*  Hub 2 */ +#define QLA82XX_HW_NIU_CRB_AGT_ADR	0x31 +#define QLA82XX_HW_I2C0_CRB_AGT_ADR	0x19 +#define QLA82XX_HW_I2C1_CRB_AGT_ADR	0x29 + +#define QLA82XX_HW_SN_CRB_AGT_ADR	0x10 +#define QLA82XX_HW_I2Q_CRB_AGT_ADR	0x20 +#define QLA82XX_HW_LPC_CRB_AGT_ADR	0x22 +#define QLA82XX_HW_ROMUSB_CRB_AGT_ADR	0x21 +#define QLA82XX_HW_QM_CRB_AGT_ADR	0x66 +#define QLA82XX_HW_SQG0_CRB_AGT_ADR	0x60 +#define QLA82XX_HW_SQG1_CRB_AGT_ADR	0x61 +#define QLA82XX_HW_SQG2_CRB_AGT_ADR	0x62 +#define QLA82XX_HW_SQG3_CRB_AGT_ADR	0x63 +#define QLA82XX_HW_RPMX1_CRB_AGT_ADR	0x09 +#define QLA82XX_HW_RPMX5_CRB_AGT_ADR	0x0d +#define QLA82XX_HW_RPMX6_CRB_AGT_ADR	0x0e +#define QLA82XX_HW_RPMX8_CRB_AGT_ADR	0x11 + +/*  Hub 3 */ +#define QLA82XX_HW_PH_CRB_AGT_ADR	0x1A +#define QLA82XX_HW_SRE_CRB_AGT_ADR	0x50 +#define QLA82XX_HW_EG_CRB_AGT_ADR	0x51 +#define QLA82XX_HW_RPMX0_CRB_AGT_ADR	0x08 + +/*  Hub 4 */ +#define QLA82XX_HW_PEGN0_CRB_AGT_ADR	0x40 +#define QLA82XX_HW_PEGN1_CRB_AGT_ADR	0x41 +#define QLA82XX_HW_PEGN2_CRB_AGT_ADR	0x42 +#define QLA82XX_HW_PEGN3_CRB_AGT_ADR	0x43 +#define QLA82XX_HW_PEGNI_CRB_AGT_ADR	0x44 +#define QLA82XX_HW_PEGND_CRB_AGT_ADR	0x45 +#define QLA82XX_HW_PEGNC_CRB_AGT_ADR	0x46 +#define QLA82XX_HW_PEGR0_CRB_AGT_ADR	0x47 +#define QLA82XX_HW_PEGR1_CRB_AGT_ADR	0x48 +#define QLA82XX_HW_PEGR2_CRB_AGT_ADR	0x49 +#define QLA82XX_HW_PEGR3_CRB_AGT_ADR	0x4a +#define QLA82XX_HW_PEGN4_CRB_AGT_ADR	0x4b + +/*  Hub 5 */ +#define QLA82XX_HW_PEGS0_CRB_AGT_ADR	0x40 +#define QLA82XX_HW_PEGS1_CRB_AGT_ADR	0x41 +#define QLA82XX_HW_PEGS2_CRB_AGT_ADR	0x42 +#define QLA82XX_HW_PEGS3_CRB_AGT_ADR	0x43 +#define QLA82XX_HW_PEGSI_CRB_AGT_ADR	0x44 +#define QLA82XX_HW_PEGSD_CRB_AGT_ADR	0x45 +#define QLA82XX_HW_PEGSC_CRB_AGT_ADR	0x46 + +/*  Hub 6 */ +#define QLA82XX_HW_CAS0_CRB_AGT_ADR	0x46 +#define QLA82XX_HW_CAS1_CRB_AGT_ADR	0x47 +#define QLA82XX_HW_CAS2_CRB_AGT_ADR	0x48 +#define QLA82XX_HW_CAS3_CRB_AGT_ADR	0x49 +#define QLA82XX_HW_NCM_CRB_AGT_ADR	0x16 +#define QLA82XX_HW_TMR_CRB_AGT_ADR	0x17 +#define QLA82XX_HW_XDMA_CRB_AGT_ADR	0x05 +#define QLA82XX_HW_OCM0_CRB_AGT_ADR	0x06 +#define QLA82XX_HW_OCM1_CRB_AGT_ADR	0x07 + +/*  This field defines PCI/X adr [25:20] of agents on the CRB */ +/*  */ +#define QLA82XX_HW_PX_MAP_CRB_PH	0 +#define QLA82XX_HW_PX_MAP_CRB_PS	1 +#define QLA82XX_HW_PX_MAP_CRB_MN	2 +#define QLA82XX_HW_PX_MAP_CRB_MS	3 +#define QLA82XX_HW_PX_MAP_CRB_SRE	5 +#define QLA82XX_HW_PX_MAP_CRB_NIU	6 +#define QLA82XX_HW_PX_MAP_CRB_QMN	7 +#define QLA82XX_HW_PX_MAP_CRB_SQN0	8 +#define QLA82XX_HW_PX_MAP_CRB_SQN1	9 +#define QLA82XX_HW_PX_MAP_CRB_SQN2	10 +#define QLA82XX_HW_PX_MAP_CRB_SQN3	11 +#define QLA82XX_HW_PX_MAP_CRB_QMS	12 +#define QLA82XX_HW_PX_MAP_CRB_SQS0	13 +#define QLA82XX_HW_PX_MAP_CRB_SQS1	14 +#define QLA82XX_HW_PX_MAP_CRB_SQS2	15 +#define QLA82XX_HW_PX_MAP_CRB_SQS3	16 +#define QLA82XX_HW_PX_MAP_CRB_PGN0	17 +#define QLA82XX_HW_PX_MAP_CRB_PGN1	18 +#define QLA82XX_HW_PX_MAP_CRB_PGN2	19 +#define QLA82XX_HW_PX_MAP_CRB_PGN3	20 +#define QLA82XX_HW_PX_MAP_CRB_PGN4	QLA82XX_HW_PX_MAP_CRB_SQS2 +#define QLA82XX_HW_PX_MAP_CRB_PGND	21 +#define QLA82XX_HW_PX_MAP_CRB_PGNI	22 +#define QLA82XX_HW_PX_MAP_CRB_PGS0	23 +#define QLA82XX_HW_PX_MAP_CRB_PGS1	24 +#define QLA82XX_HW_PX_MAP_CRB_PGS2	25 +#define QLA82XX_HW_PX_MAP_CRB_PGS3	26 +#define QLA82XX_HW_PX_MAP_CRB_PGSD	27 +#define QLA82XX_HW_PX_MAP_CRB_PGSI	28 +#define QLA82XX_HW_PX_MAP_CRB_SN	29 +#define QLA82XX_HW_PX_MAP_CRB_EG	31 +#define QLA82XX_HW_PX_MAP_CRB_PH2	32 +#define QLA82XX_HW_PX_MAP_CRB_PS2	33 +#define QLA82XX_HW_PX_MAP_CRB_CAM	34 +#define QLA82XX_HW_PX_MAP_CRB_CAS0	35 +#define QLA82XX_HW_PX_MAP_CRB_CAS1	36 +#define QLA82XX_HW_PX_MAP_CRB_CAS2	37 +#define QLA82XX_HW_PX_MAP_CRB_C2C0	38 +#define QLA82XX_HW_PX_MAP_CRB_C2C1	39 +#define QLA82XX_HW_PX_MAP_CRB_TIMR	40 +#define QLA82XX_HW_PX_MAP_CRB_RPMX1	42 +#define QLA82XX_HW_PX_MAP_CRB_RPMX2	43 +#define QLA82XX_HW_PX_MAP_CRB_RPMX3	44 +#define QLA82XX_HW_PX_MAP_CRB_RPMX4	45 +#define QLA82XX_HW_PX_MAP_CRB_RPMX5	46 +#define QLA82XX_HW_PX_MAP_CRB_RPMX6	47 +#define QLA82XX_HW_PX_MAP_CRB_RPMX7	48 +#define QLA82XX_HW_PX_MAP_CRB_XDMA	49 +#define QLA82XX_HW_PX_MAP_CRB_I2Q	50 +#define QLA82XX_HW_PX_MAP_CRB_ROMUSB	51 +#define QLA82XX_HW_PX_MAP_CRB_CAS3	52 +#define QLA82XX_HW_PX_MAP_CRB_RPMX0	53 +#define QLA82XX_HW_PX_MAP_CRB_RPMX8	54 +#define QLA82XX_HW_PX_MAP_CRB_RPMX9	55 +#define QLA82XX_HW_PX_MAP_CRB_OCM0	56 +#define QLA82XX_HW_PX_MAP_CRB_OCM1	57 +#define QLA82XX_HW_PX_MAP_CRB_SMB	58 +#define QLA82XX_HW_PX_MAP_CRB_I2C0	59 +#define QLA82XX_HW_PX_MAP_CRB_I2C1	60 +#define QLA82XX_HW_PX_MAP_CRB_LPC	61 +#define QLA82XX_HW_PX_MAP_CRB_PGNC	62 +#define QLA82XX_HW_PX_MAP_CRB_PGR0	63 +#define QLA82XX_HW_PX_MAP_CRB_PGR1	4 +#define QLA82XX_HW_PX_MAP_CRB_PGR2	30 +#define QLA82XX_HW_PX_MAP_CRB_PGR3	41 + +/*  This field defines CRB adr [31:20] of the agents */ +/*  */ + +#define QLA82XX_HW_CRB_HUB_AGT_ADR_MN	    ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_MN_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PH	    ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PH_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_MS	    ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_MS_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PS	    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PS_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SS	    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SS_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_RPMX3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMS	    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_QMS_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS0     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SQGS0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS1     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SQGS1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS2     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SQGS2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS3     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SQGS3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C0     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_C2C0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C1     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_C2C1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_RPMX2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_RPMX4_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_RPMX7_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_RPMX9_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SMB	    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SMB_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_NIU	    ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_NIU_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0     ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_I2C0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1     ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_I2C1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SRE	    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SRE_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_EG	    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_EG_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_RPMX0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMN	    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_QM_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SQG0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SQG1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SQG2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SQG3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_RPMX1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_RPMX5_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_RPMX6_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_RPMX8_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS0     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_CAS0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS1     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_CAS1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS2     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_CAS2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS3     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_CAS3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGNI_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGND     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGND_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGN0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGN1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGN2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGN3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4	   ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGN4_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGNC_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR0     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGR0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR1     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGR1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR2     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGR2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR3     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGR3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGSI_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSD     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGSD_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGS0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGS1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGS2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGS3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSC     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_PEGSC_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAM	    ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_NCM_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_TMR_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_XDMA_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SN	    ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_SN_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q	    ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_I2Q_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB   ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_ROMUSB_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_OCM0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM1     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_OCM1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_LPC	    ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ +	QLA82XX_HW_LPC_CRB_AGT_ADR) + +#define ROMUSB_GLB				(QLA82XX_CRB_ROMUSB + 0x00000) +#define QLA82XX_ROMUSB_GLB_PEGTUNE_DONE		(ROMUSB_GLB + 0x005c) +#define QLA82XX_ROMUSB_GLB_STATUS		(ROMUSB_GLB + 0x0004) +#define QLA82XX_ROMUSB_GLB_SW_RESET		(ROMUSB_GLB + 0x0008) +#define QLA82XX_ROMUSB_ROM_ADDRESS		(ROMUSB_ROM + 0x0008) +#define QLA82XX_ROMUSB_ROM_WDATA		(ROMUSB_ROM + 0x000c) +#define QLA82XX_ROMUSB_ROM_ABYTE_CNT		(ROMUSB_ROM + 0x0010) +#define QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT	(ROMUSB_ROM + 0x0014) +#define QLA82XX_ROMUSB_ROM_RDATA		(ROMUSB_ROM + 0x0018) + +#define ROMUSB_ROM				(QLA82XX_CRB_ROMUSB + 0x10000) +#define QLA82XX_ROMUSB_ROM_INSTR_OPCODE		(ROMUSB_ROM + 0x0004) +#define QLA82XX_ROMUSB_GLB_CAS_RST		(ROMUSB_GLB + 0x0038) + +/* Lock IDs for ROM lock */ +#define ROM_LOCK_DRIVER       0x0d417340 + +#define QLA82XX_PCI_CRB_WINDOWSIZE 0x00100000	 /* all are 1MB windows */ +#define QLA82XX_PCI_CRB_WINDOW(A) \ +	(QLA82XX_PCI_CRBSPACE + (A)*QLA82XX_PCI_CRB_WINDOWSIZE) +#define QLA82XX_CRB_C2C_0 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C0) +#define QLA82XX_CRB_C2C_1 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C1) +#define QLA82XX_CRB_C2C_2 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C2) +#define QLA82XX_CRB_CAM \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAM) +#define QLA82XX_CRB_CASPER \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS) +#define QLA82XX_CRB_CASPER_0 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS0) +#define QLA82XX_CRB_CASPER_1 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS1) +#define QLA82XX_CRB_CASPER_2 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS2) +#define QLA82XX_CRB_DDR_MD \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MS) +#define QLA82XX_CRB_DDR_NET \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MN) +#define QLA82XX_CRB_EPG \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_EG) +#define QLA82XX_CRB_I2Q \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2Q) +#define QLA82XX_CRB_NIU \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_NIU) + +#define QLA82XX_CRB_PCIX_HOST \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH) +#define QLA82XX_CRB_PCIX_HOST2 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH2) +#define QLA82XX_CRB_PCIX_MD \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS) +#define QLA82XX_CRB_PCIE \ +	QLA82XX_CRB_PCIX_MD + +/* window 1 pcie slot */ +#define QLA82XX_CRB_PCIE2	 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS2) +#define QLA82XX_CRB_PEG_MD_0 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS0) +#define QLA82XX_CRB_PEG_MD_1 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS1) +#define QLA82XX_CRB_PEG_MD_2 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS2) +#define QLA82XX_CRB_PEG_MD_3 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3) +#define QLA82XX_CRB_PEG_MD_3 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3) +#define QLA82XX_CRB_PEG_MD_D \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSD) +#define QLA82XX_CRB_PEG_MD_I \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSI) +#define QLA82XX_CRB_PEG_NET_0 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN0) +#define QLA82XX_CRB_PEG_NET_1 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN1) +#define QLA82XX_CRB_PEG_NET_2 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN2) +#define QLA82XX_CRB_PEG_NET_3 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN3) +#define QLA82XX_CRB_PEG_NET_4 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN4) +#define QLA82XX_CRB_PEG_NET_D \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGND) +#define QLA82XX_CRB_PEG_NET_I \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGNI) +#define QLA82XX_CRB_PQM_MD \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMS) +#define QLA82XX_CRB_PQM_NET \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMN) +#define QLA82XX_CRB_QDR_MD \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SS) +#define QLA82XX_CRB_QDR_NET \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SN) +#define QLA82XX_CRB_ROMUSB \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_ROMUSB) +#define QLA82XX_CRB_RPMX_0 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX0) +#define QLA82XX_CRB_RPMX_1 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX1) +#define QLA82XX_CRB_RPMX_2 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX2) +#define QLA82XX_CRB_RPMX_3 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX3) +#define QLA82XX_CRB_RPMX_4 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX4) +#define QLA82XX_CRB_RPMX_5 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX5) +#define QLA82XX_CRB_RPMX_6 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX6) +#define QLA82XX_CRB_RPMX_7 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX7) +#define QLA82XX_CRB_SQM_MD_0 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS0) +#define QLA82XX_CRB_SQM_MD_1 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS1) +#define QLA82XX_CRB_SQM_MD_2 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS2) +#define QLA82XX_CRB_SQM_MD_3 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS3) +#define QLA82XX_CRB_SQM_NET_0 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN0) +#define QLA82XX_CRB_SQM_NET_1 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN1) +#define QLA82XX_CRB_SQM_NET_2 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN2) +#define QLA82XX_CRB_SQM_NET_3 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN3) +#define QLA82XX_CRB_SRE \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SRE) +#define QLA82XX_CRB_TIMER \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_TIMR) +#define QLA82XX_CRB_XDMA \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_XDMA) +#define QLA82XX_CRB_I2C0 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C0) +#define QLA82XX_CRB_I2C1 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C1) +#define QLA82XX_CRB_OCM0 \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_OCM0) +#define QLA82XX_CRB_SMB \ +	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SMB) +#define QLA82XX_CRB_MAX \ +	QLA82XX_PCI_CRB_WINDOW(64) + +/* + * ====================== BASE ADDRESSES ON-CHIP ====================== + * Base addresses of major components on-chip. + * ====================== BASE ADDRESSES ON-CHIP ====================== + */ +#define QLA82XX_ADDR_DDR_NET		(0x0000000000000000ULL) +#define QLA82XX_ADDR_DDR_NET_MAX	(0x000000000fffffffULL) + +/* Imbus address bit used to indicate a host address. This bit is + * eliminated by the pcie bar and bar select before presentation + * over pcie. */ +/* host memory via IMBUS */ +#define QLA82XX_P2_ADDR_PCIE		(0x0000000800000000ULL) +#define QLA82XX_P3_ADDR_PCIE		(0x0000008000000000ULL) +#define QLA82XX_ADDR_PCIE_MAX		(0x0000000FFFFFFFFFULL) +#define QLA82XX_ADDR_OCM0		(0x0000000200000000ULL) +#define QLA82XX_ADDR_OCM0_MAX		(0x00000002000fffffULL) +#define QLA82XX_ADDR_OCM1		(0x0000000200400000ULL) +#define QLA82XX_ADDR_OCM1_MAX		(0x00000002004fffffULL) +#define QLA82XX_ADDR_QDR_NET		(0x0000000300000000ULL) + +#define QLA82XX_P2_ADDR_QDR_NET_MAX	(0x00000003001fffffULL) +#define QLA82XX_P3_ADDR_QDR_NET_MAX	(0x0000000303ffffffULL) + +#define QLA82XX_PCI_CRBSPACE		(unsigned long)0x06000000 +#define QLA82XX_PCI_DIRECT_CRB		(unsigned long)0x04400000 +#define QLA82XX_PCI_CAMQM		(unsigned long)0x04800000 +#define QLA82XX_PCI_CAMQM_MAX		(unsigned long)0x04ffffff +#define QLA82XX_PCI_DDR_NET		(unsigned long)0x00000000 +#define QLA82XX_PCI_QDR_NET		(unsigned long)0x04000000 +#define QLA82XX_PCI_QDR_NET_MAX		(unsigned long)0x043fffff + +/* + *   Register offsets for MN + */ +#define MIU_CONTROL			(0x000) +#define MIU_TAG				(0x004) +#define MIU_TEST_AGT_CTRL		(0x090) +#define MIU_TEST_AGT_ADDR_LO		(0x094) +#define MIU_TEST_AGT_ADDR_HI		(0x098) +#define MIU_TEST_AGT_WRDATA_LO		(0x0a0) +#define MIU_TEST_AGT_WRDATA_HI		(0x0a4) +#define MIU_TEST_AGT_WRDATA(i)		(0x0a0+(4*(i))) +#define MIU_TEST_AGT_RDDATA_LO		(0x0a8) +#define MIU_TEST_AGT_RDDATA_HI		(0x0ac) +#define MIU_TEST_AGT_RDDATA(i)		(0x0a8+(4*(i))) +#define MIU_TEST_AGT_ADDR_MASK		0xfffffff8 +#define MIU_TEST_AGT_UPPER_ADDR(off)	(0) + +/* MIU_TEST_AGT_CTRL flags. work for SIU as well */ +#define MIU_TA_CTL_START	1 +#define MIU_TA_CTL_ENABLE	2 +#define MIU_TA_CTL_WRITE	4 +#define MIU_TA_CTL_BUSY		8 + +/*CAM RAM */ +# define QLA82XX_CAM_RAM_BASE		(QLA82XX_CRB_CAM + 0x02000) +# define QLA82XX_CAM_RAM(reg)		(QLA82XX_CAM_RAM_BASE + (reg)) + +#define QLA82XX_PEG_TUNE_MN_SPD_ZEROED	0x80000000 +#define QLA82XX_BOOT_LOADER_MN_ISSUE	0xff00ffff +#define QLA82XX_PORT_MODE_ADDR		(QLA82XX_CAM_RAM(0x24)) +#define QLA82XX_PEG_HALT_STATUS1	(QLA82XX_CAM_RAM(0xa8)) +#define QLA82XX_PEG_HALT_STATUS2	(QLA82XX_CAM_RAM(0xac)) +#define QLA82XX_PEG_ALIVE_COUNTER	(QLA82XX_CAM_RAM(0xb0)) + +#define QLA82XX_CAMRAM_DB1		(QLA82XX_CAM_RAM(0x1b8)) +#define QLA82XX_CAMRAM_DB2		(QLA82XX_CAM_RAM(0x1bc)) + +#define HALT_STATUS_UNRECOVERABLE	0x80000000 +#define HALT_STATUS_RECOVERABLE		0x40000000 + +/* Driver Coexistence Defines */ +#define QLA82XX_CRB_DRV_ACTIVE	     (QLA82XX_CAM_RAM(0x138)) +#define QLA82XX_CRB_DEV_STATE	     (QLA82XX_CAM_RAM(0x140)) +#define QLA82XX_CRB_DEV_PART_INFO    (QLA82XX_CAM_RAM(0x14c)) +#define QLA82XX_CRB_DRV_IDC_VERSION  (QLA82XX_CAM_RAM(0x174)) +#define QLA82XX_CRB_DRV_STATE	     (QLA82XX_CAM_RAM(0x144)) +#define QLA82XX_CRB_DRV_SCRATCH      (QLA82XX_CAM_RAM(0x148)) +#define QLA82XX_CRB_DEV_PART_INFO    (QLA82XX_CAM_RAM(0x14c)) + +/* Every driver should use these Device State */ +#define QLA82XX_DEV_COLD		1 +#define QLA82XX_DEV_INITIALIZING	2 +#define QLA82XX_DEV_READY		3 +#define QLA82XX_DEV_NEED_RESET		4 +#define QLA82XX_DEV_NEED_QUIESCENT	5 +#define QLA82XX_DEV_FAILED		6 +#define QLA82XX_DEV_QUIESCENT		7 +#define	MAX_STATES			8 /* Increment if new state added */ + +#define QLA82XX_IDC_VERSION			1 +#define QLA82XX_ROM_DEV_INIT_TIMEOUT		30 +#define QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT	10 + +#define QLA82XX_ROM_LOCK_ID		(QLA82XX_CAM_RAM(0x100)) +#define QLA82XX_CRB_WIN_LOCK_ID		(QLA82XX_CAM_RAM(0x124)) +#define QLA82XX_FW_VERSION_MAJOR	(QLA82XX_CAM_RAM(0x150)) +#define QLA82XX_FW_VERSION_MINOR	(QLA82XX_CAM_RAM(0x154)) +#define QLA82XX_FW_VERSION_SUB		(QLA82XX_CAM_RAM(0x158)) +#define QLA82XX_PCIE_REG(reg)		(QLA82XX_CRB_PCIE + (reg)) + +#define PCIE_CHICKEN3			(0x120c8) +#define PCIE_SETUP_FUNCTION		(0x12040) +#define PCIE_SETUP_FUNCTION2		(0x12048) + +#define QLA82XX_PCIX_PS_REG(reg)	(QLA82XX_CRB_PCIX_MD + (reg)) +#define QLA82XX_PCIX_PS2_REG(reg)	(QLA82XX_CRB_PCIE2 + (reg)) + +#define PCIE_SEM2_LOCK	     (0x1c010)	/* Flash lock	*/ +#define PCIE_SEM2_UNLOCK     (0x1c014)	/* Flash unlock */ +#define PCIE_SEM5_LOCK	     (0x1c028)	/* Coexistence lock   */ +#define PCIE_SEM5_UNLOCK     (0x1c02c)	/* Coexistence unlock */ +#define PCIE_SEM7_LOCK	     (0x1c038)	/* crb win lock */ +#define PCIE_SEM7_UNLOCK     (0x1c03c)	/* crbwin unlock*/ + +/* Different drive state */ +#define QLA82XX_DRVST_NOT_RDY		0 +#define	QLA82XX_DRVST_RST_RDY		1 +#define QLA82XX_DRVST_QSNT_RDY		2 + +/* + * The PCI VendorID and DeviceID for our board. + */ +#define PCI_DEVICE_ID_QLOGIC_ISP8021		0x8021 + +#define QLA82XX_MSIX_TBL_SPACE			8192 +#define QLA82XX_PCI_REG_MSIX_TBL		0x44 +#define QLA82XX_PCI_MSIX_CONTROL		0x40 + +struct crb_128M_2M_sub_block_map { +	unsigned valid; +	unsigned start_128M; +	unsigned end_128M; +	unsigned start_2M; +}; + +struct crb_128M_2M_block_map { +	struct crb_128M_2M_sub_block_map sub_block[16]; +}; + +struct crb_addr_pair { +	long addr; +	long data; +}; + +#define ADDR_ERROR ((unsigned long) 0xffffffff) +#define MAX_CTL_CHECK	1000 + +/*************************************************************************** + *		PCI related defines. + **************************************************************************/ + +/* + * Interrupt related defines. + */ +#define PCIX_TARGET_STATUS	(0x10118) +#define PCIX_TARGET_STATUS_F1	(0x10160) +#define PCIX_TARGET_STATUS_F2	(0x10164) +#define PCIX_TARGET_STATUS_F3	(0x10168) +#define PCIX_TARGET_STATUS_F4	(0x10360) +#define PCIX_TARGET_STATUS_F5	(0x10364) +#define PCIX_TARGET_STATUS_F6	(0x10368) +#define PCIX_TARGET_STATUS_F7	(0x1036c) + +#define PCIX_TARGET_MASK	(0x10128) +#define PCIX_TARGET_MASK_F1	(0x10170) +#define PCIX_TARGET_MASK_F2	(0x10174) +#define PCIX_TARGET_MASK_F3	(0x10178) +#define PCIX_TARGET_MASK_F4	(0x10370) +#define PCIX_TARGET_MASK_F5	(0x10374) +#define PCIX_TARGET_MASK_F6	(0x10378) +#define PCIX_TARGET_MASK_F7	(0x1037c) + +/* + * Message Signaled Interrupts + */ +#define PCIX_MSI_F0		(0x13000) +#define PCIX_MSI_F1		(0x13004) +#define PCIX_MSI_F2		(0x13008) +#define PCIX_MSI_F3		(0x1300c) +#define PCIX_MSI_F4		(0x13010) +#define PCIX_MSI_F5		(0x13014) +#define PCIX_MSI_F6		(0x13018) +#define PCIX_MSI_F7		(0x1301c) +#define PCIX_MSI_F(FUNC)	(0x13000 + ((FUNC) * 4)) +#define PCIX_INT_VECTOR		(0x10100) +#define PCIX_INT_MASK		(0x10104) + +/* + * Interrupt state machine and other bits. + */ +#define PCIE_MISCCFG_RC		(0x1206c) + +#define ISR_INT_TARGET_STATUS \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS)) +#define ISR_INT_TARGET_STATUS_F1 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F1)) +#define ISR_INT_TARGET_STATUS_F2 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F2)) +#define ISR_INT_TARGET_STATUS_F3 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F3)) +#define ISR_INT_TARGET_STATUS_F4 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F4)) +#define ISR_INT_TARGET_STATUS_F5 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F5)) +#define ISR_INT_TARGET_STATUS_F6 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F6)) +#define ISR_INT_TARGET_STATUS_F7 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F7)) + +#define ISR_INT_TARGET_MASK \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK)) +#define ISR_INT_TARGET_MASK_F1 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F1)) +#define ISR_INT_TARGET_MASK_F2 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F2)) +#define ISR_INT_TARGET_MASK_F3 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F3)) +#define ISR_INT_TARGET_MASK_F4 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F4)) +#define ISR_INT_TARGET_MASK_F5 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F5)) +#define ISR_INT_TARGET_MASK_F6 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F6)) +#define ISR_INT_TARGET_MASK_F7 \ +	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F7)) + +#define ISR_INT_VECTOR \ +	(QLA82XX_PCIX_PS_REG(PCIX_INT_VECTOR)) +#define ISR_INT_MASK \ +	(QLA82XX_PCIX_PS_REG(PCIX_INT_MASK)) +#define ISR_INT_STATE_REG \ +	(QLA82XX_PCIX_PS_REG(PCIE_MISCCFG_RC)) + +#define	ISR_MSI_INT_TRIGGER(FUNC) \ +	(QLA82XX_PCIX_PS_REG(PCIX_MSI_F(FUNC))) + +#define	ISR_IS_LEGACY_INTR_IDLE(VAL)		(((VAL) & 0x300) == 0) +#define	ISR_IS_LEGACY_INTR_TRIGGERED(VAL)	(((VAL) & 0x300) == 0x200) + +/* + * PCI Interrupt Vector Values. + */ +#define	PCIX_INT_VECTOR_BIT_F0	0x0080 +#define	PCIX_INT_VECTOR_BIT_F1	0x0100 +#define	PCIX_INT_VECTOR_BIT_F2	0x0200 +#define	PCIX_INT_VECTOR_BIT_F3	0x0400 +#define	PCIX_INT_VECTOR_BIT_F4	0x0800 +#define	PCIX_INT_VECTOR_BIT_F5	0x1000 +#define	PCIX_INT_VECTOR_BIT_F6	0x2000 +#define	PCIX_INT_VECTOR_BIT_F7	0x4000 + +struct qla82xx_legacy_intr_set { +	uint32_t	int_vec_bit; +	uint32_t	tgt_status_reg; +	uint32_t	tgt_mask_reg; +	uint32_t	pci_int_reg; +}; + +#define QLA82XX_LEGACY_INTR_CONFIG					\ +{									\ +	{								\ +		.int_vec_bit	=	PCIX_INT_VECTOR_BIT_F0,		\ +		.tgt_status_reg =	ISR_INT_TARGET_STATUS,		\ +		.tgt_mask_reg	=	ISR_INT_TARGET_MASK,		\ +		.pci_int_reg	=	ISR_MSI_INT_TRIGGER(0) },	\ +									\ +	{								\ +		.int_vec_bit	=	PCIX_INT_VECTOR_BIT_F1,		\ +		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F1,	\ +		.tgt_mask_reg	=	ISR_INT_TARGET_MASK_F1,		\ +		.pci_int_reg	=	ISR_MSI_INT_TRIGGER(1) },	\ +									\ +	{								\ +		.int_vec_bit	=	PCIX_INT_VECTOR_BIT_F2,		\ +		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F2,	\ +		.tgt_mask_reg	=	ISR_INT_TARGET_MASK_F2,		\ +		.pci_int_reg	=	ISR_MSI_INT_TRIGGER(2) },	\ +									\ +	{								\ +		.int_vec_bit	=	PCIX_INT_VECTOR_BIT_F3,		\ +		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F3,	\ +		.tgt_mask_reg	=	ISR_INT_TARGET_MASK_F3,		\ +		.pci_int_reg	=	ISR_MSI_INT_TRIGGER(3) },	\ +									\ +	{								\ +		.int_vec_bit	=	PCIX_INT_VECTOR_BIT_F4,		\ +		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F4,	\ +		.tgt_mask_reg	=	ISR_INT_TARGET_MASK_F4,		\ +		.pci_int_reg	=	ISR_MSI_INT_TRIGGER(4) },	\ +									\ +	{								\ +		.int_vec_bit	=	PCIX_INT_VECTOR_BIT_F5,		\ +		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F5,	\ +		.tgt_mask_reg	=	ISR_INT_TARGET_MASK_F5,		\ +		.pci_int_reg	=	ISR_MSI_INT_TRIGGER(5) },	\ +									\ +	{								\ +		.int_vec_bit	=	PCIX_INT_VECTOR_BIT_F6,		\ +		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F6,	\ +		.tgt_mask_reg	=	ISR_INT_TARGET_MASK_F6,		\ +		.pci_int_reg	=	ISR_MSI_INT_TRIGGER(6) },	\ +									\ +	{								\ +		.int_vec_bit	=	PCIX_INT_VECTOR_BIT_F7,		\ +		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F7,	\ +		.tgt_mask_reg	=	ISR_INT_TARGET_MASK_F7,		\ +		.pci_int_reg	=	ISR_MSI_INT_TRIGGER(7) },	\ +} + +#define	BOOTLD_START		0x10000 +#define	IMAGE_START		0x100000 +#define FLASH_ADDR_START	0x43000 + +/* Magic number to let user know flash is programmed */ +#define QLA82XX_BDINFO_MAGIC	0x12345678 +#define FW_SIZE_OFFSET		(0x3e840c) + +#define QLA82XX_IS_REVISION_P3PLUS(_rev_)	((_rev_) >= 0x50) +#define MIU_TEST_AGT_WRDATA_UPPER_LO		(0x0b0) +#define	MIU_TEST_AGT_WRDATA_UPPER_HI		(0x0b4) + +#ifndef readq +static inline u64 readq(void __iomem *addr) +{ +	return readl(addr) | (((u64) readl(addr + 4)) << 32LL); +} +#endif + +#ifndef writeq +static inline void writeq(u64 val, void __iomem *addr) +{ +	writel(((u32) (val)), (addr)); +	writel(((u32) (val >> 32)), (addr + 4)); +} +#endif + +/* Request and response queue size */ +#define REQUEST_ENTRY_CNT_82XX		128	/* Number of request entries. */ +#define RESPONSE_ENTRY_CNT_82XX		128	/* Number of response entries.*/ + +/* + * ISP 8021 I/O Register Set structure definitions. + */ +struct device_reg_82xx { +	uint32_t req_q_out[64];		/* Request Queue out-Pointer (64 * 4) */ +	uint32_t rsp_q_in[64];		/* Response Queue In-Pointer. */ +	uint32_t rsp_q_out[64];		/* Response Queue Out-Pointer. */ + +	uint16_t mailbox_in[32];	/* Mail box In registers */ +	uint16_t unused_1[32]; +	uint32_t hint;			/* Host interrupt register */ +#define	HINT_MBX_INT_PENDING	BIT_0 +	uint16_t unused_2[62]; +	uint16_t mailbox_out[32];	/* Mail box Out registers */ +	uint32_t unused_3[48]; + +	uint32_t host_status;		/* host status */ +#define HSRX_RISC_INT		BIT_15	/* RISC to Host interrupt. */ +#define HSRX_RISC_PAUSED	BIT_8	/* RISC Paused. */ +	uint32_t host_int;		/* Interrupt status. */ +#define ISRX_NX_RISC_INT	BIT_0	/* RISC interrupt. */ +}; + +struct fcp_cmnd { +	struct scsi_lun lun; +	uint8_t crn; +	uint8_t task_attribute; +	uint8_t task_managment; +	uint8_t additional_cdb_len; +	uint8_t cdb[260]; /* 256 for CDB len and 4 for FCP_DL */ +}; + +struct dsd_dma { +	struct list_head list; +	dma_addr_t dsd_list_dma; +	void *dsd_addr; +}; + +#define QLA_DSDS_PER_IOCB	37 +#define QLA_DSD_SIZE		12 +struct ct6_dsd { +	uint16_t fcp_cmnd_len; +	dma_addr_t fcp_cmnd_dma; +	struct fcp_cmnd *fcp_cmnd; +	int dsd_use_cnt; +	struct list_head dsd_list; +}; + +#define MBC_TOGGLE_INTR			0x10 + +/* Flash  offset */ +#define FLT_REG_BOOTLOAD_82XX	0x72 +#define FLT_REG_BOOT_CODE_82XX	0x78 +#define FLT_REG_FW_82XX		0x74 +#define FLT_REG_GOLD_FW_82XX	0x75 +#define FLT_REG_VPD_82XX	0x81 + +#define	FA_VPD_SIZE_82XX	0x400 + +#define FA_FLASH_LAYOUT_ADDR_82	0xFC400 + +/****************************************************************************** +* +*    Definitions specific to M25P flash +* +******************************************************************************* +*   Instructions +*/ +#define M25P_INSTR_WREN		0x06 +#define M25P_INSTR_WRDI		0x04 +#define M25P_INSTR_RDID		0x9f +#define M25P_INSTR_RDSR		0x05 +#define M25P_INSTR_WRSR		0x01 +#define M25P_INSTR_READ		0x03 +#define M25P_INSTR_FAST_READ	0x0b +#define M25P_INSTR_PP		0x02 +#define M25P_INSTR_SE		0xd8 +#define M25P_INSTR_BE		0xc7 +#define M25P_INSTR_DP		0xb9 +#define M25P_INSTR_RES		0xab + +#endif diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 48c37e38ed0..be1a8fcbb1f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -24,11 +24,18 @@   */  char qla2x00_version_str[40]; +static int apidev_major; +  /*   * SRB allocation cache   */  static struct kmem_cache *srb_cachep; +/* + * CT6 CTX allocation cache + */ +static struct kmem_cache *ctx_cachep; +  int ql2xlogintimeout = 20;  module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);  MODULE_PARM_DESC(ql2xlogintimeout, @@ -65,13 +72,19 @@ MODULE_PARM_DESC(ql2xextended_error_logging,  		"Option to enable extended error logging, "  		"Default is 0 - no logging. 1 - log errors."); +int ql2xshiftctondsd = 6; +module_param(ql2xshiftctondsd, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xshiftctondsd, +		"Set to control shifting of command type processing " +		"based on total number of SG elements."); +  static void qla2x00_free_device(scsi_qla_host_t *);  int ql2xfdmienable=1;  module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);  MODULE_PARM_DESC(ql2xfdmienable, -		"Enables FDMI registratons " -		"Default is 0 - no FDMI. 1 - perfom FDMI."); +		"Enables FDMI registrations. " +		"0 - no FDMI. Default is 1 - perform FDMI.");  #define MAX_Q_DEPTH    32  static int ql2xmaxqdepth = MAX_Q_DEPTH; @@ -79,6 +92,19 @@ module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);  MODULE_PARM_DESC(ql2xmaxqdepth,  		"Maximum queue depth to report for target devices."); +/* Do not change the value of this after module load */ +int ql2xenabledif = 1; +module_param(ql2xenabledif, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(ql2xenabledif, +		" Enable T10-CRC-DIF " +		" Default is 0 - No DIF Support. 1 - Enable it"); + +int ql2xenablehba_err_chk; +module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(ql2xenablehba_err_chk, +		" Enable T10-CRC-DIF Error isolation by HBA" +		" Default is 0 - Error isolation disabled, 1 - Enable it"); +  int ql2xiidmaenable=1;  module_param(ql2xiidmaenable, int, S_IRUGO|S_IRUSR);  MODULE_PARM_DESC(ql2xiidmaenable, @@ -114,6 +140,32 @@ MODULE_PARM_DESC(ql2xetsenable,  		"Enables firmware ETS burst."  		"Default is 0 - skip ETS enablement."); +int ql2xdbwr; +module_param(ql2xdbwr, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xdbwr, +	"Option to specify scheme for request queue posting\n" +	" 0 -- Regular doorbell.\n" +	" 1 -- CAMRAM doorbell (faster).\n"); + +int ql2xdontresethba; +module_param(ql2xdontresethba, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xdontresethba, +	"Option to specify reset behaviour\n" +	" 0 (Default) -- Reset on failure.\n" +	" 1 -- Do not reset on failure.\n"); + +int ql2xtargetreset = 1; +module_param(ql2xtargetreset, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xtargetreset, +		 "Enable target reset." +		 "Default is 1 - use hw defaults."); + + +int ql2xasynctmfenable; +module_param(ql2xasynctmfenable, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xasynctmfenable, +		"Enables issue of TM IOCBs asynchronously via IOCB mechanism" +		"Default is 0 - Issue TM IOCBs via mailbox mechanism.");  /*   * SCSI host template entry points   */ @@ -183,6 +235,10 @@ qla2x00_start_timer(scsi_qla_host_t *vha, void *func, unsigned long interval)  static inline void  qla2x00_restart_timer(scsi_qla_host_t *vha, unsigned long interval)  { +	/* Currently used for 82XX only. */ +	if (vha->device_flags & DFLG_DEV_FAILED) +		return; +  	mod_timer(&vha->timer, jiffies + interval * HZ);  } @@ -500,6 +556,14 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))  	if (fcport->drport)  		goto qc24_target_busy; +	if (!vha->flags.difdix_supported && +		scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { +			DEBUG2(qla_printk(KERN_ERR, ha, +			    "DIF Cap Not Reg, fail DIF capable cmd's:%x\n", +			    cmd->cmnd[0])); +			cmd->result = DID_NO_CONNECT << 16; +			goto qc24_fail_command; +	}  	if (atomic_read(&fcport->state) != FCS_ONLINE) {  		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||  		    atomic_read(&base_vha->loop_state) == LOOP_DEAD) { @@ -618,6 +682,50 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *vha)  	return (return_status);  } +/* + * qla2x00_wait_for_reset_ready + *    Wait till the HBA is online after going through + *    <= MAX_RETRIES_OF_ISP_ABORT  or + *    finally HBA is disabled ie marked offline or flash + *    operations are in progress. + * + * Input: + *     ha - pointer to host adapter structure + * + * Note: + *    Does context switching-Release SPIN_LOCK + *    (if any) before calling this routine. + * + * Return: + *    Success (Adapter is online/no flash ops) : 0 + *    Failed  (Adapter is offline/disabled/flash ops in progress) : 1 + */ +int +qla2x00_wait_for_reset_ready(scsi_qla_host_t *vha) +{ +	int		return_status; +	unsigned long	wait_online; +	struct qla_hw_data *ha = vha->hw; +	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + +	wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ); +	while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) || +	    test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || +	    test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || +	    ha->optrom_state != QLA_SWAITING || +	    ha->dpc_active) && time_before(jiffies, wait_online)) +		msleep(1000); + +	if (base_vha->flags.online &&  ha->optrom_state == QLA_SWAITING) +		return_status = QLA_SUCCESS; +	else +		return_status = QLA_FUNCTION_FAILED; + +	DEBUG2(printk("%s return_status=%d\n", __func__, return_status)); + +	return return_status; +} +  int  qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha)  { @@ -739,7 +847,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)  		if (sp == NULL)  			continue; -		if (sp->ctx) +		if ((sp->ctx) && !(sp->flags & SRB_FCP_CMND_DMA_VALID) && +		    !IS_PROT_IO(sp))  			continue;  		if (sp->cmd != cmd)  			continue; @@ -805,7 +914,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,  		sp = req->outstanding_cmds[cnt];  		if (!sp)  			continue; -		if (sp->ctx) +		if ((sp->ctx) && !IS_PROT_IO(sp))  			continue;  		if (vha->vp_idx != sp->fcport->vha->vp_idx)  			continue; @@ -834,6 +943,24 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,  	return status;  } +void qla82xx_wait_for_pending_commands(scsi_qla_host_t *vha) +{ +	int cnt; +	srb_t *sp; +	struct req_que *req = vha->req; + +	DEBUG2(qla_printk(KERN_INFO, vha->hw, +		"Waiting for pending commands\n")); +	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { +		sp = req->outstanding_cmds[cnt]; +		if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, +			sp, WAIT_HOST) == QLA_SUCCESS) { +			DEBUG2(qla_printk(KERN_INFO, vha->hw, +				"Done wait for pending commands\n")); +		} +	} +} +  static char *reset_errors[] = {  	"HBA not online",  	"HBA not ready", @@ -1004,7 +1131,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)  	qla_printk(KERN_INFO, ha,  	    "scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", vha->host_no, id, lun); -	if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) +	if (qla2x00_wait_for_reset_ready(vha) != QLA_SUCCESS)  		goto eh_host_reset_lock;  	/* @@ -1020,11 +1147,19 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)  		if (qla2x00_vp_abort_isp(vha))  			goto eh_host_reset_lock;  	} else { +		if (IS_QLA82XX(vha->hw)) { +			if (!qla82xx_fcoe_ctx_reset(vha)) { +				/* Ctx reset success */ +				ret = SUCCESS; +				goto eh_host_reset_lock; +			} +			/* fall thru if ctx reset failed */ +		}  		if (ha->wq)  			flush_workqueue(ha->wq);  		set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); -		if (qla2x00_abort_isp(base_vha)) { +		if (ha->isp_ops->abort_isp(base_vha)) {  			clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);  			/* failed. schedule dpc to try */  			set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); @@ -1064,7 +1199,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)  	struct fc_port *fcport;  	struct qla_hw_data *ha = vha->hw; -	if (ha->flags.enable_target_reset) { +	if (ql2xtargetreset == 1 && ha->flags.enable_target_reset) {  		list_for_each_entry(fcport, &vha->vp_fcports, list) {  			if (fcport->port_type != FCT_TARGET)  				continue; @@ -1078,7 +1213,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)  		}  	} -	if (ha->flags.enable_lip_full_login && !IS_QLA81XX(ha)) { +	if (ha->flags.enable_lip_full_login && !IS_QLA8XXX_TYPE(ha)) {  		ret = qla2x00_full_login_lip(vha);  		if (ret != QLA_SUCCESS) {  			DEBUG2_3(printk("%s(%ld): failed: " @@ -1125,23 +1260,28 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)  			sp = req->outstanding_cmds[cnt];  			if (sp) {  				req->outstanding_cmds[cnt] = NULL; -				if (!sp->ctx) { +				if (!sp->ctx || +					(sp->flags & SRB_FCP_CMND_DMA_VALID) || +					IS_PROT_IO(sp)) {  					sp->cmd->result = res;  					qla2x00_sp_compl(ha, sp);  				} else {  					ctx = sp->ctx; -					if (ctx->type == SRB_LOGIN_CMD || ctx->type == SRB_LOGOUT_CMD) { -						del_timer_sync(&ctx->timer); -						ctx->free(sp); +					if (ctx->type == SRB_LOGIN_CMD || +					    ctx->type == SRB_LOGOUT_CMD) { +						ctx->u.iocb_cmd->free(sp);  					} else { -						struct srb_bsg* sp_bsg = (struct srb_bsg*)sp->ctx; -						if (sp_bsg->bsg_job->request->msgcode == FC_BSG_HST_CT) +						struct fc_bsg_job *bsg_job = +						    ctx->u.bsg_job; +						if (bsg_job->request->msgcode +						    == FC_BSG_HST_CT)  							kfree(sp->fcport); -						sp_bsg->bsg_job->req->errors = 0; -						sp_bsg->bsg_job->reply->result = res; -						sp_bsg->bsg_job->job_done(sp_bsg->bsg_job); +						bsg_job->req->errors = 0; +						bsg_job->reply->result = res; +						bsg_job->job_done(bsg_job);  						kfree(sp->ctx); -						mempool_free(sp, ha->srb_mempool); +						mempool_free(sp, +							ha->srb_mempool);  					}  				}  			} @@ -1379,6 +1519,7 @@ static struct isp_operations qla2100_isp_ops = {  	.write_optrom		= qla2x00_write_optrom_data,  	.get_flash_version	= qla2x00_get_flash_version,  	.start_scsi		= qla2x00_start_scsi, +	.abort_isp		= qla2x00_abort_isp,  };  static struct isp_operations qla2300_isp_ops = { @@ -1414,6 +1555,7 @@ static struct isp_operations qla2300_isp_ops = {  	.write_optrom		= qla2x00_write_optrom_data,  	.get_flash_version	= qla2x00_get_flash_version,  	.start_scsi		= qla2x00_start_scsi, +	.abort_isp		= qla2x00_abort_isp,  };  static struct isp_operations qla24xx_isp_ops = { @@ -1449,6 +1591,7 @@ static struct isp_operations qla24xx_isp_ops = {  	.write_optrom		= qla24xx_write_optrom_data,  	.get_flash_version	= qla24xx_get_flash_version,  	.start_scsi		= qla24xx_start_scsi, +	.abort_isp		= qla2x00_abort_isp,  };  static struct isp_operations qla25xx_isp_ops = { @@ -1483,7 +1626,8 @@ static struct isp_operations qla25xx_isp_ops = {  	.read_optrom		= qla25xx_read_optrom_data,  	.write_optrom		= qla24xx_write_optrom_data,  	.get_flash_version	= qla24xx_get_flash_version, -	.start_scsi		= qla24xx_start_scsi, +	.start_scsi		= qla24xx_dif_start_scsi, +	.abort_isp		= qla2x00_abort_isp,  };  static struct isp_operations qla81xx_isp_ops = { @@ -1519,6 +1663,43 @@ static struct isp_operations qla81xx_isp_ops = {  	.write_optrom		= qla24xx_write_optrom_data,  	.get_flash_version	= qla24xx_get_flash_version,  	.start_scsi		= qla24xx_start_scsi, +	.abort_isp		= qla2x00_abort_isp, +}; + +static struct isp_operations qla82xx_isp_ops = { +	.pci_config		= qla82xx_pci_config, +	.reset_chip		= qla82xx_reset_chip, +	.chip_diag		= qla24xx_chip_diag, +	.config_rings		= qla82xx_config_rings, +	.reset_adapter		= qla24xx_reset_adapter, +	.nvram_config		= qla81xx_nvram_config, +	.update_fw_options	= qla24xx_update_fw_options, +	.load_risc		= qla82xx_load_risc, +	.pci_info_str		= qla82xx_pci_info_str, +	.fw_version_str		= qla24xx_fw_version_str, +	.intr_handler		= qla82xx_intr_handler, +	.enable_intrs		= qla82xx_enable_intrs, +	.disable_intrs		= qla82xx_disable_intrs, +	.abort_command		= qla24xx_abort_command, +	.target_reset		= qla24xx_abort_target, +	.lun_reset		= qla24xx_lun_reset, +	.fabric_login		= qla24xx_login_fabric, +	.fabric_logout		= qla24xx_fabric_logout, +	.calc_req_entries	= NULL, +	.build_iocbs		= NULL, +	.prep_ms_iocb		= qla24xx_prep_ms_iocb, +	.prep_ms_fdmi_iocb	= qla24xx_prep_ms_fdmi_iocb, +	.read_nvram		= qla24xx_read_nvram_data, +	.write_nvram		= qla24xx_write_nvram_data, +	.fw_dump		= qla24xx_fw_dump, +	.beacon_on		= qla24xx_beacon_on, +	.beacon_off		= qla24xx_beacon_off, +	.beacon_blink		= qla24xx_beacon_blink, +	.read_optrom		= qla82xx_read_optrom_data, +	.write_optrom		= qla82xx_write_optrom_data, +	.get_flash_version	= qla24xx_get_flash_version, +	.start_scsi             = qla82xx_start_scsi, +	.abort_isp		= qla82xx_abort_isp,  };  static inline void @@ -1607,10 +1788,22 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)  		ha->device_type |= DT_IIDMA;  		ha->fw_srisc_address = RISC_START_ADDRESS_2400;  		break; +	case PCI_DEVICE_ID_QLOGIC_ISP8021: +		ha->device_type |= DT_ISP8021; +		ha->device_type |= DT_ZIO_SUPPORTED; +		ha->device_type |= DT_FWI2; +		ha->fw_srisc_address = RISC_START_ADDRESS_2400; +		/* Initialize 82XX ISP flags */ +		qla82xx_init_flags(ha); +		break;  	} -	/* Get adapter physical port no from interrupt pin register. */ -	pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no); +	if (IS_QLA82XX(ha)) +		ha->port_no = !(ha->portnum & 1); +	else +		/* Get adapter physical port no from interrupt pin register. */ +		pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no); +  	if (ha->port_no & 1)  		ha->flags.port0 = 1;  	else @@ -1624,6 +1817,9 @@ qla2x00_iospace_config(struct qla_hw_data *ha)  	uint16_t msix;  	int cpus; +	if (IS_QLA82XX(ha)) +		return qla82xx_iospace_config(ha); +  	if (pci_request_selected_regions(ha->pdev, ha->bars,  	    QLA2XXX_DRIVER_NAME)) {  		qla_printk(KERN_WARNING, ha, @@ -1767,7 +1963,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)  	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||  	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||  	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 || -	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001) { +	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001 || +	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021) {  		bars = pci_select_bars(pdev, IORESOURCE_MEM);  		mem_only = 1;  	} @@ -1897,6 +2094,19 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)  		ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;  		ha->nvram_conf_off = ~0;  		ha->nvram_data_off = ~0; +	} else if (IS_QLA82XX(ha)) { +		ha->mbx_count = MAILBOX_REGISTER_COUNT; +		req_length = REQUEST_ENTRY_CNT_82XX; +		rsp_length = RESPONSE_ENTRY_CNT_82XX; +		ha->max_loop_id = SNS_LAST_LOOP_ID_2300; +		ha->init_cb_size = sizeof(struct mid_init_cb_81xx); +		ha->gid_list_info_size = 8; +		ha->optrom_size = OPTROM_SIZE_82XX; +		ha->isp_ops = &qla82xx_isp_ops; +		ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; +		ha->flash_data_off = FARX_ACCESS_FLASH_DATA; +		ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; +		ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;  	}  	mutex_init(&ha->vport_lock); @@ -1969,6 +2179,7 @@ que_init:  		" pointers\n");  		goto probe_init_failed;  	} +  	ha->rsp_q_map[0] = rsp;  	ha->req_q_map[0] = req;  	rsp->req = req; @@ -1987,6 +2198,12 @@ que_init:  		rsp->rsp_q_out =  &ha->mqiobase->isp25mq.rsp_q_out;  	} +	if (IS_QLA82XX(ha)) { +		req->req_q_out = &ha->iobase->isp82.req_q_out[0]; +		rsp->rsp_q_in = &ha->iobase->isp82.rsp_q_in[0]; +		rsp->rsp_q_out = &ha->iobase->isp82.rsp_q_out[0]; +	} +  	if (qla2x00_initialize_adapter(base_vha)) {  		qla_printk(KERN_WARNING, ha,  		    "Failed to initialize adapter\n"); @@ -1995,6 +2212,14 @@ que_init:  		    "Adapter flags %x.\n",  		    base_vha->host_no, base_vha->device_flags)); +		if (IS_QLA82XX(ha)) { +			qla82xx_idc_lock(ha); +			qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, +				QLA82XX_DEV_FAILED); +			qla82xx_idc_unlock(ha); +			qla_printk(KERN_INFO, ha, "HW State: FAILED\n"); +		} +  		ret = -ENODEV;  		goto probe_failed;  	} @@ -2033,6 +2258,24 @@ skip_dpc:  	DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",  	    base_vha->host_no, ha)); +	if (IS_QLA25XX(ha) && ql2xenabledif) { +		if (ha->fw_attributes & BIT_4) { +			base_vha->flags.difdix_supported = 1; +			DEBUG18(qla_printk(KERN_INFO, ha, +			    "Registering for DIF/DIX type 1 and 3" +			    " protection.\n")); +			scsi_host_set_prot(host, +			    SHOST_DIF_TYPE1_PROTECTION +			    | SHOST_DIF_TYPE3_PROTECTION +			    | SHOST_DIX_TYPE1_PROTECTION +			    | SHOST_DIX_TYPE3_PROTECTION); +			scsi_host_set_guard(host, SHOST_DIX_GUARD_CRC); +		} else +			base_vha->flags.difdix_supported = 0; +	} + +	ha->isp_ops->enable_intrs(ha); +  	ret = scsi_add_host(host, &pdev->dev);  	if (ret)  		goto probe_failed; @@ -2040,8 +2283,6 @@ skip_dpc:  	base_vha->flags.init_done = 1;  	base_vha->flags.online = 1; -	ha->isp_ops->enable_intrs(ha); -  	scsi_scan_host(host);  	qla2x00_alloc_sysfs_attr(base_vha); @@ -2083,9 +2324,17 @@ probe_failed:  	scsi_host_put(base_vha->host);  probe_hw_failed: -	if (ha->iobase) -		iounmap(ha->iobase); - +	if (IS_QLA82XX(ha)) { +		qla82xx_idc_lock(ha); +		qla82xx_clear_drv_active(ha); +		qla82xx_idc_unlock(ha); +		iounmap((device_reg_t __iomem *)ha->nx_pcibase); +		if (!ql2xdbwr) +			iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr); +	} else { +		if (ha->iobase) +			iounmap(ha->iobase); +	}  	pci_release_selected_regions(ha->pdev, ha->bars);  	kfree(ha);  	ha = NULL; @@ -2152,11 +2401,17 @@ qla2x00_remove_one(struct pci_dev *pdev)  	scsi_host_put(base_vha->host); -	if (ha->iobase) -		iounmap(ha->iobase); +	if (IS_QLA82XX(ha)) { +		iounmap((device_reg_t __iomem *)ha->nx_pcibase); +		if (!ql2xdbwr) +			iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr); +	} else { +		if (ha->iobase) +			iounmap(ha->iobase); -	if (ha->mqiobase) -		iounmap(ha->mqiobase); +		if (ha->mqiobase) +			iounmap(ha->mqiobase); +	}  	pci_release_selected_regions(ha->pdev, ha->bars);  	kfree(ha); @@ -2205,8 +2460,10 @@ qla2x00_free_device(scsi_qla_host_t *vha)  	vha->flags.online = 0;  	/* turn-off interrupts on the card */ -	if (ha->interrupts_on) +	if (ha->interrupts_on) { +		vha->flags.init_done = 0;  		ha->isp_ops->disable_intrs(ha); +	}  	qla2x00_free_irqs(vha); @@ -2351,10 +2608,25 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,  	if (!ha->srb_mempool)  		goto fail_free_gid_list; +	if (IS_QLA82XX(ha)) { +		/* Allocate cache for CT6 Ctx. */ +		if (!ctx_cachep) { +			ctx_cachep = kmem_cache_create("qla2xxx_ctx", +				sizeof(struct ct6_dsd), 0, +				SLAB_HWCACHE_ALIGN, NULL); +			if (!ctx_cachep) +				goto fail_free_gid_list; +		} +		ha->ctx_mempool = mempool_create_slab_pool(SRB_MIN_REQ, +			ctx_cachep); +		if (!ha->ctx_mempool) +			goto fail_free_srb_mempool; +	} +  	/* Get memory for cached NVRAM */  	ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);  	if (!ha->nvram) -		goto fail_free_srb_mempool; +		goto fail_free_ctx_mempool;  	snprintf(name, sizeof(name), "%s_%d", QLA2XXX_DRIVER_NAME,  		ha->pdev->device); @@ -2363,6 +2635,24 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,  	if (!ha->s_dma_pool)  		goto fail_free_nvram; +	if (IS_QLA82XX(ha) || ql2xenabledif) { +		ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev, +			DSD_LIST_DMA_POOL_SIZE, 8, 0); +		if (!ha->dl_dma_pool) { +			qla_printk(KERN_WARNING, ha, +			    "Memory Allocation failed - dl_dma_pool\n"); +			goto fail_s_dma_pool; +		} + +		ha->fcp_cmnd_dma_pool = dma_pool_create(name, &ha->pdev->dev, +			FCP_CMND_DMA_POOL_SIZE, 8, 0); +		if (!ha->fcp_cmnd_dma_pool) { +			qla_printk(KERN_WARNING, ha, +			    "Memory Allocation failed - fcp_cmnd_dma_pool\n"); +			goto fail_dl_dma_pool; +		} +	} +  	/* Allocate memory for SNS commands */  	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {  	/* Get consistent memory allocated for SNS commands */ @@ -2429,16 +2719,28 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,  		ha->npiv_info = NULL;  	/* Get consistent memory allocated for EX-INIT-CB. */ -	if (IS_QLA81XX(ha)) { +	if (IS_QLA8XXX_TYPE(ha)) {  		ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,  		    &ha->ex_init_cb_dma);  		if (!ha->ex_init_cb)  			goto fail_ex_init_cb;  	} +	INIT_LIST_HEAD(&ha->gbl_dsd_list); + +	/* Get consistent memory allocated for Async Port-Database. */ +	if (!IS_FWI2_CAPABLE(ha)) { +		ha->async_pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, +			&ha->async_pd_dma); +		if (!ha->async_pd) +			goto fail_async_pd; +	} +  	INIT_LIST_HEAD(&ha->vp_list);  	return 1; +fail_async_pd: +	dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);  fail_ex_init_cb:  	kfree(ha->npiv_info);  fail_npiv_info: @@ -2465,11 +2767,24 @@ fail_free_ms_iocb:  	ha->ms_iocb = NULL;  	ha->ms_iocb_dma = 0;  fail_dma_pool: +	if (IS_QLA82XX(ha) || ql2xenabledif) { +		dma_pool_destroy(ha->fcp_cmnd_dma_pool); +		ha->fcp_cmnd_dma_pool = NULL; +	} +fail_dl_dma_pool: +	if (IS_QLA82XX(ha) || ql2xenabledif) { +		dma_pool_destroy(ha->dl_dma_pool); +		ha->dl_dma_pool = NULL; +	} +fail_s_dma_pool:  	dma_pool_destroy(ha->s_dma_pool);  	ha->s_dma_pool = NULL;  fail_free_nvram:  	kfree(ha->nvram);  	ha->nvram = NULL; +fail_free_ctx_mempool: +	mempool_destroy(ha->ctx_mempool); +	ha->ctx_mempool = NULL;  fail_free_srb_mempool:  	mempool_destroy(ha->srb_mempool);  	ha->srb_mempool = NULL; @@ -2538,7 +2853,11 @@ qla2x00_mem_free(struct qla_hw_data *ha)  		dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);  	if (ha->ex_init_cb) -		dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); +		dma_pool_free(ha->s_dma_pool, +			ha->ex_init_cb, ha->ex_init_cb_dma); + +	if (ha->async_pd) +		dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);  	if (ha->s_dma_pool)  		dma_pool_destroy(ha->s_dma_pool); @@ -2547,14 +2866,39 @@ qla2x00_mem_free(struct qla_hw_data *ha)  		dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,  		ha->gid_list_dma); +	if (IS_QLA82XX(ha)) { +		if (!list_empty(&ha->gbl_dsd_list)) { +			struct dsd_dma *dsd_ptr, *tdsd_ptr; + +			/* clean up allocated prev pool */ +			list_for_each_entry_safe(dsd_ptr, +				tdsd_ptr, &ha->gbl_dsd_list, list) { +				dma_pool_free(ha->dl_dma_pool, +				dsd_ptr->dsd_addr, dsd_ptr->dsd_list_dma); +				list_del(&dsd_ptr->list); +				kfree(dsd_ptr); +			} +		} +	} + +	if (ha->dl_dma_pool) +		dma_pool_destroy(ha->dl_dma_pool); + +	if (ha->fcp_cmnd_dma_pool) +		dma_pool_destroy(ha->fcp_cmnd_dma_pool); + +	if (ha->ctx_mempool) +		mempool_destroy(ha->ctx_mempool); +  	if (ha->init_cb)  		dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, -		ha->init_cb, ha->init_cb_dma); +			ha->init_cb, ha->init_cb_dma);  	vfree(ha->optrom_buffer);  	kfree(ha->nvram);  	kfree(ha->npiv_info);  	ha->srb_mempool = NULL; +	ha->ctx_mempool = NULL;  	ha->eft = NULL;  	ha->eft_dma = 0;  	ha->sns_cmd = NULL; @@ -2567,8 +2911,12 @@ qla2x00_mem_free(struct qla_hw_data *ha)  	ha->init_cb_dma = 0;  	ha->ex_init_cb = NULL;  	ha->ex_init_cb_dma = 0; +	ha->async_pd = NULL; +	ha->async_pd_dma = 0;  	ha->s_dma_pool = NULL; +	ha->dl_dma_pool = NULL; +	ha->fcp_cmnd_dma_pool = NULL;  	ha->gid_list = NULL;  	ha->gid_list_dma = 0; @@ -2691,6 +3039,8 @@ qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN);  qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE);  qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT);  qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE); +qla2x00_post_async_work(adisc, QLA_EVT_ASYNC_ADISC); +qla2x00_post_async_work(adisc_done, QLA_EVT_ASYNC_ADISC_DONE);  int  qla2x00_post_uevent_work(struct scsi_qla_host *vha, u32 code) @@ -2760,6 +3110,14 @@ qla2x00_do_work(struct scsi_qla_host *vha)  			qla2x00_async_logout_done(vha, e->u.logio.fcport,  			    e->u.logio.data);  			break; +		case QLA_EVT_ASYNC_ADISC: +			qla2x00_async_adisc(vha, e->u.logio.fcport, +			    e->u.logio.data); +			break; +		case QLA_EVT_ASYNC_ADISC_DONE: +			qla2x00_async_adisc_done(vha, e->u.logio.fcport, +			    e->u.logio.data); +			break;  		case QLA_EVT_UEVENT:  			qla2x00_uevent_emit(vha, e->u.uevent.code);  			break; @@ -2785,9 +3143,8 @@ void qla2x00_relogin(struct scsi_qla_host *vha)  	 * If the port is not ONLINE then try to login  	 * to it if we haven't run out of retries.  	 */ -		if (atomic_read(&fcport->state) != -			FCS_ONLINE && fcport->login_retry) { - +		if (atomic_read(&fcport->state) != FCS_ONLINE && +		    fcport->login_retry && !(fcport->flags & FCF_ASYNC_SENT)) {  			fcport->login_retry--;  			if (fcport->flags & FCF_FABRIC_DEVICE) {  				if (fcport->flags & FCF_FCP2_DEVICE) @@ -2798,6 +3155,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha)  							fcport->d_id.b.al_pa);  				if (IS_ALOGIO_CAPABLE(ha)) { +					fcport->flags |= FCF_ASYNC_SENT;  					data[0] = 0;  					data[1] = QLA_LOGIO_LOGIN_RETRIED;  					status = qla2x00_post_async_login_work( @@ -2896,6 +3254,45 @@ qla2x00_do_dpc(void *data)  		qla2x00_do_work(base_vha); +		if (IS_QLA82XX(ha)) { +			if (test_and_clear_bit(ISP_UNRECOVERABLE, +				&base_vha->dpc_flags)) { +				qla82xx_idc_lock(ha); +				qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, +					QLA82XX_DEV_FAILED); +				qla82xx_idc_unlock(ha); +				qla_printk(KERN_INFO, ha, +					"HW State: FAILED\n"); +				qla82xx_device_state_handler(base_vha); +				continue; +			} + +			if (test_and_clear_bit(FCOE_CTX_RESET_NEEDED, +				&base_vha->dpc_flags)) { + +				DEBUG(printk(KERN_INFO +					"scsi(%ld): dpc: sched " +					"qla82xx_fcoe_ctx_reset ha = %p\n", +					base_vha->host_no, ha)); +				if (!(test_and_set_bit(ABORT_ISP_ACTIVE, +					&base_vha->dpc_flags))) { +					if (qla82xx_fcoe_ctx_reset(base_vha)) { +						/* FCoE-ctx reset failed. +						 * Escalate to chip-reset +						 */ +						set_bit(ISP_ABORT_NEEDED, +							&base_vha->dpc_flags); +					} +					clear_bit(ABORT_ISP_ACTIVE, +						&base_vha->dpc_flags); +				} + +				DEBUG(printk("scsi(%ld): dpc:" +					" qla82xx_fcoe_ctx_reset end\n", +					base_vha->host_no)); +			} +		} +  		if (test_and_clear_bit(ISP_ABORT_NEEDED,  						&base_vha->dpc_flags)) { @@ -2905,7 +3302,7 @@ qla2x00_do_dpc(void *data)  			if (!(test_and_set_bit(ABORT_ISP_ACTIVE,  			    &base_vha->dpc_flags))) { -				if (qla2x00_abort_isp(base_vha)) { +				if (ha->isp_ops->abort_isp(base_vha)) {  					/* failed. retry later */  					set_bit(ISP_ABORT_NEEDED,  					    &base_vha->dpc_flags); @@ -3038,11 +3435,31 @@ static void  qla2x00_sp_free_dma(srb_t *sp)  {  	struct scsi_cmnd *cmd = sp->cmd; +	struct qla_hw_data *ha = sp->fcport->vha->hw;  	if (sp->flags & SRB_DMA_VALID) {  		scsi_dma_unmap(cmd);  		sp->flags &= ~SRB_DMA_VALID;  	} + +	if (sp->flags & SRB_CRC_PROT_DMA_VALID) { +		dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), +		    scsi_prot_sg_count(cmd), cmd->sc_data_direction); +		sp->flags &= ~SRB_CRC_PROT_DMA_VALID; +	} + +	if (sp->flags & SRB_CRC_CTX_DSD_VALID) { +		/* List assured to be having elements */ +		qla2x00_clean_dsd_pool(ha, sp); +		sp->flags &= ~SRB_CRC_CTX_DSD_VALID; +	} + +	if (sp->flags & SRB_CRC_CTX_DMA_VALID) { +		dma_pool_free(ha->dl_dma_pool, sp->ctx, +		    ((struct crc_context *)sp->ctx)->crc_ctx_dma); +		sp->flags &= ~SRB_CRC_CTX_DMA_VALID; +	} +  	CMD_SP(cmd) = NULL;  } @@ -3053,8 +3470,18 @@ qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)  	qla2x00_sp_free_dma(sp); -	mempool_free(sp, ha->srb_mempool); +	if (sp->flags & SRB_FCP_CMND_DMA_VALID) { +		struct ct6_dsd *ctx = sp->ctx; +		dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, +			ctx->fcp_cmnd_dma); +		list_splice(&ctx->dsd_list, &ha->gbl_dsd_list); +		ha->gbl_dsd_inuse -= ctx->dsd_use_cnt; +		ha->gbl_dsd_avail += ctx->dsd_use_cnt; +		mempool_free(sp->ctx, ha->ctx_mempool); +		sp->ctx = NULL; +	} +	mempool_free(sp, ha->srb_mempool);  	cmd->scsi_done(cmd);  } @@ -3079,6 +3506,9 @@ qla2x00_timer(scsi_qla_host_t *vha)  	struct qla_hw_data *ha = vha->hw;  	struct req_que *req; +	if (IS_QLA82XX(ha)) +		qla82xx_watchdog(vha); +  	/* Hardware read to raise pending EEH errors during mailbox waits. */  	if (!pci_channel_offline(ha->pdev))  		pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); @@ -3143,7 +3573,7 @@ qla2x00_timer(scsi_qla_host_t *vha)  					sp = req->outstanding_cmds[index];  					if (!sp)  						continue; -					if (sp->ctx) +					if (sp->ctx && !IS_PROT_IO(sp))  						continue;  					sfcp = sp->fcport;  					if (!(sfcp->flags & FCF_FCP2_DEVICE)) @@ -3193,6 +3623,8 @@ qla2x00_timer(scsi_qla_host_t *vha)  	    start_dpc ||  	    test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) ||  	    test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags) || +	    test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) || +	    test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) ||  	    test_bit(VP_DPC_NEEDED, &vha->dpc_flags) ||  	    test_bit(RELOGIN_NEEDED, &vha->dpc_flags)))  		qla2xxx_wake_dpc(vha); @@ -3202,7 +3634,7 @@ qla2x00_timer(scsi_qla_host_t *vha)  /* Firmware interface routines. */ -#define FW_BLOBS	7 +#define FW_BLOBS	8  #define FW_ISP21XX	0  #define FW_ISP22XX	1  #define FW_ISP2300	2 @@ -3210,6 +3642,7 @@ qla2x00_timer(scsi_qla_host_t *vha)  #define FW_ISP24XX	4  #define FW_ISP25XX	5  #define FW_ISP81XX	6 +#define FW_ISP82XX	7  #define FW_FILE_ISP21XX	"ql2100_fw.bin"  #define FW_FILE_ISP22XX	"ql2200_fw.bin" @@ -3218,6 +3651,7 @@ qla2x00_timer(scsi_qla_host_t *vha)  #define FW_FILE_ISP24XX	"ql2400_fw.bin"  #define FW_FILE_ISP25XX	"ql2500_fw.bin"  #define FW_FILE_ISP81XX	"ql8100_fw.bin" +#define FW_FILE_ISP82XX	"ql8200_fw.bin"  static DEFINE_MUTEX(qla_fw_lock); @@ -3229,6 +3663,7 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {  	{ .name = FW_FILE_ISP24XX, },  	{ .name = FW_FILE_ISP25XX, },  	{ .name = FW_FILE_ISP81XX, }, +	{ .name = FW_FILE_ISP82XX, },  };  struct fw_blob * @@ -3252,6 +3687,8 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)  		blob = &qla_fw_blobs[FW_ISP25XX];  	} else if (IS_QLA81XX(ha)) {  		blob = &qla_fw_blobs[FW_ISP81XX]; +	} else if (IS_QLA82XX(ha)) { +		blob = &qla_fw_blobs[FW_ISP82XX];  	}  	mutex_lock(&qla_fw_lock); @@ -3392,11 +3829,10 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)  		msleep(1000);  	set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); -	if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS) +	if (ha->isp_ops->abort_isp(base_vha) == QLA_SUCCESS)  		ret =  PCI_ERS_RESULT_RECOVERED;  	clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); -	pci_cleanup_aer_uncorrect_error_status(pdev);  	DEBUG17(qla_printk(KERN_WARNING, ha,  	    "slot_reset-return:ret=%x\n", ret)); @@ -3420,6 +3856,8 @@ qla2xxx_pci_resume(struct pci_dev *pdev)  		    "from slot/link_reset");  	} +	pci_cleanup_aer_uncorrect_error_status(pdev); +  	ha->flags.eeh_busy = 0;  } @@ -3445,6 +3883,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },  	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },  	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8021) },  	{ 0 },  };  MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl); @@ -3460,6 +3899,10 @@ static struct pci_driver qla2xxx_pci_driver = {  	.err_handler	= &qla2xxx_err_handler,  }; +static struct file_operations apidev_fops = { +	.owner = THIS_MODULE, +}; +  /**   * qla2x00_module_init - Module initialization.   **/ @@ -3488,6 +3931,13 @@ qla2x00_module_init(void)  		kmem_cache_destroy(srb_cachep);  		return -ENODEV;  	} + +	apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops); +	if (apidev_major < 0) { +		printk(KERN_WARNING "qla2xxx: Unable to register char device " +		    "%s\n", QLA2XXX_APIDEV); +	} +  	qla2xxx_transport_vport_template =  	    fc_attach_transport(&qla2xxx_transport_vport_functions);  	if (!qla2xxx_transport_vport_template) { @@ -3513,9 +3963,12 @@ qla2x00_module_init(void)  static void __exit  qla2x00_module_exit(void)  { +	unregister_chrdev(apidev_major, QLA2XXX_APIDEV);  	pci_unregister_driver(&qla2xxx_pci_driver);  	qla2x00_release_firmware();  	kmem_cache_destroy(srb_cachep); +	if (ctx_cachep) +		kmem_cache_destroy(ctx_cachep);  	fc_release_transport(qla2xxx_transport_template);  	fc_release_transport(qla2xxx_transport_vport_template);  } diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 8b3de4e54c2..de92504d758 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -423,9 +423,6 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat)  /* Flash Manipulation Routines                                               */  /*****************************************************************************/ -#define OPTROM_BURST_SIZE	0x1000 -#define OPTROM_BURST_DWORDS	(OPTROM_BURST_SIZE / 4) -  static inline uint32_t  flash_conf_addr(struct qla_hw_data *ha, uint32_t faddr)  { @@ -565,6 +562,10 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)  		*start = FA_FLASH_LAYOUT_ADDR;  	else if (IS_QLA81XX(ha))  		*start = FA_FLASH_LAYOUT_ADDR_81; +	else if (IS_QLA82XX(ha)) { +		*start = FA_FLASH_LAYOUT_ADDR_82; +		goto end; +	}  	/* Begin with first PCI expansion ROM header. */  	buf = (uint8_t *)req->ring;  	dcode = (uint32_t *)req->ring; @@ -648,6 +649,12 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)  	const uint32_t def_npiv_conf1[] =  		{ FA_NPIV_CONF1_ADDR_24, FA_NPIV_CONF1_ADDR,  			FA_NPIV_CONF1_ADDR_81 }; +	const uint32_t fcp_prio_cfg0[] = +		{ FA_FCP_PRIO0_ADDR, FA_FCP_PRIO0_ADDR_25, +			0 }; +	const uint32_t fcp_prio_cfg1[] = +		{ FA_FCP_PRIO1_ADDR, FA_FCP_PRIO1_ADDR_25, +			0 };  	uint32_t def;  	uint16_t *wptr;  	uint16_t cnt, chksum; @@ -703,10 +710,14 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)  			break;  		case FLT_REG_VPD_0:  			ha->flt_region_vpd_nvram = start; +			if (IS_QLA82XX(ha)) +				break;  			if (ha->flags.port0)  				ha->flt_region_vpd = start;  			break;  		case FLT_REG_VPD_1: +			if (IS_QLA82XX(ha)) +				break;  			if (!ha->flags.port0)  				ha->flt_region_vpd = start;  			break; @@ -732,6 +743,29 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)  		case FLT_REG_GOLD_FW:  			ha->flt_region_gold_fw = start;  			break; +		case FLT_REG_FCP_PRIO_0: +			if (ha->flags.port0) +				ha->flt_region_fcp_prio = start; +			break; +		case FLT_REG_FCP_PRIO_1: +			if (!ha->flags.port0) +				ha->flt_region_fcp_prio = start; +			break; +		case FLT_REG_BOOT_CODE_82XX: +			ha->flt_region_boot = start; +			break; +		case FLT_REG_FW_82XX: +			ha->flt_region_fw = start; +			break; +		case FLT_REG_GOLD_FW_82XX: +			ha->flt_region_gold_fw = start; +			break; +		case FLT_REG_BOOTLOAD_82XX: +			ha->flt_region_bootload = start; +			break; +		case FLT_REG_VPD_82XX: +			ha->flt_region_vpd = start; +			break;  		}  	}  	goto done; @@ -750,12 +784,14 @@ no_flash_data:  	ha->flt_region_boot = def_boot[def];  	ha->flt_region_vpd_nvram = def_vpd_nvram[def];  	ha->flt_region_vpd = ha->flags.port0 ? -	    def_vpd0[def]: def_vpd1[def]; +	    def_vpd0[def] : def_vpd1[def];  	ha->flt_region_nvram = ha->flags.port0 ? -	    def_nvram0[def]: def_nvram1[def]; +	    def_nvram0[def] : def_nvram1[def];  	ha->flt_region_fdt = def_fdt[def];  	ha->flt_region_npiv_conf = ha->flags.port0 ? -	    def_npiv_conf0[def]: def_npiv_conf1[def]; +	    def_npiv_conf0[def] : def_npiv_conf1[def]; +	ha->flt_region_fcp_prio = ha->flags.port0 ? +	    fcp_prio_cfg0[def] : fcp_prio_cfg1[def];  done:  	DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "  	    "vpd_nvram=0x%x vpd=0x%x nvram=0x%x fdt=0x%x flt=0x%x " @@ -775,7 +811,7 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)  	uint16_t *wptr;  	struct qla_fdt_layout *fdt;  	uint8_t	man_id, flash_id; -	uint16_t mid, fid; +	uint16_t mid = 0, fid = 0;  	struct qla_hw_data *ha = vha->hw;  	struct req_que *req = ha->req_q_map[0]; @@ -816,6 +852,10 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)  	goto done;  no_flash_data:  	loc = locations[0]; +	if (IS_QLA82XX(ha)) { +		ha->fdt_block_size = FLASH_BLK_SIZE_64K; +		goto done; +	}  	qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);  	mid = man_id;  	fid = flash_id; @@ -853,6 +893,31 @@ done:  	    ha->fdt_block_size));  } +static void +qla2xxx_get_idc_param(scsi_qla_host_t *vha) +{ +#define QLA82XX_IDC_PARAM_ADDR       0x003e885c +	uint32_t *wptr; +	struct qla_hw_data *ha = vha->hw; +	struct req_que *req = ha->req_q_map[0]; + +	if (!IS_QLA82XX(ha)) +		return; + +	wptr = (uint32_t *)req->ring; +	ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring, +		QLA82XX_IDC_PARAM_ADDR , 8); + +	if (*wptr == __constant_cpu_to_le32(0xffffffff)) { +		ha->nx_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT; +		ha->nx_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT; +	} else { +		ha->nx_dev_init_timeout = le32_to_cpu(*wptr++); +		ha->nx_reset_timeout = le32_to_cpu(*wptr); +	} +	return; +} +  int  qla2xxx_get_flash_info(scsi_qla_host_t *vha)  { @@ -860,7 +925,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)  	uint32_t flt_addr;  	struct qla_hw_data *ha = vha->hw; -	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA81XX(ha)) +	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA8XXX_TYPE(ha))  		return QLA_SUCCESS;  	ret = qla2xxx_find_flt_start(vha, &flt_addr); @@ -869,6 +934,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)  	qla2xxx_get_flt_info(vha, flt_addr);  	qla2xxx_get_fdt_info(vha); +	qla2xxx_get_idc_param(vha);  	return QLA_SUCCESS;  } @@ -885,7 +951,7 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)  	struct qla_npiv_entry *entry;  	struct qla_hw_data *ha = vha->hw; -	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA81XX(ha)) +	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA8XXX_TYPE(ha))  		return;  	ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr, @@ -1178,6 +1244,9 @@ qla24xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,  	uint32_t *dwptr;  	struct qla_hw_data *ha = vha->hw; +	if (IS_QLA82XX(ha)) +		return  buf; +  	/* Dword reads to flash. */  	dwptr = (uint32_t *)buf;  	for (i = 0; i < bytes >> 2; i++, naddr++) @@ -1233,6 +1302,9 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,  	ret = QLA_SUCCESS; +	if (IS_QLA82XX(ha)) +		return ret; +  	/* Enable flash write. */  	WRT_REG_DWORD(®->ctrl_status,  	    RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); @@ -1344,6 +1416,9 @@ qla2x00_beacon_blink(struct scsi_qla_host *vha)  	struct qla_hw_data *ha = vha->hw;  	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; +	if (IS_QLA82XX(ha)) +		return; +  	spin_lock_irqsave(&ha->hardware_lock, flags);  	/* Save the Original GPIOE. */ @@ -1525,6 +1600,9 @@ qla24xx_beacon_on(struct scsi_qla_host *vha)  	struct qla_hw_data *ha = vha->hw;  	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; +	if (IS_QLA82XX(ha)) +		return QLA_SUCCESS; +  	if (ha->beacon_blink_led == 0) {  		/* Enable firmware for update */  		ha->fw_options[1] |= ADD_FO1_DISABLE_GPIO_LED_CTRL; @@ -1567,6 +1645,9 @@ qla24xx_beacon_off(struct scsi_qla_host *vha)  	struct qla_hw_data *ha = vha->hw;  	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; +	if (IS_QLA82XX(ha)) +		return QLA_SUCCESS; +  	ha->beacon_blink_led = 0;  	ha->beacon_color_state = QLA_LED_ALL_ON; @@ -2576,6 +2657,9 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)  	int i;  	struct qla_hw_data *ha = vha->hw; +	if (IS_QLA82XX(ha)) +		return ret; +  	if (!mbuf)  		return QLA_FUNCTION_FAILED; @@ -2722,3 +2806,50 @@ qla2xxx_get_vpd_field(scsi_qla_host_t *vha, char *key, char *str, size_t size)  	return 0;  } + +int +qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha) +{ +	int len, max_len; +	uint32_t fcp_prio_addr; +	struct qla_hw_data *ha = vha->hw; + +	if (!ha->fcp_prio_cfg) { +		ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE); +		if (!ha->fcp_prio_cfg) { +			qla_printk(KERN_WARNING, ha, +			"Unable to allocate memory for fcp priority data " +					"(%x).\n", FCP_PRIO_CFG_SIZE); +			return QLA_FUNCTION_FAILED; +		} +	} +	memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE); + +	fcp_prio_addr = ha->flt_region_fcp_prio; + +	/* first read the fcp priority data header from flash */ +	ha->isp_ops->read_optrom(vha, (uint8_t *)ha->fcp_prio_cfg, +			fcp_prio_addr << 2, FCP_PRIO_CFG_HDR_SIZE); + +	if (!qla24xx_fcp_prio_cfg_valid(ha->fcp_prio_cfg, 0)) +		goto fail; + +	/* read remaining FCP CMD config data from flash */ +	fcp_prio_addr += (FCP_PRIO_CFG_HDR_SIZE >> 2); +	len = ha->fcp_prio_cfg->num_entries * FCP_PRIO_CFG_ENTRY_SIZE; +	max_len = FCP_PRIO_CFG_SIZE - FCP_PRIO_CFG_HDR_SIZE; + +	ha->isp_ops->read_optrom(vha, (uint8_t *)&ha->fcp_prio_cfg->entry[0], +			fcp_prio_addr << 2, (len < max_len ? len : max_len)); + +	/* revalidate the entire FCP priority config data, including entries */ +	if (!qla24xx_fcp_prio_cfg_valid(ha->fcp_prio_cfg, 1)) +		goto fail; + +	ha->flags.fcp_prio_enabled = 1; +	return QLA_SUCCESS; +fail: +	vfree(ha->fcp_prio_cfg); +	ha->fcp_prio_cfg = NULL; +	return QLA_FUNCTION_FAILED; +} diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 81b5f29254e..428802616e3 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -114,6 +114,7 @@   */  #define MAC_ADDR_LEN			6	/* in bytes */  #define IP_ADDR_LEN			4	/* in bytes */ +#define IPv6_ADDR_LEN			16	/* IPv6 address size */  #define DRIVER_NAME			"qla4xxx"  #define MAX_LINKED_CMDS_PER_LUN		3 @@ -147,6 +148,8 @@  #define MAX_RESET_HA_RETRIES		2 +#define CMD_SP(Cmnd)			((Cmnd)->SCp.ptr) +  /*   * SCSI Request Block structure	 (srb)	that is placed   * on cmd->SCp location of every I/O	 [We have 22 bytes available] @@ -169,7 +172,7 @@ struct srb {  	struct scsi_cmnd *cmd;	/* (4) SCSI command block */  	dma_addr_t dma_handle;	/* (4) for unmap of single transfers */ -	atomic_t ref_count;	/* reference count for this srb */ +	struct kref srb_ref;	/* reference count for this srb */  	uint32_t fw_ddb_index;  	uint8_t err_id;		/* error id */  #define SRB_ERR_PORT	   1	/* Request failed because "port down" */ @@ -220,7 +223,7 @@ struct ddb_entry {  	uint16_t os_target_id;	/* Target ID */  	uint16_t fw_ddb_index;	/* DDB firmware index */ -	uint8_t reserved[2]; +	uint16_t options;  	uint32_t fw_ddb_device_state; /* F/W Device State  -- see ql4_fw.h */  	uint32_t CmdSn; @@ -245,10 +248,18 @@ struct ddb_entry {  	uint16_t port;  	uint32_t tpgt; -	uint8_t ip_addr[ISCSI_IPADDR_SIZE]; +	uint8_t ip_addr[IP_ADDR_LEN];  	uint8_t iscsi_name[ISCSI_NAME_SIZE];	/* 72 x48 */  	uint8_t iscsi_alias[0x20];  	uint8_t isid[6]; +	uint16_t iscsi_max_burst_len; +	uint16_t iscsi_max_outsnd_r2t; +	uint16_t iscsi_first_burst_len; +	uint16_t iscsi_max_rcv_data_seg_len; +	uint16_t iscsi_max_snd_data_seg_len; + +	struct in6_addr remote_ipv6_addr; +	struct in6_addr link_local_ipv6_addr;  };  /* @@ -301,6 +312,7 @@ struct scsi_qla_host {  #define DPC_ISNS_RESTART		7 /* 0x00000080 */  #define DPC_AEN				9 /* 0x00000200 */  #define DPC_GET_DHCP_IP_ADDR		15 /* 0x00008000 */ +#define DPC_LINK_CHANGED		18 /* 0x00040000 */  	struct Scsi_Host *host; /* pointer to host data */  	uint32_t tot_ddbs; @@ -320,8 +332,7 @@ struct scsi_qla_host {  #define MIN_IOBASE_LEN		0x100  	uint16_t req_q_count; -	uint8_t marker_needed; -	uint8_t rsvd1; +	uint8_t rsvd1[2];  	unsigned long host_no; @@ -441,8 +452,35 @@ struct scsi_qla_host {  	/* Saved srb for status continuation entry processing */  	struct srb *status_srb; + +	/* IPv6 support info from InitFW */ +	uint8_t acb_version; +	uint8_t ipv4_addr_state; +	uint16_t ipv4_options; + +	uint32_t resvd2; +	uint32_t ipv6_options; +	uint32_t ipv6_addl_options; +	uint8_t ipv6_link_local_state; +	uint8_t ipv6_addr0_state; +	uint8_t ipv6_addr1_state; +	uint8_t ipv6_default_router_state; +	struct in6_addr ipv6_link_local_addr; +	struct in6_addr ipv6_addr0; +	struct in6_addr ipv6_addr1; +	struct in6_addr ipv6_default_router_addr;  }; +static inline int is_ipv4_enabled(struct scsi_qla_host *ha) +{ +	return ((ha->ipv4_options & IPOPT_IPv4_PROTOCOL_ENABLE) != 0); +} + +static inline int is_ipv6_enabled(struct scsi_qla_host *ha) +{ +	return ((ha->ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE) != 0); +} +  static inline int is_qla4010(struct scsi_qla_host *ha)  {  	return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010; diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 9cd7a608df3..855226e0866 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -215,6 +215,7 @@ union external_hw_config_reg {  /*  Mailbox command definitions */  #define MBOX_CMD_ABOUT_FW			0x0009  #define MBOX_CMD_PING				0x000B +#define MBOX_CMD_ABORT_TASK			0x0015  #define MBOX_CMD_LUN_RESET			0x0016  #define MBOX_CMD_TARGET_WARM_RESET		0x0017  #define MBOX_CMD_GET_MANAGEMENT_DATA		0x001E @@ -258,13 +259,15 @@ union external_hw_config_reg {  /* Mailbox 1 */  #define FW_STATE_READY				0x0000  #define FW_STATE_CONFIG_WAIT			0x0001 -#define FW_STATE_WAIT_LOGIN			0x0002 +#define FW_STATE_WAIT_AUTOCONNECT		0x0002  #define FW_STATE_ERROR				0x0004 -#define FW_STATE_DHCP_IN_PROGRESS		0x0008 +#define FW_STATE_CONFIGURING_IP			0x0008  /* Mailbox 3 */  #define FW_ADDSTATE_OPTICAL_MEDIA		0x0001 -#define FW_ADDSTATE_DHCP_ENABLED		0x0002 +#define FW_ADDSTATE_DHCPv4_ENABLED		0x0002 +#define FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED	0x0004 +#define FW_ADDSTATE_DHCPv4_LEASE_EXPIRED	0x0008  #define FW_ADDSTATE_LINK_UP			0x0010  #define FW_ADDSTATE_ISNS_SVC_ENABLED		0x0020  #define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS	0x006B @@ -320,6 +323,8 @@ union external_hw_config_reg {  /* Host Adapter Initialization Control Block (from host) */  struct addr_ctrl_blk {  	uint8_t version;	/* 00 */ +#define  IFCB_VER_MIN			0x01 +#define  IFCB_VER_MAX			0x02  	uint8_t control;	/* 01 */  	uint16_t fw_options;	/* 02-03 */ @@ -351,11 +356,16 @@ struct addr_ctrl_blk {  	uint16_t iscsi_opts;	/* 30-31 */  	uint16_t ipv4_tcp_opts;	/* 32-33 */  	uint16_t ipv4_ip_opts;	/* 34-35 */ +#define  IPOPT_IPv4_PROTOCOL_ENABLE	0x8000  	uint16_t iscsi_max_pdu_size;	/* 36-37 */  	uint8_t ipv4_tos;	/* 38 */  	uint8_t ipv4_ttl;	/* 39 */  	uint8_t acb_version;	/* 3A */ +#define ACB_NOT_SUPPORTED		0x00 +#define ACB_SUPPORTED			0x02 /* Capable of ACB Version 2 +						Features */ +  	uint8_t res2;	/* 3B */  	uint16_t def_timeout;	/* 3C-3D */  	uint16_t iscsi_fburst_len;	/* 3E-3F */ @@ -397,16 +407,35 @@ struct addr_ctrl_blk {  	uint32_t cookie;	/* 200-203 */  	uint16_t ipv6_port;	/* 204-205 */  	uint16_t ipv6_opts;	/* 206-207 */ +#define IPV6_OPT_IPV6_PROTOCOL_ENABLE	0x8000 +  	uint16_t ipv6_addtl_opts;	/* 208-209 */ +#define IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE	0x0002 /* Pri ACB +								  Only */ +#define IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR		0x0001 +  	uint16_t ipv6_tcp_opts;	/* 20A-20B */  	uint8_t ipv6_tcp_wsf;	/* 20C */  	uint16_t ipv6_flow_lbl;	/* 20D-20F */ -	uint8_t ipv6_gw_addr[16];	/* 210-21F */ +	uint8_t ipv6_dflt_rtr_addr[16]; /* 210-21F */  	uint16_t ipv6_vlan_tag;	/* 220-221 */  	uint8_t ipv6_lnk_lcl_addr_state;/* 222 */  	uint8_t ipv6_addr0_state;	/* 223 */  	uint8_t ipv6_addr1_state;	/* 224 */ -	uint8_t ipv6_gw_state;	/* 225 */ +#define IP_ADDRSTATE_UNCONFIGURED	0 +#define IP_ADDRSTATE_INVALID		1 +#define IP_ADDRSTATE_ACQUIRING		2 +#define IP_ADDRSTATE_TENTATIVE		3 +#define IP_ADDRSTATE_DEPRICATED		4 +#define IP_ADDRSTATE_PREFERRED		5 +#define IP_ADDRSTATE_DISABLING		6 + +	uint8_t ipv6_dflt_rtr_state;    /* 225 */ +#define IPV6_RTRSTATE_UNKNOWN                   0 +#define IPV6_RTRSTATE_MANUAL                    1 +#define IPV6_RTRSTATE_ADVERTISED                3 +#define IPV6_RTRSTATE_STALE                     4 +  	uint8_t ipv6_traffic_class;	/* 226 */  	uint8_t ipv6_hop_limit;	/* 227 */  	uint8_t ipv6_if_id[8];	/* 228-22F */ @@ -424,7 +453,7 @@ struct addr_ctrl_blk {  struct init_fw_ctrl_blk {  	struct addr_ctrl_blk pri; -	struct addr_ctrl_blk sec; +/*	struct addr_ctrl_blk sec;*/  };  /*************************************************************************/ @@ -433,6 +462,9 @@ struct dev_db_entry {  	uint16_t options;	/* 00-01 */  #define DDB_OPT_DISC_SESSION  0x10  #define DDB_OPT_TARGET	      0x02 /* device is a target */ +#define DDB_OPT_IPV6_DEVICE	0x100 +#define DDB_OPT_IPV6_NULL_LINK_LOCAL		0x800 /* post connection */ +#define DDB_OPT_IPV6_FW_DEFINED_LINK_LOCAL	0x800 /* pre connection */  	uint16_t exec_throttle;	/* 02-03 */  	uint16_t exec_count;	/* 04-05 */ @@ -468,7 +500,7 @@ struct dev_db_entry {  					 * pointer to a string so we  					 * don't have to reserve soooo  					 * much RAM */ -	uint8_t ipv6_addr[0x10];/* 1A0-1AF */ +	uint8_t link_local_ipv6_addr[0x10]; /* 1A0-1AF */  	uint8_t res5[0x10];	/* 1B0-1BF */  	uint16_t ddb_link;	/* 1C0-1C1 */  	uint16_t chap_tbl_idx;	/* 1C2-1C3 */ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 96ebfb021f6..c4636f6cb3c 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -25,6 +25,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen);  int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha);  int qla4xxx_relogin_device(struct scsi_qla_host * ha,  			   struct ddb_entry * ddb_entry); +int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb);  int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,  		      int lun);  int qla4xxx_reset_target(struct scsi_qla_host * ha, @@ -65,13 +66,14 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,  int qla4xxx_init_rings(struct scsi_qla_host * ha);  struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha,  					uint32_t index); -void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb); +void qla4xxx_srb_compl(struct kref *ref);  int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); -int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha, -				uint32_t fw_ddb_index, uint32_t state); +int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, +		uint32_t state, uint32_t conn_error);  void qla4xxx_dump_buffer(void *b, uint32_t size);  int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,  	struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod); +int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err);  extern int ql4xextended_error_logging;  extern int ql4xdiscoverywait; diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 92329a461c6..5510df8a7fa 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -189,6 +189,78 @@ static int qla4xxx_init_local_data(struct scsi_qla_host *ha)  	return qla4xxx_get_firmware_status(ha);  } +static uint8_t +qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha) +{ +	uint8_t ipv4_wait = 0; +	uint8_t ipv6_wait = 0; +	int8_t ip_address[IPv6_ADDR_LEN] = {0} ; + +	/* If both IPv4 & IPv6 are enabled, possibly only one +	 * IP address may be acquired, so check to see if we +	 * need to wait for another */ +	if (is_ipv4_enabled(ha) && is_ipv6_enabled(ha)) { +		if (((ha->addl_fw_state & FW_ADDSTATE_DHCPv4_ENABLED) != 0) && +		    ((ha->addl_fw_state & +				    FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED) == 0)) { +			ipv4_wait = 1; +		} +		if (((ha->ipv6_addl_options & +			    IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) != 0) && +		    ((ha->ipv6_link_local_state == IP_ADDRSTATE_ACQUIRING) || +		     (ha->ipv6_addr0_state == IP_ADDRSTATE_ACQUIRING) || +		     (ha->ipv6_addr1_state == IP_ADDRSTATE_ACQUIRING))) { + +			ipv6_wait = 1; + +			if ((ha->ipv6_link_local_state == +						     IP_ADDRSTATE_PREFERRED) || +			    (ha->ipv6_addr0_state == IP_ADDRSTATE_PREFERRED) || +			    (ha->ipv6_addr1_state == IP_ADDRSTATE_PREFERRED)) { +				DEBUG2(printk(KERN_INFO "scsi%ld: %s: " +					      "Preferred IP configured." +					      " Don't wait!\n", ha->host_no, +					      __func__)); +				ipv6_wait = 0; +			} +			if (memcmp(&ha->ipv6_default_router_addr, ip_address, +				IPv6_ADDR_LEN) == 0) { +				DEBUG2(printk(KERN_INFO "scsi%ld: %s: " +					      "No Router configured. " +					      "Don't wait!\n", ha->host_no, +					      __func__)); +				ipv6_wait = 0; +			} +			if ((ha->ipv6_default_router_state == +						IPV6_RTRSTATE_MANUAL) && +			    (ha->ipv6_link_local_state == +						IP_ADDRSTATE_TENTATIVE) && +			    (memcmp(&ha->ipv6_link_local_addr, +				    &ha->ipv6_default_router_addr, 4) == 0)) { +				DEBUG2(printk("scsi%ld: %s: LinkLocal Router & " +					"IP configured. Don't wait!\n", +					ha->host_no, __func__)); +				ipv6_wait = 0; +			} +		} +		if (ipv4_wait || ipv6_wait) { +			DEBUG2(printk("scsi%ld: %s: Wait for additional " +				      "IP(s) \"", ha->host_no, __func__)); +			if (ipv4_wait) +				DEBUG2(printk("IPv4 ")); +			if (ha->ipv6_link_local_state == IP_ADDRSTATE_ACQUIRING) +				DEBUG2(printk("IPv6LinkLocal ")); +			if (ha->ipv6_addr0_state == IP_ADDRSTATE_ACQUIRING) +				DEBUG2(printk("IPv6Addr0 ")); +			if (ha->ipv6_addr1_state == IP_ADDRSTATE_ACQUIRING) +				DEBUG2(printk("IPv6Addr1 ")); +			DEBUG2(printk("\"\n")); +		} +	} + +	return ipv4_wait|ipv6_wait; +} +  static int qla4xxx_fw_ready(struct scsi_qla_host *ha)  {  	uint32_t timeout_count; @@ -226,38 +298,80 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)  			continue;  		} +		if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { +			DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" +				      "AUTOCONNECT in progress\n", +				      ha->host_no, __func__)); +		} + +		if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { +			DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" +				      " CONFIGURING IP\n", +				      ha->host_no, __func__)); +			/* +			 * Check for link state after 15 secs and if link is +			 * still DOWN then, cable is unplugged. Ignore "DHCP +			 * in Progress/CONFIGURING IP" bit to check if firmware +			 * is in ready state or not after 15 secs. +			 * This is applicable for both 2.x & 3.x firmware +			 */ +			if (timeout_count <= (ADAPTER_INIT_TOV - 15)) { +				if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) { +					DEBUG2(printk(KERN_INFO "scsi%ld: %s:" +						  " LINK UP (Cable plugged)\n", +						  ha->host_no, __func__)); +				} else if (ha->firmware_state & +					  (FW_STATE_CONFIGURING_IP | +							     FW_STATE_READY)) { +					DEBUG2(printk(KERN_INFO "scsi%ld: %s: " +						"LINK DOWN (Cable unplugged)\n", +						ha->host_no, __func__)); +					ha->firmware_state = FW_STATE_READY; +				} +			} +		} +  		if (ha->firmware_state == FW_STATE_READY) { -			DEBUG2(dev_info(&ha->pdev->dev, "Firmware Ready..\n")); -			/* The firmware is ready to process SCSI commands. */ -			DEBUG2(dev_info(&ha->pdev->dev, -					  "scsi%ld: %s: MEDIA TYPE - %s\n", -					  ha->host_no, -					  __func__, (ha->addl_fw_state & -						     FW_ADDSTATE_OPTICAL_MEDIA) -					  != 0 ? "OPTICAL" : "COPPER")); -			DEBUG2(dev_info(&ha->pdev->dev, -					  "scsi%ld: %s: DHCP STATE Enabled " -					  "%s\n", -					  ha->host_no, __func__, -					  (ha->addl_fw_state & -					   FW_ADDSTATE_DHCP_ENABLED) != 0 ? -					  "YES" : "NO")); -			DEBUG2(dev_info(&ha->pdev->dev, -					  "scsi%ld: %s: LINK %s\n", -					  ha->host_no, __func__, -					  (ha->addl_fw_state & -					   FW_ADDSTATE_LINK_UP) != 0 ? -					  "UP" : "DOWN")); -			DEBUG2(dev_info(&ha->pdev->dev, -					  "scsi%ld: %s: iSNS Service " -					  "Started %s\n", -					  ha->host_no, __func__, -					  (ha->addl_fw_state & -					   FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? -					  "YES" : "NO")); +			/* If DHCP IP Addr is available, retrieve it now. */ +			if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, +								&ha->dpc_flags)) +				qla4xxx_get_dhcp_ip_address(ha); -			ready = 1; -			break; +			if (!qla4xxx_wait_for_ip_config(ha) || +							timeout_count == 1) { +				DEBUG2(dev_info(&ha->pdev->dev, +						"Firmware Ready..\n")); +				/* The firmware is ready to process SCSI +				   commands. */ +				DEBUG2(dev_info(&ha->pdev->dev, +					"scsi%ld: %s: MEDIA TYPE" +					" - %s\n", ha->host_no, +					__func__, (ha->addl_fw_state & +					FW_ADDSTATE_OPTICAL_MEDIA) +					!= 0 ? "OPTICAL" : "COPPER")); +				DEBUG2(dev_info(&ha->pdev->dev, +					"scsi%ld: %s: DHCPv4 STATE" +					" Enabled %s\n", ha->host_no, +					 __func__, (ha->addl_fw_state & +					 FW_ADDSTATE_DHCPv4_ENABLED) != 0 ? +					"YES" : "NO")); +				DEBUG2(dev_info(&ha->pdev->dev, +					"scsi%ld: %s: LINK %s\n", +					ha->host_no, __func__, +					(ha->addl_fw_state & +					 FW_ADDSTATE_LINK_UP) != 0 ? +					"UP" : "DOWN")); +				DEBUG2(dev_info(&ha->pdev->dev, +					"scsi%ld: %s: iSNS Service " +					"Started %s\n", +					ha->host_no, __func__, +					(ha->addl_fw_state & +					 FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? +					"YES" : "NO")); + +				ready = 1; +				break; +			}  		}  		DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - "  			      "seconds expired= %d\n", ha->host_no, __func__, @@ -272,15 +386,19 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)  		msleep(1000);  	}			/* end of for */ -	if (timeout_count == 0) +	if (timeout_count <= 0)  		DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n",  			      ha->host_no, __func__)); -	if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)  { -		DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to" -			      " grab an IP address from DHCP server\n", -			      ha->host_no, __func__)); +	if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { +		DEBUG2(printk("scsi%ld: %s: FW initialized, but is reporting " +			      "it's waiting to configure an IP address\n", +			       ha->host_no, __func__));  		ready = 1; +	} else if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { +		DEBUG2(printk("scsi%ld: %s: FW initialized, but " +			      "auto-discovery still in process\n", +			       ha->host_no, __func__));  	}  	return ready; @@ -387,6 +505,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,  	struct dev_db_entry *fw_ddb_entry = NULL;  	dma_addr_t fw_ddb_entry_dma;  	int status = QLA_ERROR; +	uint32_t conn_err;  	if (ddb_entry == NULL) {  		DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no, @@ -407,7 +526,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,  	if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,  				    fw_ddb_entry_dma, NULL, NULL, -				    &ddb_entry->fw_ddb_device_state, NULL, +				    &ddb_entry->fw_ddb_device_state, &conn_err,  				    &ddb_entry->tcp_source_port_num,  				    &ddb_entry->connection_id) ==  	    QLA_ERROR) { @@ -419,6 +538,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,  	}  	status = QLA_SUCCESS; +	ddb_entry->options = le16_to_cpu(fw_ddb_entry->options);  	ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid);  	ddb_entry->task_mgmt_timeout =  		le16_to_cpu(fw_ddb_entry->def_timeout); @@ -442,11 +562,44 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,  	memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0],  	       min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr))); -	DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n", -		      ha->host_no, __func__, fw_ddb_index, -		      ddb_entry->fw_ddb_device_state, status)); +	ddb_entry->iscsi_max_burst_len = fw_ddb_entry->iscsi_max_burst_len; +	ddb_entry->iscsi_max_outsnd_r2t = fw_ddb_entry->iscsi_max_outsnd_r2t; +	ddb_entry->iscsi_first_burst_len = fw_ddb_entry->iscsi_first_burst_len; +	ddb_entry->iscsi_max_rcv_data_seg_len = +				fw_ddb_entry->iscsi_max_rcv_data_seg_len; +	ddb_entry->iscsi_max_snd_data_seg_len = +				fw_ddb_entry->iscsi_max_snd_data_seg_len; + +	if (ddb_entry->options & DDB_OPT_IPV6_DEVICE) { +		memcpy(&ddb_entry->remote_ipv6_addr, +			fw_ddb_entry->ip_addr, +			min(sizeof(ddb_entry->remote_ipv6_addr), +			sizeof(fw_ddb_entry->ip_addr))); +		memcpy(&ddb_entry->link_local_ipv6_addr, +			fw_ddb_entry->link_local_ipv6_addr, +			min(sizeof(ddb_entry->link_local_ipv6_addr), +			sizeof(fw_ddb_entry->link_local_ipv6_addr))); - exit_update_ddb: +		DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d " +					"State %04x ConnErr %08x IP %pI6 " +					":%04d \"%s\"\n", +					__func__, fw_ddb_index, +					ddb_entry->os_target_id, +					ddb_entry->fw_ddb_device_state, +					conn_err, fw_ddb_entry->ip_addr, +					le16_to_cpu(fw_ddb_entry->port), +					fw_ddb_entry->iscsi_name)); +	} else +		DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d " +					"State %04x ConnErr %08x IP %pI4 " +					":%04d \"%s\"\n", +					__func__, fw_ddb_index, +					ddb_entry->os_target_id, +					ddb_entry->fw_ddb_device_state, +					conn_err, fw_ddb_entry->ip_addr, +					le16_to_cpu(fw_ddb_entry->port), +					fw_ddb_entry->iscsi_name)); +exit_update_ddb:  	if (fw_ddb_entry)  		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),  				  fw_ddb_entry, fw_ddb_entry_dma); @@ -492,6 +645,40 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,  }  /** + * qla4_is_relogin_allowed - Are we allowed to login? + * @ha: Pointer to host adapter structure. + * @conn_err: Last connection error associated with the ddb + * + * This routine tests the given connection error to determine if + * we are allowed to login. + **/ +int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err) +{ +	uint32_t err_code, login_rsp_sts_class; +	int relogin = 1; + +	err_code = ((conn_err & 0x00ff0000) >> 16); +	login_rsp_sts_class = ((conn_err & 0x0000ff00) >> 8); +	if (err_code == 0x1c || err_code == 0x06) { +		DEBUG2(dev_info(&ha->pdev->dev, +				": conn_err=0x%08x, send target completed" +				" or access denied failure\n", conn_err)); +		relogin = 0; +	} +	if ((err_code == 0x08) && (login_rsp_sts_class == 0x02)) { +		/* Login Response PDU returned an error. +		   Login Response Status in Error Code Detail +		   indicates login should not be retried.*/ +		DEBUG2(dev_info(&ha->pdev->dev, +				": conn_err=0x%08x, do not retry relogin\n", +				conn_err)); +		relogin = 0; +	} + +	return relogin; +} + +/**   * qla4xxx_configure_ddbs - builds driver ddb list   * @ha: Pointer to host adapter structure.   * @@ -505,18 +692,30 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)  	uint32_t fw_ddb_index = 0;  	uint32_t next_fw_ddb_index = 0;  	uint32_t ddb_state; -	uint32_t conn_err, err_code; +	uint32_t conn_err;  	struct ddb_entry *ddb_entry; +	struct dev_db_entry *fw_ddb_entry = NULL; +	dma_addr_t fw_ddb_entry_dma; +	uint32_t ipv6_device;  	uint32_t new_tgt; +	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), +			&fw_ddb_entry_dma, GFP_KERNEL); +	if (fw_ddb_entry == NULL) { +		DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n", +				__func__)); +		return QLA_ERROR; +	} +  	dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");  	for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;  	     fw_ddb_index = next_fw_ddb_index) {  		/* First, let's see if a device exists here */ -		if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL, -					    &next_fw_ddb_index, &ddb_state, -					    &conn_err, NULL, NULL) == -		    QLA_ERROR) { +		if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, +					    0, NULL, &next_fw_ddb_index, +					    &ddb_state, &conn_err, +					    NULL, NULL) == +					    QLA_ERROR) {  			DEBUG2(printk("scsi%ld: %s: get_ddb_entry, "  				      "fw_ddb_index %d failed", ha->host_no,  				      __func__, fw_ddb_index)); @@ -533,18 +732,19 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)  			/* Try and login to device */  			DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n",  				      ha->host_no, __func__, fw_ddb_index)); -			err_code = ((conn_err & 0x00ff0000) >> 16); -			if (err_code == 0x1c || err_code == 0x06) { -				DEBUG2(printk("scsi%ld: %s send target " -					      "completed " -					      "or access denied failure\n", -					      ha->host_no, __func__)); -			} else { +			ipv6_device = le16_to_cpu(fw_ddb_entry->options) & +					DDB_OPT_IPV6_DEVICE; +			if (qla4_is_relogin_allowed(ha, conn_err) && +					((!ipv6_device && +					  *((uint32_t *)fw_ddb_entry->ip_addr)) +					 || ipv6_device)) {  				qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0);  				if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, -					NULL, 0, NULL, &next_fw_ddb_index, -					&ddb_state, &conn_err, NULL, NULL) -					== QLA_ERROR) { +							NULL, 0, NULL, +							&next_fw_ddb_index, +							&ddb_state, &conn_err, +							NULL, NULL) +						== QLA_ERROR) {  					DEBUG2(printk("scsi%ld: %s:"  						"get_ddb_entry %d failed\n",  						ha->host_no, @@ -599,7 +799,6 @@ next_one:  struct qla4_relog_scan {  	int halt_wait;  	uint32_t conn_err; -	uint32_t err_code;  	uint32_t fw_ddb_index;  	uint32_t next_fw_ddb_index;  	uint32_t fw_ddb_device_state; @@ -609,18 +808,7 @@ static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs)  {  	struct ddb_entry *ddb_entry; -	/* -	 * Don't want to do a relogin if connection -	 * error is 0x1c. -	 */ -	rs->err_code = ((rs->conn_err & 0x00ff0000) >> 16); -	if (rs->err_code == 0x1c || rs->err_code == 0x06) { -		DEBUG2(printk( -			       "scsi%ld: %s send target" -			       " completed or " -			       "access denied failure\n", -			       ha->host_no, __func__)); -	} else { +	if (qla4_is_relogin_allowed(ha, rs->conn_err)) {  		/* We either have a device that is in  		 * the process of relogging in or a  		 * device that is waiting to be @@ -908,7 +1096,7 @@ static void qla4x00_pci_config(struct scsi_qla_host *ha)  static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)  {  	int status = QLA_ERROR; -	uint32_t max_wait_time; +	unsigned long max_wait_time;  	unsigned long flags;  	uint32_t mbox_status; @@ -940,7 +1128,10 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)  	spin_unlock_irqrestore(&ha->hardware_lock, flags);  	/* Wait for firmware to come UP. */ -	max_wait_time = FIRMWARE_UP_TOV * 4; +	DEBUG2(printk(KERN_INFO "scsi%ld: %s: Wait up to %d seconds for " +		      "boot firmware to complete...\n", +		      ha->host_no, __func__, FIRMWARE_UP_TOV)); +	max_wait_time = jiffies + (FIRMWARE_UP_TOV * HZ);  	do {  		uint32_t ctrl_status; @@ -954,16 +1145,15 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)  		if (mbox_status == MBOX_STS_COMMAND_COMPLETE)  			break; -		DEBUG2(printk("scsi%ld: %s: Waiting for boot firmware to " -			      "complete... ctrl_sts=0x%x, remaining=%d\n", -			      ha->host_no, __func__, ctrl_status, -			      max_wait_time)); +		DEBUG2(printk(KERN_INFO "scsi%ld: %s: Waiting for boot " +			      "firmware to complete... ctrl_sts=0x%x\n", +			      ha->host_no, __func__, ctrl_status)); -		msleep(250); -	} while ((max_wait_time--)); +		msleep_interruptible(250); +	} while (!time_after_eq(jiffies, max_wait_time));  	if (mbox_status == MBOX_STS_COMMAND_COMPLETE) { -		DEBUG(printk("scsi%ld: %s: Firmware has started\n", +		DEBUG(printk(KERN_INFO "scsi%ld: %s: Firmware has started\n",  			     ha->host_no, __func__));  		spin_lock_irqsave(&ha->hardware_lock, flags); @@ -1141,6 +1331,7 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,  	int status = QLA_ERROR;  	int8_t ip_address[IP_ADDR_LEN] = {0} ; +	clear_bit(AF_ONLINE, &ha->flags);  	ha->eeprom_cmd_data = 0;  	qla4x00_pci_config(ha); @@ -1166,7 +1357,7 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,  	 * the ddb_list and wait for DHCP lease acquired aen to come in  	 * followed by 0x8014 aen" to trigger the tgt discovery process.  	 */ -	if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) +	if (ha->firmware_state & FW_STATE_CONFIGURING_IP)  		goto exit_init_online;  	/* Skip device discovery if ip and subnet is zero */ @@ -1270,8 +1461,8 @@ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,   *   * This routine processes a Decive Database Changed AEN Event.   **/ -int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, -				uint32_t fw_ddb_index, uint32_t state) +int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, +		uint32_t state, uint32_t conn_err)  {  	struct ddb_entry * ddb_entry;  	uint32_t old_fw_ddb_device_state; @@ -1318,19 +1509,24 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,  		 * the device came back.  		 */  	} else { -		/* Device went away, try to relogin. */ -		/* Mark device missing */ -		if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) +		/* Device went away, mark device missing */ +		if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) { +			DEBUG2(dev_info(&ha->pdev->dev, "%s mark missing " +					"ddb_entry 0x%p sess 0x%p conn 0x%p\n", +					__func__, ddb_entry, +					ddb_entry->sess, ddb_entry->conn));  			qla4xxx_mark_device_missing(ha, ddb_entry); +		} +  		/*  		 * Relogin if device state changed to a not active state. -		 * However, do not relogin if this aen is a result of an IOCTL -		 * logout (DF_NO_RELOGIN) or if this is a discovered device. +		 * However, do not relogin if a RELOGIN is in process, or +		 * we are not allowed to relogin to this DDB.  		 */  		if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED &&  		    !test_bit(DF_RELOGIN, &ddb_entry->flags) &&  		    !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) && -		    !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) { +		    qla4_is_relogin_allowed(ha, conn_err)) {  			/*  			 * This triggers a relogin.  After the relogin_timer  			 * expires, the relogin gets scheduled.	 We must wait a @@ -1338,7 +1534,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,  			 * with failed device_state or a logout response before  			 * we can issue another relogin.  			 */ -			/* Firmware padds this timeout: (time2wait +1). +			/* Firmware pads this timeout: (time2wait +1).  			 * Driver retry to login should be longer than F/W.  			 * Otherwise F/W will fail  			 * set_ddb() mbx cmd with 0x4005 since it still diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index e0c32159749..e66f3f263f4 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c @@ -299,7 +299,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)  	qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);  	wmb(); -	srb->cmd->host_scribble = (unsigned char *)srb; +	srb->cmd->host_scribble = (unsigned char *)(unsigned long)index;  	/* update counters */  	srb->state = SRB_ACTIVE_STATE; diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index c196d55eae3..596c3031483 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -97,7 +97,7 @@ qla4xxx_status_cont_entry(struct scsi_qla_host *ha,  	/* Place command on done queue. */  	if (srb->req_sense_len == 0) { -		qla4xxx_srb_compl(ha, srb); +		kref_put(&srb->srb_ref, qla4xxx_srb_compl);  		ha->status_srb = NULL;  	}  } @@ -329,7 +329,7 @@ status_entry_exit:  	/* complete the request, if not waiting for status_continuation pkt */  	srb->cc_stat = sts_entry->completionStatus;  	if (ha->status_srb == NULL) -		qla4xxx_srb_compl(ha, srb); +		kref_put(&srb->srb_ref, qla4xxx_srb_compl);  }  /** @@ -393,7 +393,7 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)  			/* ETRY normally by sending it back with  			 * DID_BUS_BUSY */  			srb->cmd->result = DID_BUS_BUSY << 16; -			qla4xxx_srb_compl(ha, srb); +			kref_put(&srb->srb_ref, qla4xxx_srb_compl);  			break;  		case ET_CONTINUE: @@ -498,15 +498,22 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,  			break;  		case MBOX_ASTS_LINK_UP: -			DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK UP\n", -				      ha->host_no, mbox_status));  			set_bit(AF_LINK_UP, &ha->flags); +			if (test_bit(AF_INIT_DONE, &ha->flags)) +				set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); + +			DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter" +					" LINK UP\n", ha->host_no, +					mbox_status));  			break;  		case MBOX_ASTS_LINK_DOWN: -			DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK DOWN\n", -				      ha->host_no, mbox_status));  			clear_bit(AF_LINK_UP, &ha->flags); +			set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); + +			DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter" +					" LINK DOWN\n", ha->host_no, +					mbox_status));  			break;  		case MBOX_ASTS_HEARTBEAT: @@ -831,7 +838,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)  				qla4xxx_reinitialize_ddb_list(ha);  			} else if (mbox_sts[1] == 1) {	/* Specific device. */  				qla4xxx_process_ddb_changed(ha, mbox_sts[2], -							    mbox_sts[3]); +						mbox_sts[3], mbox_sts[4]);  			}  			break;  		} diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index caeb7d10ae0..75496fb0ae7 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -172,108 +172,207 @@ mbox_exit:  	return status;  } +uint8_t +qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, +		 uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) +{ +	memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); +	memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); +	mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE; +	mbox_cmd[1] = 0; +	mbox_cmd[2] = LSDW(init_fw_cb_dma); +	mbox_cmd[3] = MSDW(init_fw_cb_dma); +	mbox_cmd[4] = sizeof(struct addr_ctrl_blk); +	mbox_cmd[5] = (IFCB_VER_MAX << 8) | IFCB_VER_MIN; + +	if (qla4xxx_mailbox_command(ha, 6, 6, mbox_cmd, mbox_sts) != +	    QLA_SUCCESS) { +		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: " +			      "MBOX_CMD_INITIALIZE_FIRMWARE" +			      " failed w/ status %04X\n", +			      ha->host_no, __func__, mbox_sts[0])); +		return QLA_ERROR; +	} +	return QLA_SUCCESS; +} + +uint8_t +qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, +		 uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) +{ +	memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); +	memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); +	mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; +	mbox_cmd[2] = LSDW(init_fw_cb_dma); +	mbox_cmd[3] = MSDW(init_fw_cb_dma); +	mbox_cmd[4] = sizeof(struct addr_ctrl_blk); + +	if (qla4xxx_mailbox_command(ha, 5, 5, mbox_cmd, mbox_sts) != +	    QLA_SUCCESS) { +		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: " +			      "MBOX_CMD_GET_INIT_FW_CTRL_BLOCK" +			      " failed w/ status %04X\n", +			      ha->host_no, __func__, mbox_sts[0])); +		return QLA_ERROR; +	} +	return QLA_SUCCESS; +} + +void +qla4xxx_update_local_ip(struct scsi_qla_host *ha, +			 struct addr_ctrl_blk  *init_fw_cb) +{ +	/* Save IPv4 Address Info */ +	memcpy(ha->ip_address, init_fw_cb->ipv4_addr, +		min(sizeof(ha->ip_address), sizeof(init_fw_cb->ipv4_addr))); +	memcpy(ha->subnet_mask, init_fw_cb->ipv4_subnet, +		min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->ipv4_subnet))); +	memcpy(ha->gateway, init_fw_cb->ipv4_gw_addr, +		min(sizeof(ha->gateway), sizeof(init_fw_cb->ipv4_gw_addr))); + +	if (is_ipv6_enabled(ha)) { +		/* Save IPv6 Address */ +		ha->ipv6_link_local_state = init_fw_cb->ipv6_lnk_lcl_addr_state; +		ha->ipv6_addr0_state = init_fw_cb->ipv6_addr0_state; +		ha->ipv6_addr1_state = init_fw_cb->ipv6_addr1_state; +		ha->ipv6_default_router_state = init_fw_cb->ipv6_dflt_rtr_state; +		ha->ipv6_link_local_addr.in6_u.u6_addr8[0] = 0xFE; +		ha->ipv6_link_local_addr.in6_u.u6_addr8[1] = 0x80; + +		memcpy(&ha->ipv6_link_local_addr.in6_u.u6_addr8[8], +			init_fw_cb->ipv6_if_id, +			min(sizeof(ha->ipv6_link_local_addr)/2, +			sizeof(init_fw_cb->ipv6_if_id))); +		memcpy(&ha->ipv6_addr0, init_fw_cb->ipv6_addr0, +			min(sizeof(ha->ipv6_addr0), +			sizeof(init_fw_cb->ipv6_addr0))); +		memcpy(&ha->ipv6_addr1, init_fw_cb->ipv6_addr1, +			min(sizeof(ha->ipv6_addr1), +			sizeof(init_fw_cb->ipv6_addr1))); +		memcpy(&ha->ipv6_default_router_addr, +			init_fw_cb->ipv6_dflt_rtr_addr, +			min(sizeof(ha->ipv6_default_router_addr), +			sizeof(init_fw_cb->ipv6_dflt_rtr_addr))); +	} +} + +uint8_t +qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, +			  uint32_t *mbox_cmd, +			  uint32_t *mbox_sts, +			  struct addr_ctrl_blk  *init_fw_cb, +			  dma_addr_t init_fw_cb_dma) +{ +	if (qla4xxx_get_ifcb(ha, mbox_cmd, mbox_sts, init_fw_cb_dma) +	    != QLA_SUCCESS) { +		DEBUG2(printk(KERN_WARNING +			      "scsi%ld: %s: Failed to get init_fw_ctrl_blk\n", +			      ha->host_no, __func__)); +		return QLA_ERROR; +	} + +	DEBUG2(qla4xxx_dump_buffer(init_fw_cb, sizeof(struct addr_ctrl_blk))); + +	/* Save some info in adapter structure. */ +	ha->acb_version = init_fw_cb->acb_version; +	ha->firmware_options = le16_to_cpu(init_fw_cb->fw_options); +	ha->tcp_options = le16_to_cpu(init_fw_cb->ipv4_tcp_opts); +	ha->ipv4_options = le16_to_cpu(init_fw_cb->ipv4_ip_opts); +	ha->ipv4_addr_state = le16_to_cpu(init_fw_cb->ipv4_addr_state); +	ha->heartbeat_interval = init_fw_cb->hb_interval; +	memcpy(ha->name_string, init_fw_cb->iscsi_name, +		min(sizeof(ha->name_string), +		sizeof(init_fw_cb->iscsi_name))); +	/*memcpy(ha->alias, init_fw_cb->Alias, +	       min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ + +	/* Save Command Line Paramater info */ +	ha->port_down_retry_count = le16_to_cpu(init_fw_cb->conn_ka_timeout); +	ha->discovery_wait = ql4xdiscoverywait; + +	if (ha->acb_version == ACB_SUPPORTED) { +		ha->ipv6_options = init_fw_cb->ipv6_opts; +		ha->ipv6_addl_options = init_fw_cb->ipv6_addtl_opts; +	} +	qla4xxx_update_local_ip(ha, init_fw_cb); + +	return QLA_SUCCESS; +} +  /**   * qla4xxx_initialize_fw_cb - initializes firmware control block.   * @ha: Pointer to host adapter structure.   **/  int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)  { -	struct init_fw_ctrl_blk *init_fw_cb; +	struct addr_ctrl_blk *init_fw_cb;  	dma_addr_t init_fw_cb_dma;  	uint32_t mbox_cmd[MBOX_REG_COUNT];  	uint32_t mbox_sts[MBOX_REG_COUNT];  	int status = QLA_ERROR;  	init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, -					sizeof(struct init_fw_ctrl_blk), +					sizeof(struct addr_ctrl_blk),  					&init_fw_cb_dma, GFP_KERNEL);  	if (init_fw_cb == NULL) {  		DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n",  			      ha->host_no, __func__));  		return 10;  	} -	memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk)); +	memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));  	/* Get Initialize Firmware Control Block. */  	memset(&mbox_cmd, 0, sizeof(mbox_cmd));  	memset(&mbox_sts, 0, sizeof(mbox_sts)); -	mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; -	mbox_cmd[2] = LSDW(init_fw_cb_dma); -	mbox_cmd[3] = MSDW(init_fw_cb_dma); -	mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk); - -	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) != +	if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) !=  	    QLA_SUCCESS) {  		dma_free_coherent(&ha->pdev->dev, -				  sizeof(struct init_fw_ctrl_blk), +				  sizeof(struct addr_ctrl_blk),  				  init_fw_cb, init_fw_cb_dma); -		return status; +		goto exit_init_fw_cb;  	}  	/* Initialize request and response queues. */  	qla4xxx_init_rings(ha);  	/* Fill in the request and response queue information. */ -	init_fw_cb->pri.rqq_consumer_idx = cpu_to_le16(ha->request_out); -	init_fw_cb->pri.compq_producer_idx = cpu_to_le16(ha->response_in); -	init_fw_cb->pri.rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH); -	init_fw_cb->pri.compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH); -	init_fw_cb->pri.rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma)); -	init_fw_cb->pri.rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma)); -	init_fw_cb->pri.compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma)); -	init_fw_cb->pri.compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma)); -	init_fw_cb->pri.shdwreg_addr_lo = -		cpu_to_le32(LSDW(ha->shadow_regs_dma)); -	init_fw_cb->pri.shdwreg_addr_hi = -		cpu_to_le32(MSDW(ha->shadow_regs_dma)); +	init_fw_cb->rqq_consumer_idx = cpu_to_le16(ha->request_out); +	init_fw_cb->compq_producer_idx = cpu_to_le16(ha->response_in); +	init_fw_cb->rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH); +	init_fw_cb->compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH); +	init_fw_cb->rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma)); +	init_fw_cb->rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma)); +	init_fw_cb->compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma)); +	init_fw_cb->compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma)); +	init_fw_cb->shdwreg_addr_lo = cpu_to_le32(LSDW(ha->shadow_regs_dma)); +	init_fw_cb->shdwreg_addr_hi = cpu_to_le32(MSDW(ha->shadow_regs_dma));  	/* Set up required options. */ -	init_fw_cb->pri.fw_options |= +	init_fw_cb->fw_options |=  		__constant_cpu_to_le16(FWOPT_SESSION_MODE |  				       FWOPT_INITIATOR_MODE); -	init_fw_cb->pri.fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); +	init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); -	/* Save some info in adapter structure. */ -	ha->firmware_options = le16_to_cpu(init_fw_cb->pri.fw_options); -	ha->tcp_options = le16_to_cpu(init_fw_cb->pri.ipv4_tcp_opts); -	ha->heartbeat_interval = init_fw_cb->pri.hb_interval; -	memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr, -	       min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr))); -	memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet, -	       min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet))); -	memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr, -	       min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr))); -	memcpy(ha->name_string, init_fw_cb->pri.iscsi_name, -	       min(sizeof(ha->name_string), -		   sizeof(init_fw_cb->pri.iscsi_name))); -	/*memcpy(ha->alias, init_fw_cb->Alias, -	       min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ - -	/* Save Command Line Paramater info */ -	ha->port_down_retry_count = le16_to_cpu(init_fw_cb->pri.conn_ka_timeout); -	ha->discovery_wait = ql4xdiscoverywait; - -	/* Send Initialize Firmware Control Block. */ -	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); -	memset(&mbox_sts, 0, sizeof(mbox_sts)); - -	mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE; -	mbox_cmd[1] = 0; -	mbox_cmd[2] = LSDW(init_fw_cb_dma); -	mbox_cmd[3] = MSDW(init_fw_cb_dma); -	mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk); +	if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) +		!= QLA_SUCCESS) { +		DEBUG2(printk(KERN_WARNING +			      "scsi%ld: %s: Failed to set init_fw_ctrl_blk\n", +			      ha->host_no, __func__)); +		goto exit_init_fw_cb; +	} -	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) == -	    QLA_SUCCESS) -		status = QLA_SUCCESS; -	 else { -		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE " -			      "failed w/ status %04X\n", ha->host_no, __func__, -			      mbox_sts[0])); +	if (qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], +		init_fw_cb, init_fw_cb_dma) != QLA_SUCCESS) { +		DEBUG2(printk("scsi%ld: %s: Failed to update local ifcb\n", +				ha->host_no, __func__)); +		goto exit_init_fw_cb;  	} -	dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk), -			  init_fw_cb, init_fw_cb_dma); +	status = QLA_SUCCESS; + +exit_init_fw_cb: +	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), +				init_fw_cb, init_fw_cb_dma);  	return status;  } @@ -284,13 +383,13 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)   **/  int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)  { -	struct init_fw_ctrl_blk *init_fw_cb; +	struct addr_ctrl_blk *init_fw_cb;  	dma_addr_t init_fw_cb_dma;  	uint32_t mbox_cmd[MBOX_REG_COUNT];  	uint32_t mbox_sts[MBOX_REG_COUNT];  	init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, -					sizeof(struct init_fw_ctrl_blk), +					sizeof(struct addr_ctrl_blk),  					&init_fw_cb_dma, GFP_KERNEL);  	if (init_fw_cb == NULL) {  		printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, @@ -299,35 +398,21 @@ int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)  	}  	/* Get Initialize Firmware Control Block. */ -	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); -	memset(&mbox_sts, 0, sizeof(mbox_sts)); - -	memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk)); -	mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; -	mbox_cmd[2] = LSDW(init_fw_cb_dma); -	mbox_cmd[3] = MSDW(init_fw_cb_dma); -	mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk); - -	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) != +	memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); +	if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) !=  	    QLA_SUCCESS) {  		DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",  			      ha->host_no, __func__));  		dma_free_coherent(&ha->pdev->dev, -				  sizeof(struct init_fw_ctrl_blk), +				  sizeof(struct addr_ctrl_blk),  				  init_fw_cb, init_fw_cb_dma);  		return QLA_ERROR;  	}  	/* Save IP Address. */ -	memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr, -	       min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr))); -	memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet, -	       min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet))); -	memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr, -	       min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr))); - -	dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk), -			  init_fw_cb, init_fw_cb_dma); +	qla4xxx_update_local_ip(ha, init_fw_cb); +	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), +				init_fw_cb, init_fw_cb_dma);  	return QLA_SUCCESS;  } @@ -409,6 +494,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,  			    uint16_t *connection_id)  {  	int status = QLA_ERROR; +	uint16_t options;  	uint32_t mbox_cmd[MBOX_REG_COUNT];  	uint32_t mbox_sts[MBOX_REG_COUNT]; @@ -441,14 +527,26 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,  		goto exit_get_fwddb;  	}  	if (fw_ddb_entry) { -		dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d " -			   "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", -			   fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3], -			   mbox_sts[4], mbox_sts[5], fw_ddb_entry->ip_addr[0], -			   fw_ddb_entry->ip_addr[1], fw_ddb_entry->ip_addr[2], -			   fw_ddb_entry->ip_addr[3], -			   le16_to_cpu(fw_ddb_entry->port), -			   fw_ddb_entry->iscsi_name); +		options = le16_to_cpu(fw_ddb_entry->options); +		if (options & DDB_OPT_IPV6_DEVICE) { +			dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d " +				"Next %d State %04x ConnErr %08x %pI6 " +				":%04d \"%s\"\n", __func__, fw_ddb_index, +				mbox_sts[0], mbox_sts[2], mbox_sts[3], +				mbox_sts[4], mbox_sts[5], +				fw_ddb_entry->ip_addr, +				le16_to_cpu(fw_ddb_entry->port), +				fw_ddb_entry->iscsi_name); +		} else { +			dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d " +				"Next %d State %04x ConnErr %08x %pI4 " +				":%04d \"%s\"\n", __func__, fw_ddb_index, +				mbox_sts[0], mbox_sts[2], mbox_sts[3], +				mbox_sts[4], mbox_sts[5], +				fw_ddb_entry->ip_addr, +				le16_to_cpu(fw_ddb_entry->port), +				fw_ddb_entry->iscsi_name); +		}  	}  	if (num_valid_ddb_entries)  		*num_valid_ddb_entries = mbox_sts[2]; @@ -664,6 +762,59 @@ exit_get_event_log:  }  /** + * qla4xxx_abort_task - issues Abort Task + * @ha: Pointer to host adapter structure. + * @srb: Pointer to srb entry + * + * This routine performs a LUN RESET on the specified target/lun. + * The caller must ensure that the ddb_entry and lun_entry pointers + * are valid before calling this routine. + **/ +int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb) +{ +	uint32_t mbox_cmd[MBOX_REG_COUNT]; +	uint32_t mbox_sts[MBOX_REG_COUNT]; +	struct scsi_cmnd *cmd = srb->cmd; +	int status = QLA_SUCCESS; +	unsigned long flags = 0; +	uint32_t index; + +	/* +	 * Send abort task command to ISP, so that the ISP will return +	 * request with ABORT status +	 */ +	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); +	memset(&mbox_sts, 0, sizeof(mbox_sts)); + +	spin_lock_irqsave(&ha->hardware_lock, flags); +	index = (unsigned long)(unsigned char *)cmd->host_scribble; +	spin_unlock_irqrestore(&ha->hardware_lock, flags); + +	/* Firmware already posted completion on response queue */ +	if (index == MAX_SRBS) +		return status; + +	mbox_cmd[0] = MBOX_CMD_ABORT_TASK; +	mbox_cmd[1] = srb->fw_ddb_index; +	mbox_cmd[2] = index; +	/* Immediate Command Enable */ +	mbox_cmd[5] = 0x01; + +	qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], +	    &mbox_sts[0]); +	if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE) { +		status = QLA_ERROR; + +		DEBUG2(printk(KERN_WARNING "scsi%ld:%d:%d: abort task FAILED: " +		    "mbx0=%04X, mb1=%04X, mb2=%04X, mb3=%04X, mb4=%04X\n", +		    ha->host_no, cmd->device->id, cmd->device->lun, mbox_sts[0], +		    mbox_sts[1], mbox_sts[2], mbox_sts[3], mbox_sts[4])); +	} + +	return status; +} + +/**   * qla4xxx_reset_lun - issues LUN Reset   * @ha: Pointer to host adapter structure.   * @db_entry: Pointer to device database entry diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 2ccad36bee9..38b1d38afca 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -74,6 +74,7 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);   */  static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,  				void (*done) (struct scsi_cmnd *)); +static int qla4xxx_eh_abort(struct scsi_cmnd *cmd);  static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);  static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);  static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); @@ -88,6 +89,7 @@ static struct scsi_host_template qla4xxx_driver_template = {  	.proc_name		= DRIVER_NAME,  	.queuecommand		= qla4xxx_queuecommand, +	.eh_abort_handler	= qla4xxx_eh_abort,  	.eh_device_reset_handler = qla4xxx_eh_device_reset,  	.eh_target_reset_handler = qla4xxx_eh_target_reset,  	.eh_host_reset_handler	= qla4xxx_eh_host_reset, @@ -384,12 +386,12 @@ static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,  	if (!srb)  		return srb; -	atomic_set(&srb->ref_count, 1); +	kref_init(&srb->srb_ref);  	srb->ha = ha;  	srb->ddb = ddb_entry;  	srb->cmd = cmd;  	srb->flags = 0; -	cmd->SCp.ptr = (void *)srb; +	CMD_SP(cmd) = (void *)srb;  	cmd->scsi_done = done;  	return srb; @@ -403,12 +405,14 @@ static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)  		scsi_dma_unmap(cmd);  		srb->flags &= ~SRB_DMA_VALID;  	} -	cmd->SCp.ptr = NULL; +	CMD_SP(cmd) = NULL;  } -void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb) +void qla4xxx_srb_compl(struct kref *ref)  { +	struct srb *srb = container_of(ref, struct srb, srb_ref);  	struct scsi_cmnd *cmd = srb->cmd; +	struct scsi_qla_host *ha = srb->ha;  	qla4xxx_srb_free_dma(ha, srb); @@ -685,6 +689,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)  	     test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||  	     test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||  	     test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || +	     test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||  	     test_bit(DPC_AEN, &ha->dpc_flags)) &&  	     ha->dpc_thread) {  		DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" @@ -886,11 +891,10 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)  		srb = qla4xxx_del_from_active_array(ha, i);  		if (srb != NULL) {  			srb->cmd->result = DID_RESET << 16; -			qla4xxx_srb_compl(ha, srb); +			kref_put(&srb->srb_ref, qla4xxx_srb_compl);  		}  	}  	spin_unlock_irqrestore(&ha->hardware_lock, flags); -  }  /** @@ -1069,6 +1073,54 @@ static void qla4xxx_do_dpc(struct work_struct *work)  	if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))  		qla4xxx_get_dhcp_ip_address(ha); +	/* ---- link change? --- */ +	if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { +		if (!test_bit(AF_LINK_UP, &ha->flags)) { +			/* ---- link down? --- */ +			list_for_each_entry_safe(ddb_entry, dtemp, +						 &ha->ddb_list, list) { +				if (atomic_read(&ddb_entry->state) == +						DDB_STATE_ONLINE) +					qla4xxx_mark_device_missing(ha, +							ddb_entry); +			} +		} else { +			/* ---- link up? --- * +			 * F/W will auto login to all devices ONLY ONCE after +			 * link up during driver initialization and runtime +			 * fatal error recovery.  Therefore, the driver must +			 * manually relogin to devices when recovering from +			 * connection failures, logouts, expired KATO, etc. */ + +			list_for_each_entry_safe(ddb_entry, dtemp, +							&ha->ddb_list, list) { +				if ((atomic_read(&ddb_entry->state) == +						 DDB_STATE_MISSING) || +				    (atomic_read(&ddb_entry->state) == +						 DDB_STATE_DEAD)) { +					if (ddb_entry->fw_ddb_device_state == +					    DDB_DS_SESSION_ACTIVE) { +						atomic_set(&ddb_entry->state, +							   DDB_STATE_ONLINE); +						dev_info(&ha->pdev->dev, +						    "scsi%ld: %s: ddb[%d]" +						    " os[%d] marked" +						    " ONLINE\n", +						    ha->host_no, __func__, +						    ddb_entry->fw_ddb_index, +						    ddb_entry->os_target_id); + +						iscsi_unblock_session( +						    ddb_entry->sess); +					} else +						qla4xxx_relogin_device( +						    ha, ddb_entry); +				} + +			} +		} +	} +  	/* ---- relogin device? --- */  	if (adapter_up(ha) &&  	    test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { @@ -1430,12 +1482,14 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev)  struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index)  {  	struct srb *srb = NULL; -	struct scsi_cmnd *cmd; +	struct scsi_cmnd *cmd = NULL; -	if (!(cmd = scsi_host_find_tag(ha->host, index))) +	cmd = scsi_host_find_tag(ha->host, index); +	if (!cmd)  		return srb; -	if (!(srb = (struct srb *)cmd->host_scribble)) +	srb = (struct srb *)CMD_SP(cmd); +	if (!srb)  		return srb;  	/* update counters */ @@ -1443,14 +1497,15 @@ struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t in  		ha->req_q_count += srb->iocb_cnt;  		ha->iocb_cnt -= srb->iocb_cnt;  		if (srb->cmd) -			srb->cmd->host_scribble = NULL; +			srb->cmd->host_scribble = +				(unsigned char *)(unsigned long) MAX_SRBS;  	}  	return srb;  }  /**   * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware - * @ha: actual ha whose done queue will contain the comd returned by firmware. + * @ha: Pointer to host adapter structure.   * @cmd: Scsi Command to wait on.   *   * This routine waits for the command to be returned by the Firmware @@ -1465,7 +1520,7 @@ static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,  	do {  		/* Checking to see if its returned to OS */ -		rp = (struct srb *) cmd->SCp.ptr; +		rp = (struct srb *) CMD_SP(cmd);  		if (rp == NULL) {  			done++;  			break; @@ -1534,6 +1589,62 @@ static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,  }  /** + * qla4xxx_eh_abort - callback for abort task. + * @cmd: Pointer to Linux's SCSI command structure + * + * This routine is called by the Linux OS to abort the specified + * command. + **/ +static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) +{ +	struct scsi_qla_host *ha = to_qla_host(cmd->device->host); +	unsigned int id = cmd->device->id; +	unsigned int lun = cmd->device->lun; +	unsigned long serial = cmd->serial_number; +	struct srb *srb = NULL; +	int ret = SUCCESS; +	int wait = 0; + +	dev_info(&ha->pdev->dev, +	    "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n", +	    ha->host_no, id, lun, cmd, serial); + +	srb = (struct srb *) CMD_SP(cmd); + +	if (!srb) +		return SUCCESS; + +	kref_get(&srb->srb_ref); + +	if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { +		DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n", +		    ha->host_no, id, lun)); +		ret = FAILED; +	} else { +		DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n", +		    ha->host_no, id, lun)); +		wait = 1; +	} + +	kref_put(&srb->srb_ref, qla4xxx_srb_compl); + +	/* Wait for command to complete */ +	if (wait) { +		if (!qla4xxx_eh_wait_on_command(ha, cmd)) { +			DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n", +			    ha->host_no, id, lun)); +			ret = FAILED; +		} +	} + +	dev_info(&ha->pdev->dev, +	    "scsi%ld:%d:%d: Abort command - %s\n", +	    ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed"); + +	return ret; +} + +/**   * qla4xxx_eh_device_reset - callback for target reset.   * @cmd: Pointer to Linux's SCSI command structure   * diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 6980cb279c8..28a6c494a2e 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,5 +5,4 @@   * See LICENSE.qla4xxx for copyright and licensing details.   */ -#define QLA4XXX_DRIVER_VERSION	"5.01.00-k9" - +#define QLA4XXX_DRIVER_VERSION	"5.02.00-k1" diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 1c08f616465..ad0ed212db4 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -67,6 +67,9 @@  #include "scsi_priv.h"  #include "scsi_logging.h" +#define CREATE_TRACE_POINTS +#include <trace/events/scsi.h> +  static void scsi_done(struct scsi_cmnd *cmd);  /* @@ -747,10 +750,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)  		cmd->result = (DID_NO_CONNECT << 16);  		scsi_done(cmd);  	} else { +		trace_scsi_dispatch_cmd_start(cmd);  		rtn = host->hostt->queuecommand(cmd, scsi_done);  	}  	spin_unlock_irqrestore(host->host_lock, flags);  	if (rtn) { +		trace_scsi_dispatch_cmd_error(cmd, rtn);  		if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&  		    rtn != SCSI_MLQUEUE_TARGET_BUSY)  			rtn = SCSI_MLQUEUE_HOST_BUSY; @@ -781,6 +786,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)   */  static void scsi_done(struct scsi_cmnd *cmd)  { +	trace_scsi_dispatch_cmd_done(cmd);  	blk_complete_request(cmd->request);  } diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 3a5bfd10b2c..136329b4027 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -12,7 +12,7 @@   *  SAS disks.   *   * - *  For documentation see http://www.torque.net/sg/sdebug26.html + *  For documentation see http://sg.danny.cz/sg/sdebug26.html   *   *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]   *   dpg: work for devfs large number of disks [20010809] @@ -58,8 +58,8 @@  #include "sd.h"  #include "scsi_logging.h" -#define SCSI_DEBUG_VERSION "1.81" -static const char * scsi_debug_version_date = "20070104"; +#define SCSI_DEBUG_VERSION "1.82" +static const char * scsi_debug_version_date = "20100324";  /* Additional Sense Code (ASC) */  #define NO_ADDITIONAL_SENSE 0x0 @@ -108,6 +108,7 @@ static const char * scsi_debug_version_date = "20070104";  #define DEF_ATO 1  #define DEF_PHYSBLK_EXP 0  #define DEF_LOWEST_ALIGNED 0 +#define DEF_OPT_BLKS 64  #define DEF_UNMAP_MAX_BLOCKS 0  #define DEF_UNMAP_MAX_DESC 0  #define DEF_UNMAP_GRANULARITY 0 @@ -147,12 +148,18 @@ static const char * scsi_debug_version_date = "20070104";  #define SAM2_LUN_ADDRESS_METHOD 0  #define SAM2_WLUN_REPORT_LUNS 0xc101 +/* Can queue up to this number of commands. Typically commands that + * that have a non-zero delay are queued. */ +#define SCSI_DEBUG_CANQUEUE  255 +  static int scsi_debug_add_host = DEF_NUM_HOST;  static int scsi_debug_delay = DEF_DELAY;  static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;  static int scsi_debug_every_nth = DEF_EVERY_NTH;  static int scsi_debug_max_luns = DEF_MAX_LUNS; +static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;  static int scsi_debug_num_parts = DEF_NUM_PARTS; +static int scsi_debug_no_uld = 0;  static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */  static int scsi_debug_opts = DEF_OPTS;  static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; @@ -169,6 +176,7 @@ static int scsi_debug_guard = DEF_GUARD;  static int scsi_debug_ato = DEF_ATO;  static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;  static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; +static int scsi_debug_opt_blks = DEF_OPT_BLKS;  static int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;  static int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;  static int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; @@ -192,7 +200,6 @@ static int sdebug_sectors_per;		/* sectors per cylinder */  #define SDEBUG_SENSE_LEN 32 -#define SCSI_DEBUG_CANQUEUE  255  #define SCSI_DEBUG_MAX_CMD_LEN 32  struct sdebug_dev_info { @@ -699,9 +706,13 @@ static int inquiry_evpd_b0(unsigned char * arr)  	unsigned int gran;  	memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); + +	/* Optimal transfer length granularity */  	gran = 1 << scsi_debug_physblk_exp;  	arr[2] = (gran >> 8) & 0xff;  	arr[3] = gran & 0xff; + +	/* Maximum Transfer Length */  	if (sdebug_store_sectors > 0x400) {  		arr[4] = (sdebug_store_sectors >> 24) & 0xff;  		arr[5] = (sdebug_store_sectors >> 16) & 0xff; @@ -709,6 +720,9 @@ static int inquiry_evpd_b0(unsigned char * arr)  		arr[7] = sdebug_store_sectors & 0xff;  	} +	/* Optimal Transfer Length */ +	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); +  	if (scsi_debug_unmap_max_desc) {  		unsigned int blocks; @@ -717,15 +731,20 @@ static int inquiry_evpd_b0(unsigned char * arr)  		else  			blocks = 0xffffffff; +		/* Maximum Unmap LBA Count */  		put_unaligned_be32(blocks, &arr[16]); + +		/* Maximum Unmap Block Descriptor Count */  		put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);  	} +	/* Unmap Granularity Alignment */  	if (scsi_debug_unmap_alignment) {  		put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);  		arr[28] |= 0x80; /* UGAVALID */  	} +	/* Optimal Unmap Granularity */  	if (scsi_debug_unmap_granularity) {  		put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);  		return 0x3c; /* Mandatory page length for thin provisioning */ @@ -2266,7 +2285,7 @@ static void timer_intr_handler(unsigned long indx)  	struct sdebug_queued_cmd * sqcp;  	unsigned long iflags; -	if (indx >= SCSI_DEBUG_CANQUEUE) { +	if (indx >= scsi_debug_max_queue) {  		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "  		       "large\n");  		return; @@ -2380,6 +2399,8 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp)  		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,  					sdp->host->cmd_per_lun);  	blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); +	if (scsi_debug_no_uld) +		sdp->no_uld_attach = 1;  	return 0;  } @@ -2406,7 +2427,7 @@ static int stop_queued_cmnd(struct scsi_cmnd *cmnd)  	struct sdebug_queued_cmd *sqcp;  	spin_lock_irqsave(&queued_arr_lock, iflags); -	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { +	for (k = 0; k < scsi_debug_max_queue; ++k) {  		sqcp = &queued_arr[k];  		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {  			del_timer_sync(&sqcp->cmnd_timer); @@ -2416,7 +2437,7 @@ static int stop_queued_cmnd(struct scsi_cmnd *cmnd)  		}  	}  	spin_unlock_irqrestore(&queued_arr_lock, iflags); -	return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0; +	return (k < scsi_debug_max_queue) ? 1 : 0;  }  /* Deletes (stops) timers of all queued commands */ @@ -2427,7 +2448,7 @@ static void stop_all_queued(void)  	struct sdebug_queued_cmd *sqcp;  	spin_lock_irqsave(&queued_arr_lock, iflags); -	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { +	for (k = 0; k < scsi_debug_max_queue; ++k) {  		sqcp = &queued_arr[k];  		if (sqcp->in_use && sqcp->a_cmnd) {  			del_timer_sync(&sqcp->cmnd_timer); @@ -2533,7 +2554,7 @@ static void __init init_all_queued(void)  	struct sdebug_queued_cmd * sqcp;  	spin_lock_irqsave(&queued_arr_lock, iflags); -	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { +	for (k = 0; k < scsi_debug_max_queue; ++k) {  		sqcp = &queued_arr[k];  		init_timer(&sqcp->cmnd_timer);  		sqcp->in_use = 0; @@ -2625,12 +2646,12 @@ static int schedule_resp(struct scsi_cmnd * cmnd,  		struct sdebug_queued_cmd * sqcp = NULL;  		spin_lock_irqsave(&queued_arr_lock, iflags); -		for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { +		for (k = 0; k < scsi_debug_max_queue; ++k) {  			sqcp = &queued_arr[k];  			if (! sqcp->in_use)  				break;  		} -		if (k >= SCSI_DEBUG_CANQUEUE) { +		if (k >= scsi_debug_max_queue) {  			spin_unlock_irqrestore(&queued_arr_lock, iflags);  			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");  			return 1;	/* report busy to mid level */ @@ -2662,7 +2683,9 @@ module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);  module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);  module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);  module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); +module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);  module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); +module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);  module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);  module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);  module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); @@ -2677,6 +2700,7 @@ module_param_named(dif, scsi_debug_dif, int, S_IRUGO);  module_param_named(guard, scsi_debug_guard, int, S_IRUGO);  module_param_named(ato, scsi_debug_ato, int, S_IRUGO);  module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); +module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);  module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);  module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);  module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); @@ -2695,7 +2719,9 @@ MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");  MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");  MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");  MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); +MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");  MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); +MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");  MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");  MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");  MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); @@ -2705,6 +2731,7 @@ MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)")  MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");  MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");  MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); +MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");  MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");  MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");  MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); @@ -2970,6 +2997,31 @@ static ssize_t sdebug_max_luns_store(struct device_driver * ddp,  DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,  	    sdebug_max_luns_store); +static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf) +{ +        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue); +} +static ssize_t sdebug_max_queue_store(struct device_driver * ddp, +				      const char * buf, size_t count) +{ +        int n; + +	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && +	    (n <= SCSI_DEBUG_CANQUEUE)) { +		scsi_debug_max_queue = n; +		return count; +	} +	return -EINVAL; +} +DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show, +	    sdebug_max_queue_store); + +static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf) +{ +        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld); +} +DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL); +  static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); @@ -3107,7 +3159,9 @@ static int do_create_driverfs_files(void)  	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);  	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);  	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); +	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);  	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); +	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);  	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);  	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);  	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); @@ -3139,7 +3193,9 @@ static void do_remove_driverfs_files(void)  	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);  	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);  	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); +	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);  	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); +	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);  	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);  	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);  	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); @@ -3830,12 +3886,13 @@ static int sdebug_driver_probe(struct device * dev)  	sdbg_host = to_sdebug_host(dev); -        hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); -        if (NULL == hpnt) { -                printk(KERN_ERR "%s: scsi_register failed\n", __func__); -                error = -ENODEV; +	sdebug_driver_template.can_queue = scsi_debug_max_queue; +	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); +	if (NULL == hpnt) { +		printk(KERN_ERR "%s: scsi_register failed\n", __func__); +		error = -ENODEV;  		return error; -        } +	}          sdbg_host->shost = hpnt;  	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 7ad53fa4276..a5d630f5f51 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -39,6 +39,8 @@  #include "scsi_logging.h"  #include "scsi_transport_api.h" +#include <trace/events/scsi.h> +  #define SENSE_TIMEOUT		(10*HZ)  /* @@ -52,6 +54,7 @@  void scsi_eh_wakeup(struct Scsi_Host *shost)  {  	if (shost->host_busy == shost->host_failed) { +		trace_scsi_eh_wakeup(shost);  		wake_up_process(shost->ehandler);  		SCSI_LOG_ERROR_RECOVERY(5,  				printk("Waking error handler thread\n")); @@ -127,6 +130,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)  	struct scsi_cmnd *scmd = req->special;  	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED; +	trace_scsi_dispatch_cmd_timeout(scmd);  	scsi_log_completion(scmd, TIMEOUT_ERROR);  	if (scmd->device->host->transportt->eh_timed_out) @@ -970,9 +974,10 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,  						  "0x%p\n", current->comm,  						  scmd));  		rtn = scsi_try_to_abort_cmd(scmd); -		if (rtn == SUCCESS) { +		if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {  			scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD;  			if (!scsi_device_online(scmd->device) || +			    rtn == FAST_IO_FAIL ||  			    !scsi_eh_tur(scmd)) {  				scsi_eh_finish_cmd(scmd, done_q);  			} @@ -1099,8 +1104,9 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,  						  " 0x%p\n", current->comm,  						  sdev));  		rtn = scsi_try_bus_device_reset(bdr_scmd); -		if (rtn == SUCCESS) { +		if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {  			if (!scsi_device_online(sdev) || +			    rtn == FAST_IO_FAIL ||  			    !scsi_eh_tur(bdr_scmd)) {  				list_for_each_entry_safe(scmd, next,  							 work_q, eh_entry) { @@ -1163,10 +1169,11 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,  						  "to target %d\n",  						  current->comm, id));  		rtn = scsi_try_target_reset(tgtr_scmd); -		if (rtn == SUCCESS) { +		if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {  			list_for_each_entry_safe(scmd, next, work_q, eh_entry) {  				if (id == scmd_id(scmd))  					if (!scsi_device_online(scmd->device) || +					    rtn == FAST_IO_FAIL ||  					    !scsi_eh_tur(tgtr_scmd))  						scsi_eh_finish_cmd(scmd,  								   done_q); @@ -1222,10 +1229,11 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,  						  " %d\n", current->comm,  						  channel));  		rtn = scsi_try_bus_reset(chan_scmd); -		if (rtn == SUCCESS) { +		if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {  			list_for_each_entry_safe(scmd, next, work_q, eh_entry) {  				if (channel == scmd_channel(scmd))  					if (!scsi_device_online(scmd->device) || +					    rtn == FAST_IO_FAIL ||  					    !scsi_eh_tur(scmd))  						scsi_eh_finish_cmd(scmd,  								   done_q); @@ -1259,9 +1267,10 @@ static int scsi_eh_host_reset(struct list_head *work_q,  						  , current->comm));  		rtn = scsi_try_host_reset(scmd); -		if (rtn == SUCCESS) { +		if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {  			list_for_each_entry_safe(scmd, next, work_q, eh_entry) {  				if (!scsi_device_online(scmd->device) || +				    rtn == FAST_IO_FAIL ||  				    (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) ||  				    !scsi_eh_tur(scmd))  					scsi_eh_finish_cmd(scmd, done_q); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 38518b08807..c992ecf4e37 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -459,8 +459,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,  	found_target->reap_ref++;  	spin_unlock_irqrestore(shost->host_lock, flags);  	if (found_target->state != STARGET_DEL) { -		put_device(parent); -		kfree(starget); +		put_device(dev);  		return found_target;  	}  	/* Unfortunately, we found a dying target; need to diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 429c9b73e3e..c23ab978c3b 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -474,7 +474,7 @@ static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL);  /* - * sdev_rd_attr: create a function and attribute variable for a + * sdev_rw_attr: create a function and attribute variable for a   * read/write field.   */  #define sdev_rw_attr(field, format_string)				\ @@ -486,7 +486,7 @@ sdev_store_##field (struct device *dev, struct device_attribute *attr,	\  {									\  	struct scsi_device *sdev;					\  	sdev = to_scsi_device(dev);					\ -	snscanf (buf, 20, format_string, &sdev->field);			\ +	sscanf (buf, format_string, &sdev->field);			\  	return count;							\  }									\  static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field); @@ -853,9 +853,6 @@ static int scsi_target_add(struct scsi_target *starget)  	error = device_add(&starget->dev);  	if (error) {  		dev_err(&starget->dev, "target device_add failed, error %d\n", error); -		get_device(&starget->dev); -		scsi_target_reap(starget); -		put_device(&starget->dev);  		return error;  	}  	transport_add_device(&starget->dev); diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c new file mode 100644 index 00000000000..b587289cfac --- /dev/null +++ b/drivers/scsi/scsi_trace.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2010 FUJITSU LIMITED + * Copyright (C) 2010 Tomohiro Kusumi <kusumi.tomohiro@jp.fujitsu.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + */ +#include <linux/kernel.h> +#include <linux/trace_seq.h> +#include <trace/events/scsi.h> + +#define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) +#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) + +static const char * +scsi_trace_misc(struct trace_seq *, unsigned char *, int); + +static const char * +scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) +{ +	const char *ret = p->buffer + p->len; +	sector_t lba = 0, txlen = 0; + +	lba |= ((cdb[1] & 0x1F) << 16); +	lba |=  (cdb[2] << 8); +	lba |=   cdb[3]; +	txlen = cdb[4]; + +	trace_seq_printf(p, "lba=%llu txlen=%llu", +			 (unsigned long long)lba, (unsigned long long)txlen); +	trace_seq_putc(p, 0); + +	return ret; +} + +static const char * +scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) +{ +	const char *ret = p->buffer + p->len; +	sector_t lba = 0, txlen = 0; + +	lba |= (cdb[2] << 24); +	lba |= (cdb[3] << 16); +	lba |= (cdb[4] << 8); +	lba |=  cdb[5]; +	txlen |= (cdb[7] << 8); +	txlen |=  cdb[8]; + +	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", +			 (unsigned long long)lba, (unsigned long long)txlen, +			 cdb[1] >> 5); +	trace_seq_putc(p, 0); + +	return ret; +} + +static const char * +scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) +{ +	const char *ret = p->buffer + p->len; +	sector_t lba = 0, txlen = 0; + +	lba |= (cdb[2] << 24); +	lba |= (cdb[3] << 16); +	lba |= (cdb[4] << 8); +	lba |=  cdb[5]; +	txlen |= (cdb[6] << 24); +	txlen |= (cdb[7] << 16); +	txlen |= (cdb[8] << 8); +	txlen |=  cdb[9]; + +	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", +			 (unsigned long long)lba, (unsigned long long)txlen, +			 cdb[1] >> 5); +	trace_seq_putc(p, 0); + +	return ret; +} + +static const char * +scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) +{ +	const char *ret = p->buffer + p->len; +	sector_t lba = 0, txlen = 0; + +	lba |= ((u64)cdb[2] << 56); +	lba |= ((u64)cdb[3] << 48); +	lba |= ((u64)cdb[4] << 40); +	lba |= ((u64)cdb[5] << 32); +	lba |= (cdb[6] << 24); +	lba |= (cdb[7] << 16); +	lba |= (cdb[8] << 8); +	lba |=  cdb[9]; +	txlen |= (cdb[10] << 24); +	txlen |= (cdb[11] << 16); +	txlen |= (cdb[12] << 8); +	txlen |=  cdb[13]; + +	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", +			 (unsigned long long)lba, (unsigned long long)txlen, +			 cdb[1] >> 5); + +	if (cdb[0] == WRITE_SAME_16) +		trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); + +	trace_seq_putc(p, 0); + +	return ret; +} + +static const char * +scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) +{ +	const char *ret = p->buffer + p->len, *cmd; +	sector_t lba = 0, txlen = 0; +	u32 ei_lbrt = 0; + +	switch (SERVICE_ACTION32(cdb)) { +	case READ_32: +		cmd = "READ"; +		break; +	case VERIFY_32: +		cmd = "VERIFY"; +		break; +	case WRITE_32: +		cmd = "WRITE"; +		break; +	case WRITE_SAME_32: +		cmd = "WRITE_SAME"; +		break; +	default: +		trace_seq_printf(p, "UNKNOWN"); +		goto out; +	} + +	lba |= ((u64)cdb[12] << 56); +	lba |= ((u64)cdb[13] << 48); +	lba |= ((u64)cdb[14] << 40); +	lba |= ((u64)cdb[15] << 32); +	lba |= (cdb[16] << 24); +	lba |= (cdb[17] << 16); +	lba |= (cdb[18] << 8); +	lba |=  cdb[19]; +	ei_lbrt |= (cdb[20] << 24); +	ei_lbrt |= (cdb[21] << 16); +	ei_lbrt |= (cdb[22] << 8); +	ei_lbrt |=  cdb[23]; +	txlen |= (cdb[28] << 24); +	txlen |= (cdb[29] << 16); +	txlen |= (cdb[30] << 8); +	txlen |=  cdb[31]; + +	trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", +			 cmd, (unsigned long long)lba, +			 (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); + +	if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) +		trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); + +out: +	trace_seq_putc(p, 0); + +	return ret; +} + +static const char * +scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) +{ +	const char *ret = p->buffer + p->len; +	unsigned int regions = cdb[7] << 8 | cdb[8]; + +	trace_seq_printf(p, "regions=%u", (regions - 8) / 16); +	trace_seq_putc(p, 0); + +	return ret; +} + +static const char * +scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) +{ +	const char *ret = p->buffer + p->len, *cmd; +	sector_t lba = 0; +	u32 alloc_len = 0; + +	switch (SERVICE_ACTION16(cdb)) { +	case SAI_READ_CAPACITY_16: +		cmd = "READ_CAPACITY_16"; +		break; +	case SAI_GET_LBA_STATUS: +		cmd = "GET_LBA_STATUS"; +		break; +	default: +		trace_seq_printf(p, "UNKNOWN"); +		goto out; +	} + +	lba |= ((u64)cdb[2] << 56); +	lba |= ((u64)cdb[3] << 48); +	lba |= ((u64)cdb[4] << 40); +	lba |= ((u64)cdb[5] << 32); +	lba |= (cdb[6] << 24); +	lba |= (cdb[7] << 16); +	lba |= (cdb[8] << 8); +	lba |=  cdb[9]; +	alloc_len |= (cdb[10] << 24); +	alloc_len |= (cdb[11] << 16); +	alloc_len |= (cdb[12] << 8); +	alloc_len |=  cdb[13]; + +	trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, +			 (unsigned long long)lba, alloc_len); + +out: +	trace_seq_putc(p, 0); + +	return ret; +} + +static const char * +scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) +{ +	switch (SERVICE_ACTION32(cdb)) { +	case READ_32: +	case VERIFY_32: +	case WRITE_32: +	case WRITE_SAME_32: +		return scsi_trace_rw32(p, cdb, len); +	default: +		return scsi_trace_misc(p, cdb, len); +	} +} + +static const char * +scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len) +{ +	const char *ret = p->buffer + p->len; + +	trace_seq_printf(p, "-"); +	trace_seq_putc(p, 0); + +	return ret; +} + +const char * +scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len) +{ +	switch (cdb[0]) { +	case READ_6: +	case WRITE_6: +		return scsi_trace_rw6(p, cdb, len); +	case READ_10: +	case VERIFY: +	case WRITE_10: +	case WRITE_SAME: +		return scsi_trace_rw10(p, cdb, len); +	case READ_12: +	case VERIFY_12: +	case WRITE_12: +		return scsi_trace_rw12(p, cdb, len); +	case READ_16: +	case VERIFY_16: +	case WRITE_16: +	case WRITE_SAME_16: +		return scsi_trace_rw16(p, cdb, len); +	case UNMAP: +		return scsi_trace_unmap(p, cdb, len); +	case SERVICE_ACTION_IN: +		return scsi_trace_service_action_in(p, cdb, len); +	case VARIABLE_LENGTH_CMD: +		return scsi_trace_varlen(p, cdb, len); +	default: +		return scsi_trace_misc(p, cdb, len); +	} +} diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 6cfffc88022..06813789145 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -834,7 +834,7 @@ static ssize_t  store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr,  			    const char *buf, size_t count)  { -	int val; +	unsigned long val;  	struct fc_rport *rport = transport_class_to_rport(dev);  	struct Scsi_Host *shost = rport_to_shost(rport);  	struct fc_internal *i = to_fc_internal(shost->transportt); @@ -848,6 +848,12 @@ store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr,  		return -EINVAL;  	/* +	 * Check for overflow; dev_loss_tmo is u32 +	 */ +	if (val > UINT_MAX) +		return -EINVAL; + +	/*  	 * If fast_io_fail is off we have to cap  	 * dev_loss_tmo at SCSI_DEVICE_BLOCK_MAX_TIMEOUT  	 */ @@ -2865,7 +2871,7 @@ void  fc_remote_port_delete(struct fc_rport  *rport)  {  	struct Scsi_Host *shost = rport_to_shost(rport); -	int timeout = rport->dev_loss_tmo; +	unsigned long timeout = rport->dev_loss_tmo;  	unsigned long flags;  	/* @@ -3191,23 +3197,33 @@ fc_scsi_scan_rport(struct work_struct *work)   *   * This routine can be called from a FC LLD scsi_eh callback. It   * blocks the scsi_eh thread until the fc_rport leaves the - * FC_PORTSTATE_BLOCKED. This is necessary to avoid the scsi_eh - * failing recovery actions for blocked rports which would lead to - * offlined SCSI devices. + * FC_PORTSTATE_BLOCKED, or the fast_io_fail_tmo fires. This is + * necessary to avoid the scsi_eh failing recovery actions for blocked + * rports which would lead to offlined SCSI devices. + * + * Returns: 0 if the fc_rport left the state FC_PORTSTATE_BLOCKED. + *	    FAST_IO_FAIL if the fast_io_fail_tmo fired, this should be + *	    passed back to scsi_eh.   */ -void fc_block_scsi_eh(struct scsi_cmnd *cmnd) +int fc_block_scsi_eh(struct scsi_cmnd *cmnd)  {  	struct Scsi_Host *shost = cmnd->device->host;  	struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));  	unsigned long flags;  	spin_lock_irqsave(shost->host_lock, flags); -	while (rport->port_state == FC_PORTSTATE_BLOCKED) { +	while (rport->port_state == FC_PORTSTATE_BLOCKED && +	       !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) {  		spin_unlock_irqrestore(shost->host_lock, flags);  		msleep(1000);  		spin_lock_irqsave(shost->host_lock, flags);  	}  	spin_unlock_irqrestore(shost->host_lock, flags); + +	if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT) +		return FAST_IO_FAIL; + +	return 0;  }  EXPORT_SYMBOL(fc_block_scsi_eh); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index de6c60320f6..829cc37abc4 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1434,6 +1434,8 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,  #error RC16_LEN must not be more than SD_BUF_SIZE  #endif +#define READ_CAPACITY_RETRIES_ON_RESET	10 +  static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,  						unsigned char *buffer)  { @@ -1441,7 +1443,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,  	struct scsi_sense_hdr sshdr;  	int sense_valid = 0;  	int the_result; -	int retries = 3; +	int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;  	unsigned int alignment;  	unsigned long long lba;  	unsigned sector_size; @@ -1470,6 +1472,13 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,  				 * Invalid Field in CDB, just retry  				 * silently with RC10 */  				return -EINVAL; +			if (sense_valid && +			    sshdr.sense_key == UNIT_ATTENTION && +			    sshdr.asc == 0x29 && sshdr.ascq == 0x00) +				/* Device reset might occur several times, +				 * give it one more chance */ +				if (--reset_retries > 0) +					continue;  		}  		retries--; @@ -1528,7 +1537,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,  	struct scsi_sense_hdr sshdr;  	int sense_valid = 0;  	int the_result; -	int retries = 3; +	int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;  	sector_t lba;  	unsigned sector_size; @@ -1544,8 +1553,16 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,  		if (media_not_present(sdkp, &sshdr))  			return -ENODEV; -		if (the_result) +		if (the_result) {  			sense_valid = scsi_sense_valid(&sshdr); +			if (sense_valid && +			    sshdr.sense_key == UNIT_ATTENTION && +			    sshdr.asc == 0x29 && sshdr.ascq == 0x00) +				/* Device reset might occur several times, +				 * give it one more chance */ +				if (--reset_retries > 0) +					continue; +		}  		retries--;  	} while (the_result && retries); @@ -1574,6 +1591,8 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,  static int sd_try_rc16_first(struct scsi_device *sdp)  { +	if (sdp->host->max_cmd_len < 16) +		return 0;  	if (sdp->scsi_level > SCSI_SPC_2)  		return 1;  	if (scsi_device_protection(sdp)) diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 5fda881c247..b701bf2cc18 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -2224,14 +2224,8 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off  } -void -wd33c93_release(void) -{ -} -  EXPORT_SYMBOL(wd33c93_host_reset);  EXPORT_SYMBOL(wd33c93_init); -EXPORT_SYMBOL(wd33c93_release);  EXPORT_SYMBOL(wd33c93_abort);  EXPORT_SYMBOL(wd33c93_queuecommand);  EXPORT_SYMBOL(wd33c93_intr); diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index 00123f2383d..1ed5f3bf388 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -348,6 +348,5 @@ int wd33c93_queuecommand (struct scsi_cmnd *cmd,  void wd33c93_intr (struct Scsi_Host *instance);  int wd33c93_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);  int wd33c93_host_reset (struct scsi_cmnd *); -void wd33c93_release(void);  #endif /* WD33C93_H */ diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index c0f4b364c71..c3c5aaaae53 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -25,6 +25,9 @@ const char *ftrace_print_flags_seq(struct trace_seq *p, const char *delim,  const char *ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,  				     const struct trace_print_flags *symbol_array); +const char *ftrace_print_hex_seq(struct trace_seq *p, +				 const unsigned char *buf, int len); +  /*   * The trace entry - the most basic unit of tracing. This is what   * is printed in the end as a single line in the trace output, such as: diff --git a/include/scsi/Kbuild b/include/scsi/Kbuild index b3a0ee6b2f1..f2b94918994 100644 --- a/include/scsi/Kbuild +++ b/include/scsi/Kbuild @@ -1,4 +1,3 @@ -header-y += scsi.h  header-y += scsi_netlink.h  header-y += scsi_netlink_fc.h  header-y += scsi_bsg_fc.h diff --git a/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h index 747e2c7d88d..8e9b222251c 100644 --- a/include/scsi/fc/fc_fcp.h +++ b/include/scsi/fc/fc_fcp.h @@ -76,6 +76,7 @@ struct fcp_cmnd32 {  #define	FCP_PTA_HEADQ	    1	/* head of queue task attribute */  #define	FCP_PTA_ORDERED     2	/* ordered task attribute */  #define	FCP_PTA_ACA	    4	/* auto. contigent allegiance */ +#define	FCP_PTA_MASK	    7	/* mask for task attribute field */  #define	FCP_PRI_SHIFT	    3	/* priority field starts in bit 3 */  #define	FCP_PRI_RESVD_MASK  0x80	/* reserved bits in priority field */ diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h index 8eb0a0fc0a7..9b4867c9c2d 100644 --- a/include/scsi/fc_encode.h +++ b/include/scsi/fc_encode.h @@ -74,7 +74,7 @@ static inline void fc_adisc_fill(struct fc_lport *lport, struct fc_frame *fp)  	adisc->adisc_cmd = ELS_ADISC;  	put_unaligned_be64(lport->wwpn, &adisc->adisc_wwpn);  	put_unaligned_be64(lport->wwnn, &adisc->adisc_wwnn); -	hton24(adisc->adisc_port_id, fc_host_port_id(lport->host)); +	hton24(adisc->adisc_port_id, lport->port_id);  }  /** @@ -127,15 +127,13 @@ static inline int fc_ct_fill(struct fc_lport *lport,  	case FC_NS_RFT_ID:  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft)); -		hton24(ct->payload.rft.fid.fp_fid, -		       fc_host_port_id(lport->host)); +		hton24(ct->payload.rft.fid.fp_fid, lport->port_id);  		ct->payload.rft.fts = lport->fcts;  		break;  	case FC_NS_RFF_ID:  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rff_id)); -		hton24(ct->payload.rff.fr_fid.fp_fid, -		       fc_host_port_id(lport->host)); +		hton24(ct->payload.rff.fr_fid.fp_fid, lport->port_id);  		ct->payload.rff.fr_type = FC_TYPE_FCP;  		if (lport->service_params & FCP_SPPF_INIT_FCN)  			ct->payload.rff.fr_feat = FCP_FEAT_INIT; @@ -145,16 +143,14 @@ static inline int fc_ct_fill(struct fc_lport *lport,  	case FC_NS_RNN_ID:  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id)); -		hton24(ct->payload.rn.fr_fid.fp_fid, -		       fc_host_port_id(lport->host)); +		hton24(ct->payload.rn.fr_fid.fp_fid, lport->port_id);  		put_unaligned_be64(lport->wwnn, &ct->payload.rn.fr_wwn);  		break;  	case FC_NS_RSPN_ID:  		len = strnlen(fc_host_symbolic_name(lport->host), 255);  		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rspn) + len); -		hton24(ct->payload.spn.fr_fid.fp_fid, -		       fc_host_port_id(lport->host)); +		hton24(ct->payload.spn.fr_fid.fp_fid, lport->port_id);  		strncpy(ct->payload.spn.fr_name,  			fc_host_symbolic_name(lport->host), len);  		ct->payload.spn.fr_name_len = len; @@ -268,7 +264,7 @@ static inline void fc_logo_fill(struct fc_lport *lport, struct fc_frame *fp)  	logo = fc_frame_payload_get(fp, sizeof(*logo));  	memset(logo, 0, sizeof(*logo));  	logo->fl_cmd = ELS_LOGO; -	hton24(logo->fl_n_port_id, fc_host_port_id(lport->host)); +	hton24(logo->fl_n_port_id, lport->port_id);  	logo->fl_n_port_wwn = htonll(lport->wwpn);  } @@ -295,7 +291,7 @@ static inline void fc_rec_fill(struct fc_lport *lport, struct fc_frame *fp)  	rec = fc_frame_payload_get(fp, sizeof(*rec));  	memset(rec, 0, sizeof(*rec));  	rec->rec_cmd = ELS_REC; -	hton24(rec->rec_s_id, fc_host_port_id(lport->host)); +	hton24(rec->rec_s_id, lport->port_id);  	rec->rec_ox_id = htons(ep->oxid);  	rec->rec_rx_id = htons(ep->rxid);  } diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 4b912eee33e..7495c0ba67e 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -47,13 +47,18 @@  #define ntohll(x) be64_to_cpu(x)  #define htonll(x) cpu_to_be64(x) -#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2])) -#define hton24(p, v)	do {			\ -		p[0] = (((v) >> 16) & 0xFF);	\ -		p[1] = (((v) >> 8) & 0xFF);	\ -		p[2] = ((v) & 0xFF);		\ -	} while (0) +static inline u32 ntoh24(const u8 *p) +{ +	return (p[0] << 16) | (p[1] << 8) | p[2]; +} + +static inline void hton24(u8 *p, u32 v) +{ +	p[0] = (v >> 16) & 0xff; +	p[1] = (v >> 8) & 0xff; +	p[2] = v & 0xff; +}  /**   * enum fc_lport_state - Local port states @@ -775,6 +780,7 @@ struct fc_disc {   * @dev_stats:             FCoE device stats (TODO: libfc should not be   *                         FCoE aware)   * @retry_count:           Number of retries in the current state + * @port_id:               FC Port ID   * @wwpn:                  World Wide Port Name   * @wwnn:                  World Wide Node Name   * @service_params:        Common service parameters @@ -821,6 +827,7 @@ struct fc_lport {  	u8			       retry_count;  	/* Fabric information */ +	u32                            port_id;  	u64			       wwpn;  	u64			       wwnn;  	unsigned int		       service_params; @@ -918,15 +925,6 @@ static inline void fc_lport_free_stats(struct fc_lport *lport)  }  /** - * fc_lport_get_stats() - Get a local port's statistics - * @lport: The local port whose statistics are to be retreived - */ -static inline struct fcoe_dev_stats *fc_lport_get_stats(struct fc_lport *lport) -{ -	return per_cpu_ptr(lport->dev_stats, smp_processor_id()); -} - -/**   * lport_priv() - Return the private data from a local port   * @lport: The local port whose private data is to be retreived   */ @@ -1053,7 +1051,6 @@ void fc_exch_mgr_reset(struct fc_lport *, u32 s_id, u32 d_id);   * Functions for fc_functions_template   */  void fc_get_host_speed(struct Scsi_Host *); -void fc_get_host_port_type(struct Scsi_Host *);  void fc_get_host_port_state(struct Scsi_Host *);  void fc_set_rport_loss_tmo(struct fc_rport *, u32 timeout);  struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *); diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index c603f4a7e7f..ec13f51531f 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -29,6 +29,8 @@  #include <scsi/fc/fc_fcoe.h>  #include <scsi/libfc.h> +#define FCOE_MAX_CMD_LEN	16	/* Supported CDB length */ +  /*   * FIP tunable parameters.   */ @@ -65,14 +67,12 @@ enum fip_state {   * @port_ka_time:  time of next port keep-alive.   * @ctlr_ka_time:  time of next controller keep-alive.   * @timer:	   timer struct used for all delayed events. - * @link_work:	   &work_struct for doing FCF selection. + * @timer_work:	   &work_struct for doing keep-alives and resets.   * @recv_work:	   &work_struct for receiving FIP frames.   * @fip_recv_list: list of received FIP frames.   * @user_mfs:	   configured maximum FC frame size, including FC header.   * @flogi_oxid:    exchange ID of most recent fabric login.   * @flogi_count:   number of FLOGI attempts in AUTO mode. - * @link:	   current link status for libfc. - * @last_link:	   last link state reported to libfc.   * @map_dest:	   use the FC_MAP mode for destination MAC addresses.   * @spma:	   supports SPMA server-provided MACs mode   * @send_ctlr_ka:  need to send controller keep alive @@ -100,14 +100,12 @@ struct fcoe_ctlr {  	unsigned long port_ka_time;  	unsigned long ctlr_ka_time;  	struct timer_list timer; -	struct work_struct link_work; +	struct work_struct timer_work;  	struct work_struct recv_work;  	struct sk_buff_head fip_recv_list;  	u16 user_mfs;  	u16 flogi_oxid;  	u8 flogi_count; -	u8 link; -	u8 last_link;  	u8 reset_req;  	u8 map_dest;  	u8 spma; diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 8b4deca996a..9ae5c613131 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -114,6 +114,7 @@ struct scsi_cmnd;  #define READ_12               0xa8  #define WRITE_12              0xaa  #define WRITE_VERIFY_12       0xae +#define VERIFY_12	      0xaf  #define SEARCH_HIGH_12        0xb0  #define SEARCH_EQUAL_12       0xb1  #define SEARCH_LOW_12         0xb2 @@ -134,6 +135,7 @@ struct scsi_cmnd;  #define MO_SET_TARGET_PGS     0x0a  /* values for variable length command */  #define READ_32		      0x09 +#define VERIFY_32	      0x0a  #define WRITE_32	      0x0b  #define WRITE_SAME_32	      0x0d @@ -423,6 +425,7 @@ static inline int scsi_is_wlun(unsigned int lun)  #define ADD_TO_MLQUEUE  0x2006  #define TIMEOUT_ERROR   0x2007  #define SCSI_RETURN_NOT_HANDLED   0x2008 +#define FAST_IO_FAIL	0x2009  /*   * Midlevel queue return values. diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 8e86a94faf0..87d81b3ce56 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -807,6 +807,6 @@ void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,  struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel,  		struct fc_vport_identifiers *);  int fc_vport_terminate(struct fc_vport *vport); -void fc_block_scsi_eh(struct scsi_cmnd *cmnd); +int fc_block_scsi_eh(struct scsi_cmnd *cmnd);  #endif /* SCSI_TRANSPORT_FC_H */ diff --git a/include/trace/events/scsi.h b/include/trace/events/scsi.h new file mode 100644 index 00000000000..25fbefdf2f2 --- /dev/null +++ b/include/trace/events/scsi.h @@ -0,0 +1,345 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM scsi + +#if !defined(_TRACE_SCSI_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_SCSI_H + +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_host.h> +#include <linux/tracepoint.h> +#include <linux/trace_seq.h> + +#define scsi_opcode_name(opcode)	{ opcode, #opcode } +#define show_opcode_name(val)					\ +	__print_symbolic(val,					\ +		scsi_opcode_name(TEST_UNIT_READY),		\ +		scsi_opcode_name(REZERO_UNIT),			\ +		scsi_opcode_name(REQUEST_SENSE),		\ +		scsi_opcode_name(FORMAT_UNIT),			\ +		scsi_opcode_name(READ_BLOCK_LIMITS),		\ +		scsi_opcode_name(REASSIGN_BLOCKS),		\ +		scsi_opcode_name(INITIALIZE_ELEMENT_STATUS),	\ +		scsi_opcode_name(READ_6),			\ +		scsi_opcode_name(WRITE_6),			\ +		scsi_opcode_name(SEEK_6),			\ +		scsi_opcode_name(READ_REVERSE),			\ +		scsi_opcode_name(WRITE_FILEMARKS),		\ +		scsi_opcode_name(SPACE),			\ +		scsi_opcode_name(INQUIRY),			\ +		scsi_opcode_name(RECOVER_BUFFERED_DATA),	\ +		scsi_opcode_name(MODE_SELECT),			\ +		scsi_opcode_name(RESERVE),			\ +		scsi_opcode_name(RELEASE),			\ +		scsi_opcode_name(COPY),				\ +		scsi_opcode_name(ERASE),			\ +		scsi_opcode_name(MODE_SENSE),			\ +		scsi_opcode_name(START_STOP),			\ +		scsi_opcode_name(RECEIVE_DIAGNOSTIC),		\ +		scsi_opcode_name(SEND_DIAGNOSTIC),		\ +		scsi_opcode_name(ALLOW_MEDIUM_REMOVAL),		\ +		scsi_opcode_name(SET_WINDOW),			\ +		scsi_opcode_name(READ_CAPACITY),		\ +		scsi_opcode_name(READ_10),			\ +		scsi_opcode_name(WRITE_10),			\ +		scsi_opcode_name(SEEK_10),			\ +		scsi_opcode_name(POSITION_TO_ELEMENT),		\ +		scsi_opcode_name(WRITE_VERIFY),			\ +		scsi_opcode_name(VERIFY),			\ +		scsi_opcode_name(SEARCH_HIGH),			\ +		scsi_opcode_name(SEARCH_EQUAL),			\ +		scsi_opcode_name(SEARCH_LOW),			\ +		scsi_opcode_name(SET_LIMITS),			\ +		scsi_opcode_name(PRE_FETCH),			\ +		scsi_opcode_name(READ_POSITION),		\ +		scsi_opcode_name(SYNCHRONIZE_CACHE),		\ +		scsi_opcode_name(LOCK_UNLOCK_CACHE),		\ +		scsi_opcode_name(READ_DEFECT_DATA),		\ +		scsi_opcode_name(MEDIUM_SCAN),			\ +		scsi_opcode_name(COMPARE),			\ +		scsi_opcode_name(COPY_VERIFY),			\ +		scsi_opcode_name(WRITE_BUFFER),			\ +		scsi_opcode_name(READ_BUFFER),			\ +		scsi_opcode_name(UPDATE_BLOCK),			\ +		scsi_opcode_name(READ_LONG),			\ +		scsi_opcode_name(WRITE_LONG),			\ +		scsi_opcode_name(CHANGE_DEFINITION),		\ +		scsi_opcode_name(WRITE_SAME),			\ +		scsi_opcode_name(UNMAP),			\ +		scsi_opcode_name(READ_TOC),			\ +		scsi_opcode_name(LOG_SELECT),			\ +		scsi_opcode_name(LOG_SENSE),			\ +		scsi_opcode_name(XDWRITEREAD_10),		\ +		scsi_opcode_name(MODE_SELECT_10),		\ +		scsi_opcode_name(RESERVE_10),			\ +		scsi_opcode_name(RELEASE_10),			\ +		scsi_opcode_name(MODE_SENSE_10),		\ +		scsi_opcode_name(PERSISTENT_RESERVE_IN),	\ +		scsi_opcode_name(PERSISTENT_RESERVE_OUT),	\ +		scsi_opcode_name(VARIABLE_LENGTH_CMD),		\ +		scsi_opcode_name(REPORT_LUNS),			\ +		scsi_opcode_name(MAINTENANCE_IN),		\ +		scsi_opcode_name(MAINTENANCE_OUT),		\ +		scsi_opcode_name(MOVE_MEDIUM),			\ +		scsi_opcode_name(EXCHANGE_MEDIUM),		\ +		scsi_opcode_name(READ_12),			\ +		scsi_opcode_name(WRITE_12),			\ +		scsi_opcode_name(WRITE_VERIFY_12),		\ +		scsi_opcode_name(SEARCH_HIGH_12),		\ +		scsi_opcode_name(SEARCH_EQUAL_12),		\ +		scsi_opcode_name(SEARCH_LOW_12),		\ +		scsi_opcode_name(READ_ELEMENT_STATUS),		\ +		scsi_opcode_name(SEND_VOLUME_TAG),		\ +		scsi_opcode_name(WRITE_LONG_2),			\ +		scsi_opcode_name(READ_16),			\ +		scsi_opcode_name(WRITE_16),			\ +		scsi_opcode_name(VERIFY_16),			\ +		scsi_opcode_name(WRITE_SAME_16),		\ +		scsi_opcode_name(SERVICE_ACTION_IN),		\ +		scsi_opcode_name(SAI_READ_CAPACITY_16),		\ +		scsi_opcode_name(SAI_GET_LBA_STATUS),		\ +		scsi_opcode_name(MI_REPORT_TARGET_PGS),		\ +		scsi_opcode_name(MO_SET_TARGET_PGS),		\ +		scsi_opcode_name(READ_32),			\ +		scsi_opcode_name(WRITE_32),			\ +		scsi_opcode_name(WRITE_SAME_32),		\ +		scsi_opcode_name(ATA_16),			\ +		scsi_opcode_name(ATA_12)) + +#define scsi_hostbyte_name(result)	{ result, #result } +#define show_hostbyte_name(val)					\ +	__print_symbolic(val,					\ +		scsi_hostbyte_name(DID_OK),			\ +		scsi_hostbyte_name(DID_NO_CONNECT),		\ +		scsi_hostbyte_name(DID_BUS_BUSY),		\ +		scsi_hostbyte_name(DID_TIME_OUT),		\ +		scsi_hostbyte_name(DID_BAD_TARGET),		\ +		scsi_hostbyte_name(DID_ABORT),			\ +		scsi_hostbyte_name(DID_PARITY),			\ +		scsi_hostbyte_name(DID_ERROR),			\ +		scsi_hostbyte_name(DID_RESET),			\ +		scsi_hostbyte_name(DID_BAD_INTR),		\ +		scsi_hostbyte_name(DID_PASSTHROUGH),		\ +		scsi_hostbyte_name(DID_SOFT_ERROR),		\ +		scsi_hostbyte_name(DID_IMM_RETRY),		\ +		scsi_hostbyte_name(DID_REQUEUE),		\ +		scsi_hostbyte_name(DID_TRANSPORT_DISRUPTED),	\ +		scsi_hostbyte_name(DID_TRANSPORT_FAILFAST)) + +#define scsi_driverbyte_name(result)	{ result, #result } +#define show_driverbyte_name(val)				\ +	__print_symbolic(val,					\ +		scsi_driverbyte_name(DRIVER_OK),		\ +		scsi_driverbyte_name(DRIVER_BUSY),		\ +		scsi_driverbyte_name(DRIVER_SOFT),		\ +		scsi_driverbyte_name(DRIVER_MEDIA),		\ +		scsi_driverbyte_name(DRIVER_ERROR),		\ +		scsi_driverbyte_name(DRIVER_INVALID),		\ +		scsi_driverbyte_name(DRIVER_TIMEOUT),		\ +		scsi_driverbyte_name(DRIVER_HARD),		\ +		scsi_driverbyte_name(DRIVER_SENSE)) + +#define scsi_msgbyte_name(result)	{ result, #result } +#define show_msgbyte_name(val)					\ +	__print_symbolic(val,					\ +		scsi_msgbyte_name(COMMAND_COMPLETE),		\ +		scsi_msgbyte_name(EXTENDED_MESSAGE),		\ +		scsi_msgbyte_name(SAVE_POINTERS),		\ +		scsi_msgbyte_name(RESTORE_POINTERS),		\ +		scsi_msgbyte_name(DISCONNECT),			\ +		scsi_msgbyte_name(INITIATOR_ERROR),		\ +		scsi_msgbyte_name(ABORT_TASK_SET),		\ +		scsi_msgbyte_name(MESSAGE_REJECT),		\ +		scsi_msgbyte_name(NOP),				\ +		scsi_msgbyte_name(MSG_PARITY_ERROR),		\ +		scsi_msgbyte_name(LINKED_CMD_COMPLETE),		\ +		scsi_msgbyte_name(LINKED_FLG_CMD_COMPLETE),	\ +		scsi_msgbyte_name(TARGET_RESET),		\ +		scsi_msgbyte_name(ABORT_TASK),			\ +		scsi_msgbyte_name(CLEAR_TASK_SET),		\ +		scsi_msgbyte_name(INITIATE_RECOVERY),		\ +		scsi_msgbyte_name(RELEASE_RECOVERY),		\ +		scsi_msgbyte_name(CLEAR_ACA),			\ +		scsi_msgbyte_name(LOGICAL_UNIT_RESET),		\ +		scsi_msgbyte_name(SIMPLE_QUEUE_TAG),		\ +		scsi_msgbyte_name(HEAD_OF_QUEUE_TAG),		\ +		scsi_msgbyte_name(ORDERED_QUEUE_TAG),		\ +		scsi_msgbyte_name(IGNORE_WIDE_RESIDUE),		\ +		scsi_msgbyte_name(ACA),				\ +		scsi_msgbyte_name(QAS_REQUEST),			\ +		scsi_msgbyte_name(BUS_DEVICE_RESET),		\ +		scsi_msgbyte_name(ABORT)) + +#define scsi_statusbyte_name(result)	{ result, #result } +#define show_statusbyte_name(val)				\ +	__print_symbolic(val,					\ +		scsi_statusbyte_name(SAM_STAT_GOOD),		\ +		scsi_statusbyte_name(SAM_STAT_CHECK_CONDITION),	\ +		scsi_statusbyte_name(SAM_STAT_CONDITION_MET),	\ +		scsi_statusbyte_name(SAM_STAT_BUSY),		\ +		scsi_statusbyte_name(SAM_STAT_INTERMEDIATE),	\ +		scsi_statusbyte_name(SAM_STAT_INTERMEDIATE_CONDITION_MET), \ +		scsi_statusbyte_name(SAM_STAT_RESERVATION_CONFLICT),	\ +		scsi_statusbyte_name(SAM_STAT_COMMAND_TERMINATED),	\ +		scsi_statusbyte_name(SAM_STAT_TASK_SET_FULL),	\ +		scsi_statusbyte_name(SAM_STAT_ACA_ACTIVE),	\ +		scsi_statusbyte_name(SAM_STAT_TASK_ABORTED)) + +const char *scsi_trace_parse_cdb(struct trace_seq*, unsigned char*, int); +#define __parse_cdb(cdb, len) scsi_trace_parse_cdb(p, cdb, len) + +TRACE_EVENT(scsi_dispatch_cmd_start, + +	TP_PROTO(struct scsi_cmnd *cmd), + +	TP_ARGS(cmd), + +	TP_STRUCT__entry( +		__field( unsigned int,	host_no	) +		__field( unsigned int,	channel	) +		__field( unsigned int,	id	) +		__field( unsigned int,	lun	) +		__field( unsigned int,	opcode	) +		__field( unsigned int,	cmd_len ) +		__field( unsigned int,	data_sglen ) +		__field( unsigned int,	prot_sglen ) +		__dynamic_array(unsigned char,	cmnd, cmd->cmd_len) +	), + +	TP_fast_assign( +		__entry->host_no	= cmd->device->host->host_no; +		__entry->channel	= cmd->device->channel; +		__entry->id		= cmd->device->id; +		__entry->lun		= cmd->device->lun; +		__entry->opcode		= cmd->cmnd[0]; +		__entry->cmd_len	= cmd->cmd_len; +		__entry->data_sglen	= scsi_sg_count(cmd); +		__entry->prot_sglen	= scsi_prot_sg_count(cmd); +		memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len); +	), + +	TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u prot_sgl=%u" \ +		  " cmnd=(%s %s raw=%s)", +		  __entry->host_no, __entry->channel, __entry->id, +		  __entry->lun, __entry->data_sglen, __entry->prot_sglen, +		  show_opcode_name(__entry->opcode), +		  __parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len), +		  __print_hex(__get_dynamic_array(cmnd), __entry->cmd_len)) +); + +TRACE_EVENT(scsi_dispatch_cmd_error, + +	TP_PROTO(struct scsi_cmnd *cmd, int rtn), + +	TP_ARGS(cmd, rtn), + +	TP_STRUCT__entry( +		__field( unsigned int,	host_no	) +		__field( unsigned int,	channel	) +		__field( unsigned int,	id	) +		__field( unsigned int,	lun	) +		__field( int,		rtn	) +		__field( unsigned int,	opcode	) +		__field( unsigned int,	cmd_len ) +		__field( unsigned int,	data_sglen ) +		__field( unsigned int,	prot_sglen ) +		__dynamic_array(unsigned char,	cmnd, cmd->cmd_len) +	), + +	TP_fast_assign( +		__entry->host_no	= cmd->device->host->host_no; +		__entry->channel	= cmd->device->channel; +		__entry->id		= cmd->device->id; +		__entry->lun		= cmd->device->lun; +		__entry->rtn		= rtn; +		__entry->opcode		= cmd->cmnd[0]; +		__entry->cmd_len	= cmd->cmd_len; +		__entry->data_sglen	= scsi_sg_count(cmd); +		__entry->prot_sglen	= scsi_prot_sg_count(cmd); +		memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len); +	), + +	TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u prot_sgl=%u" \ +		  " cmnd=(%s %s raw=%s) rtn=%d", +		  __entry->host_no, __entry->channel, __entry->id, +		  __entry->lun, __entry->data_sglen, __entry->prot_sglen, +		  show_opcode_name(__entry->opcode), +		  __parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len), +		  __print_hex(__get_dynamic_array(cmnd), __entry->cmd_len), +		  __entry->rtn) +); + +DECLARE_EVENT_CLASS(scsi_cmd_done_timeout_template, + +	TP_PROTO(struct scsi_cmnd *cmd), + +	TP_ARGS(cmd), + +	TP_STRUCT__entry( +		__field( unsigned int,	host_no	) +		__field( unsigned int,	channel	) +		__field( unsigned int,	id	) +		__field( unsigned int,	lun	) +		__field( int,		result	) +		__field( unsigned int,	opcode	) +		__field( unsigned int,	cmd_len ) +		__field( unsigned int,	data_sglen ) +		__field( unsigned int,	prot_sglen ) +		__dynamic_array(unsigned char,	cmnd, cmd->cmd_len) +	), + +	TP_fast_assign( +		__entry->host_no	= cmd->device->host->host_no; +		__entry->channel	= cmd->device->channel; +		__entry->id		= cmd->device->id; +		__entry->lun		= cmd->device->lun; +		__entry->result		= cmd->result; +		__entry->opcode		= cmd->cmnd[0]; +		__entry->cmd_len	= cmd->cmd_len; +		__entry->data_sglen	= scsi_sg_count(cmd); +		__entry->prot_sglen	= scsi_prot_sg_count(cmd); +		memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len); +	), + +	TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u " \ +		  "prot_sgl=%u cmnd=(%s %s raw=%s) result=(driver=%s host=%s " \ +		  "message=%s status=%s)", +		  __entry->host_no, __entry->channel, __entry->id, +		  __entry->lun, __entry->data_sglen, __entry->prot_sglen, +		  show_opcode_name(__entry->opcode), +		  __parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len), +		  __print_hex(__get_dynamic_array(cmnd), __entry->cmd_len), +		  show_driverbyte_name(((__entry->result) >> 24) & 0xff), +		  show_hostbyte_name(((__entry->result) >> 16) & 0xff), +		  show_msgbyte_name(((__entry->result) >> 8) & 0xff), +		  show_statusbyte_name(__entry->result & 0xff)) +); + +DEFINE_EVENT(scsi_cmd_done_timeout_template, scsi_dispatch_cmd_done, +	     TP_PROTO(struct scsi_cmnd *cmd), +	     TP_ARGS(cmd)); + +DEFINE_EVENT(scsi_cmd_done_timeout_template, scsi_dispatch_cmd_timeout, +	     TP_PROTO(struct scsi_cmnd *cmd), +	     TP_ARGS(cmd)); + +TRACE_EVENT(scsi_eh_wakeup, + +	TP_PROTO(struct Scsi_Host *shost), + +	TP_ARGS(shost), + +	TP_STRUCT__entry( +		__field( unsigned int,	host_no	) +	), + +	TP_fast_assign( +		__entry->host_no	= shost->host_no; +	), + +	TP_printk("host_no=%u", __entry->host_no) +); + +#endif /*  _TRACE_SCSI_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index ea6f9d4a20e..c48320b3dab 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -198,6 +198,9 @@  		ftrace_print_symbols_seq(p, value, symbols);		\  	}) +#undef __print_hex +#define __print_hex(buf, buf_len) ftrace_print_hex_seq(p, buf, buf_len) +  #undef DECLARE_EVENT_CLASS  #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)	\  static notrace enum print_line_t					\ diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 8e46b3323cd..9cb5df5dc65 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -209,6 +209,7 @@ int trace_seq_putc(struct trace_seq *s, unsigned char c)  	return 1;  } +EXPORT_SYMBOL(trace_seq_putc);  int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len)  { @@ -355,6 +356,21 @@ ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,  }  EXPORT_SYMBOL(ftrace_print_symbols_seq); +const char * +ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len) +{ +	int i; +	const char *ret = p->buffer + p->len; + +	for (i = 0; i < buf_len; i++) +		trace_seq_printf(p, "%s%2.2x", i == 0 ? "" : " ", buf[i]); + +	trace_seq_putc(p, 0); + +	return ret; +} +EXPORT_SYMBOL(ftrace_print_hex_seq); +  #ifdef CONFIG_KRETPROBES  static inline const char *kretprobed(const char *name)  {  |