brintos

brintos / linux-shallow public Read only

0
0
Text · 92.0 KiB · 6c3f25c Raw
3321 lines · c
1/*2 *  linux/drivers/message/fusion/mptscsih.c3 *      For use with LSI PCI chip/adapter(s)4 *      running LSI Fusion MPT (Message Passing Technology) firmware.5 *6 *  Copyright (c) 1999-2008 LSI Corporation7 *  (mailto:DL-MPTFusionLinux@lsi.com)8 *9 */10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/11/*12    This program is free software; you can redistribute it and/or modify13    it under the terms of the GNU General Public License as published by14    the Free Software Foundation; version 2 of the License.15 16    This program is distributed in the hope that it will be useful,17    but WITHOUT ANY WARRANTY; without even the implied warranty of18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the19    GNU General Public License for more details.20 21    NO WARRANTY22    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR23    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT24    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,25    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is26    solely responsible for determining the appropriateness of using and27    distributing the Program and assumes all risks associated with its28    exercise of rights under this Agreement, including but not limited to29    the risks and costs of program errors, damage to or loss of data,30    programs or equipment, and unavailability or interruption of operations.31 32    DISCLAIMER OF LIABILITY33    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY34    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL35    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND36    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR37    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE38    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED39    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES40 41    You should have received a copy of the GNU General Public License42    along with this program; if not, write to the Free Software43    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA44*/45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/46 47#include <linux/module.h>48#include <linux/kernel.h>49#include <linux/slab.h>50#include <linux/init.h>51#include <linux/errno.h>52#include <linux/kdev_t.h>53#include <linux/blkdev.h>54#include <linux/delay.h>	/* for mdelay */55#include <linux/interrupt.h>56#include <linux/reboot.h>	/* notifier code */57#include <linux/workqueue.h>58 59#include <scsi/scsi.h>60#include <scsi/scsi_cmnd.h>61#include <scsi/scsi_device.h>62#include <scsi/scsi_host.h>63#include <scsi/scsi_tcq.h>64#include <scsi/scsi_dbg.h>65 66#include "mptbase.h"67#include "mptscsih.h"68#include "lsi/mpi_log_sas.h"69 70/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/71#define my_NAME		"Fusion MPT SCSI Host driver"72#define my_VERSION	MPT_LINUX_VERSION_COMMON73#define MYNAM		"mptscsih"74 75MODULE_AUTHOR(MODULEAUTHOR);76MODULE_DESCRIPTION(my_NAME);77MODULE_LICENSE("GPL");78MODULE_VERSION(my_VERSION);79 80/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/81/*82 *  Other private/forward protos...83 */84struct scsi_cmnd	*mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);85static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);86static void	mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);87static int	SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);88int		mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);89static void	mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);90int		mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);91 92static int	mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,93				 SCSIIORequest_t *pReq, int req_idx);94static void	mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);95static void	mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);96 97int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,98		u64 lun, int ctx2abort, ulong timeout);99 100int		mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);101int		mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);102 103void104mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);105static int	mptscsih_get_completion_code(MPT_ADAPTER *ioc,106		MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);107int		mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);108static int	mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);109static void	mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);110 111static int112mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,113				SCSITaskMgmtReply_t *pScsiTmReply);114void 		mptscsih_remove(struct pci_dev *);115void 		mptscsih_shutdown(struct pci_dev *);116#ifdef CONFIG_PM117int 		mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);118int 		mptscsih_resume(struct pci_dev *pdev);119#endif120 121 122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/123/*124 *	mptscsih_getFreeChainBuffer - Function to get a free chain125 *	from the MPT_SCSI_HOST FreeChainQ.126 *	@ioc: Pointer to MPT_ADAPTER structure127 *	@req_idx: Index of the SCSI IO request frame. (output)128 *129 *	return SUCCESS or FAILED130 */131static inline int132mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)133{134	MPT_FRAME_HDR *chainBuf;135	unsigned long flags;136	int rc;137	int chain_idx;138 139	dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",140	    ioc->name));141	spin_lock_irqsave(&ioc->FreeQlock, flags);142	if (!list_empty(&ioc->FreeChainQ)) {143		int offset;144 145		chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,146				u.frame.linkage.list);147		list_del(&chainBuf->u.frame.linkage.list);148		offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;149		chain_idx = offset / ioc->req_sz;150		rc = SUCCESS;151		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT152		    "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",153		    ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));154	} else {155		rc = FAILED;156		chain_idx = MPT_HOST_NO_CHAIN;157		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",158		    ioc->name));159	}160	spin_unlock_irqrestore(&ioc->FreeQlock, flags);161 162	*retIndex = chain_idx;163	return rc;164} /* mptscsih_getFreeChainBuffer() */165 166/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/167/*168 *	mptscsih_AddSGE - Add a SGE (plus chain buffers) to the169 *	SCSIIORequest_t Message Frame.170 *	@ioc: Pointer to MPT_ADAPTER structure171 *	@SCpnt: Pointer to scsi_cmnd structure172 *	@pReq: Pointer to SCSIIORequest_t structure173 *174 *	Returns ...175 */176static int177mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,178		SCSIIORequest_t *pReq, int req_idx)179{180	char 	*psge;181	char	*chainSge;182	struct scatterlist *sg;183	int	 frm_sz;184	int	 sges_left, sg_done;185	int	 chain_idx = MPT_HOST_NO_CHAIN;186	int	 sgeOffset;187	int	 numSgeSlots, numSgeThisFrame;188	u32	 sgflags, sgdir, thisxfer = 0;189	int	 chain_dma_off = 0;190	int	 newIndex;191	int	 ii;192	dma_addr_t v2;193	u32	RequestNB;194 195	sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;196	if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {197		sgdir = MPT_TRANSFER_HOST_TO_IOC;198	} else {199		sgdir = MPT_TRANSFER_IOC_TO_HOST;200	}201 202	psge = (char *) &pReq->SGL;203	frm_sz = ioc->req_sz;204 205	/* Map the data portion, if any.206	 * sges_left  = 0 if no data transfer.207	 */208	sges_left = scsi_dma_map(SCpnt);209	if (sges_left < 0)210		return FAILED;211 212	/* Handle the SG case.213	 */214	sg = scsi_sglist(SCpnt);215	sg_done  = 0;216	sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);217	chainSge = NULL;218 219	/* Prior to entering this loop - the following must be set220	 * current MF:  sgeOffset (bytes)221	 *              chainSge (Null if original MF is not a chain buffer)222	 *              sg_done (num SGE done for this MF)223	 */224 225nextSGEset:226	numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);227	numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;228 229	sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;230 231	/* Get first (num - 1) SG elements232	 * Skip any SG entries with a length of 0233	 * NOTE: at finish, sg and psge pointed to NEXT data/location positions234	 */235	for (ii=0; ii < (numSgeThisFrame-1); ii++) {236		thisxfer = sg_dma_len(sg);237		if (thisxfer == 0) {238			/* Get next SG element from the OS */239			sg = sg_next(sg);240			sg_done++;241			continue;242		}243 244		v2 = sg_dma_address(sg);245		ioc->add_sge(psge, sgflags | thisxfer, v2);246 247		/* Get next SG element from the OS */248		sg = sg_next(sg);249		psge += ioc->SGE_size;250		sgeOffset += ioc->SGE_size;251		sg_done++;252	}253 254	if (numSgeThisFrame == sges_left) {255		/* Add last element, end of buffer and end of list flags.256		 */257		sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |258				MPT_SGE_FLAGS_END_OF_BUFFER |259				MPT_SGE_FLAGS_END_OF_LIST;260 261		/* Add last SGE and set termination flags.262		 * Note: Last SGE may have a length of 0 - which should be ok.263		 */264		thisxfer = sg_dma_len(sg);265 266		v2 = sg_dma_address(sg);267		ioc->add_sge(psge, sgflags | thisxfer, v2);268		sgeOffset += ioc->SGE_size;269		sg_done++;270 271		if (chainSge) {272			/* The current buffer is a chain buffer,273			 * but there is not another one.274			 * Update the chain element275			 * Offset and Length fields.276			 */277			ioc->add_chain((char *)chainSge, 0, sgeOffset,278				ioc->ChainBufferDMA + chain_dma_off);279		} else {280			/* The current buffer is the original MF281			 * and there is no Chain buffer.282			 */283			pReq->ChainOffset = 0;284			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;285			dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT286			    "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));287			ioc->RequestNB[req_idx] = RequestNB;288		}289	} else {290		/* At least one chain buffer is needed.291		 * Complete the first MF292		 *  - last SGE element, set the LastElement bit293		 *  - set ChainOffset (words) for orig MF294		 *             (OR finish previous MF chain buffer)295		 *  - update MFStructPtr ChainIndex296		 *  - Populate chain element297		 * Also298		 * Loop until done.299		 */300 301		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",302				ioc->name, sg_done));303 304		/* Set LAST_ELEMENT flag for last non-chain element305		 * in the buffer. Since psge points at the NEXT306		 * SGE element, go back one SGE element, update the flags307		 * and reset the pointer. (Note: sgflags & thisxfer are already308		 * set properly).309		 */310		if (sg_done) {311			u32 *ptmp = (u32 *) (psge - ioc->SGE_size);312			sgflags = le32_to_cpu(*ptmp);313			sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;314			*ptmp = cpu_to_le32(sgflags);315		}316 317		if (chainSge) {318			/* The current buffer is a chain buffer.319			 * chainSge points to the previous Chain Element.320			 * Update its chain element Offset and Length (must321			 * include chain element size) fields.322			 * Old chain element is now complete.323			 */324			u8 nextChain = (u8) (sgeOffset >> 2);325			sgeOffset += ioc->SGE_size;326			ioc->add_chain((char *)chainSge, nextChain, sgeOffset,327					 ioc->ChainBufferDMA + chain_dma_off);328		} else {329			/* The original MF buffer requires a chain buffer -330			 * set the offset.331			 * Last element in this MF is a chain element.332			 */333			pReq->ChainOffset = (u8) (sgeOffset >> 2);334			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;335			dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));336			ioc->RequestNB[req_idx] = RequestNB;337		}338 339		sges_left -= sg_done;340 341 342		/* NOTE: psge points to the beginning of the chain element343		 * in current buffer. Get a chain buffer.344		 */345		if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {346			dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT347			    "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",348 			    ioc->name, pReq->CDB[0], SCpnt));349			return FAILED;350		}351 352		/* Update the tracking arrays.353		 * If chainSge == NULL, update ReqToChain, else ChainToChain354		 */355		if (chainSge) {356			ioc->ChainToChain[chain_idx] = newIndex;357		} else {358			ioc->ReqToChain[req_idx] = newIndex;359		}360		chain_idx = newIndex;361		chain_dma_off = ioc->req_sz * chain_idx;362 363		/* Populate the chainSGE for the current buffer.364		 * - Set chain buffer pointer to psge and fill365		 *   out the Address and Flags fields.366		 */367		chainSge = (char *) psge;368		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Current buff @ %p (index 0x%x)",369		    ioc->name, psge, req_idx));370 371		/* Start the SGE for the next buffer372		 */373		psge = (char *) (ioc->ChainBuffer + chain_dma_off);374		sgeOffset = 0;375		sg_done = 0;376 377		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Chain buff @ %p (index 0x%x)\n",378		    ioc->name, psge, chain_idx));379 380		/* Start the SGE for the next buffer381		 */382 383		goto nextSGEset;384	}385 386	return SUCCESS;387} /* mptscsih_AddSGE() */388 389static void390mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,391    U32 SlotStatus)392{393	MPT_FRAME_HDR *mf;394	SEPRequest_t 	 *SEPMsg;395 396	if (ioc->bus_type != SAS)397		return;398 399	/* Not supported for hidden raid components400	 */401	if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)402		return;403 404	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {405		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",406		    ioc->name,__func__));407		return;408	}409 410	SEPMsg = (SEPRequest_t *)mf;411	SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;412	SEPMsg->Bus = vtarget->channel;413	SEPMsg->TargetID = vtarget->id;414	SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;415	SEPMsg->SlotStatus = SlotStatus;416	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT417	    "Sending SEP cmd=%x channel=%d id=%d\n",418	    ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));419	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);420}421 422#ifdef CONFIG_FUSION_LOGGING423/**424 *	mptscsih_info_scsiio - debug print info on reply frame425 *	@ioc: Pointer to MPT_ADAPTER structure426 *	@sc: original scsi cmnd pointer427 *	@pScsiReply: Pointer to MPT reply frame428 *429 *	MPT_DEBUG_REPLY needs to be enabled to obtain this info430 *431 *	Refer to lsi/mpi.h.432 **/433static void434mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)435{436	char	*desc = NULL;437	char	*desc1 = NULL;438	u16	ioc_status;439	u8	skey, asc, ascq;440 441	ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;442 443	switch (ioc_status) {444 445	case MPI_IOCSTATUS_SUCCESS:446		desc = "success";447		break;448	case MPI_IOCSTATUS_SCSI_INVALID_BUS:449		desc = "invalid bus";450		break;451	case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:452		desc = "invalid target_id";453		break;454	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:455		desc = "device not there";456		break;457	case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:458		desc = "data overrun";459		break;460	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:461		desc = "data underrun";462		break;463	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:464		desc = "I/O data error";465		break;466	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:467		desc = "protocol error";468		break;469	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:470		desc = "task terminated";471		break;472	case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:473		desc = "residual mismatch";474		break;475	case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:476		desc = "task management failed";477		break;478	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:479		desc = "IOC terminated";480		break;481	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:482		desc = "ext terminated";483		break;484	default:485		desc = "";486		break;487	}488 489	switch (pScsiReply->SCSIStatus)490	{491 492	case MPI_SCSI_STATUS_SUCCESS:493		desc1 = "success";494		break;495	case MPI_SCSI_STATUS_CHECK_CONDITION:496		desc1 = "check condition";497		break;498	case MPI_SCSI_STATUS_CONDITION_MET:499		desc1 = "condition met";500		break;501	case MPI_SCSI_STATUS_BUSY:502		desc1 = "busy";503		break;504	case MPI_SCSI_STATUS_INTERMEDIATE:505		desc1 = "intermediate";506		break;507	case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:508		desc1 = "intermediate condmet";509		break;510	case MPI_SCSI_STATUS_RESERVATION_CONFLICT:511		desc1 = "reservation conflict";512		break;513	case MPI_SCSI_STATUS_COMMAND_TERMINATED:514		desc1 = "command terminated";515		break;516	case MPI_SCSI_STATUS_TASK_SET_FULL:517		desc1 = "task set full";518		break;519	case MPI_SCSI_STATUS_ACA_ACTIVE:520		desc1 = "aca active";521		break;522	case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:523		desc1 = "fcpext device logged out";524		break;525	case MPI_SCSI_STATUS_FCPEXT_NO_LINK:526		desc1 = "fcpext no link";527		break;528	case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:529		desc1 = "fcpext unassigned";530		break;531	default:532		desc1 = "";533		break;534	}535 536	scsi_print_command(sc);537	printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %llu\n",538	    ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);539	printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "540	    "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,541	    scsi_get_resid(sc));542	printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "543	    "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),544	    le32_to_cpu(pScsiReply->TransferCount), sc->result);545 546	printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "547	    "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",548	    ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,549	    pScsiReply->SCSIState);550 551	if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {552		skey = sc->sense_buffer[2] & 0x0F;553		asc = sc->sense_buffer[12];554		ascq = sc->sense_buffer[13];555 556		printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "557		    "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);558	}559 560	/*561	 *  Look for + dump FCP ResponseInfo[]!562	 */563	if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&564	    pScsiReply->ResponseInfo)565		printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",566		    ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));567}568#endif569 570/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/571/*572 *	mptscsih_io_done - Main SCSI IO callback routine registered to573 *	Fusion MPT (base) driver574 *	@ioc: Pointer to MPT_ADAPTER structure575 *	@mf: Pointer to original MPT request frame576 *	@r: Pointer to MPT reply frame (NULL if TurboReply)577 *578 *	This routine is called from mpt.c::mpt_interrupt() at the completion579 *	of any SCSI IO request.580 *	This routine is registered with the Fusion MPT (base) driver at driver581 *	load/init time via the mpt_register() API call.582 *583 *	Returns 1 indicating alloc'd request frame ptr should be freed.584 */585int586mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)587{588	struct scsi_cmnd	*sc;589	MPT_SCSI_HOST	*hd;590	SCSIIORequest_t	*pScsiReq;591	SCSIIOReply_t	*pScsiReply;592	u16		 req_idx, req_idx_MR;593	VirtDevice	 *vdevice;594	VirtTarget	 *vtarget;595 596	hd = shost_priv(ioc->sh);597	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);598	req_idx_MR = (mr != NULL) ?599	    le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;600 601	/* Special case, where already freed message frame is received from602	 * Firmware. It happens with Resetting IOC.603	 * Return immediately. Do not care604	 */605	if ((req_idx != req_idx_MR) ||606	    (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))607		return 0;608 609	sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);610	if (sc == NULL) {611		MPIHeader_t *hdr = (MPIHeader_t *)mf;612 613		/* Remark: writeSDP1 will use the ScsiDoneCtx614		 * If a SCSI I/O cmd, device disabled by OS and615		 * completion done. Cannot touch sc struct. Just free mem.616		 */617		if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)618			printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",619			ioc->name);620 621		mptscsih_freeChainBuffers(ioc, req_idx);622		return 1;623	}624 625	if ((unsigned char *)mf != sc->host_scribble) {626		mptscsih_freeChainBuffers(ioc, req_idx);627		return 1;628	}629 630	if (ioc->bus_type == SAS) {631		VirtDevice *vdevice = sc->device->hostdata;632 633		if (!vdevice || !vdevice->vtarget ||634		    vdevice->vtarget->deleted) {635			sc->result = DID_NO_CONNECT << 16;636			goto out;637		}638	}639 640	sc->host_scribble = NULL;641	sc->result = DID_OK << 16;		/* Set default reply as OK */642	pScsiReq = (SCSIIORequest_t *) mf;643	pScsiReply = (SCSIIOReply_t *) mr;644 645	if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){646		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT647			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",648			ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));649	}else{650		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT651			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",652			ioc->name, mf, mr, sc, req_idx));653	}654 655	if (pScsiReply == NULL) {656		/* special context reply handling */657		;658	} else {659		u32	 xfer_cnt;660		u16	 status;661		u8	 scsi_state, scsi_status;662		u32	 log_info;663 664		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;665 666		scsi_state = pScsiReply->SCSIState;667		scsi_status = pScsiReply->SCSIStatus;668		xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);669		scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);670		log_info = le32_to_cpu(pScsiReply->IOCLogInfo);671 672		/*673		 *  if we get a data underrun indication, yet no data was674		 *  transferred and the SCSI status indicates that the675		 *  command was never started, change the data underrun676		 *  to success677		 */678		if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&679		    (scsi_status == MPI_SCSI_STATUS_BUSY ||680		     scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||681		     scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {682			status = MPI_IOCSTATUS_SUCCESS;683		}684 685		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)686			mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);687 688		/*689		 *  Look for + dump FCP ResponseInfo[]!690		 */691		if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&692		    pScsiReply->ResponseInfo) {693			printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%llu] "694			"FCP_ResponseInfo=%08xh\n", ioc->name,695			sc->device->host->host_no, sc->device->channel,696			sc->device->id, sc->device->lun,697			le32_to_cpu(pScsiReply->ResponseInfo));698		}699 700		switch(status) {701		case MPI_IOCSTATUS_BUSY:			/* 0x0002 */702		case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:	/* 0x0006 */703			/* CHECKME!704			 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)705			 * But not: DID_BUS_BUSY lest one risk706			 * killing interrupt handler:-(707			 */708			sc->result = SAM_STAT_BUSY;709			break;710 711		case MPI_IOCSTATUS_SCSI_INVALID_BUS:		/* 0x0041 */712		case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:	/* 0x0042 */713			sc->result = DID_BAD_TARGET << 16;714			break;715 716		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */717			/* Spoof to SCSI Selection Timeout! */718			if (ioc->bus_type != FC)719				sc->result = DID_NO_CONNECT << 16;720			/* else fibre, just stall until rescan event */721			else722				sc->result = DID_REQUEUE << 16;723 724			if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)725				hd->sel_timeout[pScsiReq->TargetID]++;726 727			vdevice = sc->device->hostdata;728			if (!vdevice)729				break;730			vtarget = vdevice->vtarget;731			if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {732				mptscsih_issue_sep_command(ioc, vtarget,733				    MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);734				vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;735			}736			break;737 738		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */739			if ( ioc->bus_type == SAS ) {740				u16 ioc_status =741				    le16_to_cpu(pScsiReply->IOCStatus);742				if ((ioc_status &743					MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)744					&&745					((log_info & SAS_LOGINFO_MASK) ==746					SAS_LOGINFO_NEXUS_LOSS)) {747						VirtDevice *vdevice =748						sc->device->hostdata;749 750					    /* flag the device as being in751					     * device removal delay so we can752					     * notify the midlayer to hold off753					     * on timeout eh */754						if (vdevice && vdevice->755							vtarget &&756							vdevice->vtarget->757							raidVolume)758							printk(KERN_INFO759							"Skipping Raid Volume"760							"for inDMD\n");761						else if (vdevice &&762							vdevice->vtarget)763							vdevice->vtarget->764								inDMD = 1;765 766					    sc->result =767						    (DID_TRANSPORT_DISRUPTED768						    << 16);769					    break;770				}771			} else if (ioc->bus_type == FC) {772				/*773				 * The FC IOC may kill a request for variety of774				 * reasons, some of which may be recovered by a775				 * retry, some which are unlikely to be776				 * recovered. Return DID_ERROR instead of777				 * DID_RESET to permit retry of the command,778				 * just not an infinite number of them779				 */780				sc->result = DID_ERROR << 16;781				break;782			}783 784			/*785			 * Allow non-SAS & non-NEXUS_LOSS to drop into below code786			 */787			fallthrough;788 789		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */790			/* Linux handles an unsolicited DID_RESET better791			 * than an unsolicited DID_ABORT.792			 */793			sc->result = DID_RESET << 16;794			break;795 796		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */797			if (ioc->bus_type == FC)798				sc->result = DID_ERROR << 16;799			else800				sc->result = DID_RESET << 16;801			break;802 803		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */804			scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);805			if((xfer_cnt==0)||(sc->underflow > xfer_cnt))806				sc->result=DID_SOFT_ERROR << 16;807			else /* Sufficient data transfer occurred */808				sc->result = (DID_OK << 16) | scsi_status;809			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT810			    "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",811			    ioc->name, sc->result, sc->device->channel, sc->device->id));812			break;813 814		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */815			/*816			 *  Do upfront check for valid SenseData and give it817			 *  precedence!818			 */819			sc->result = (DID_OK << 16) | scsi_status;820			if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {821 822				/*823				 * For an Errata on LSI53C1030824				 * When the length of request data825				 * and transfer data are different826				 * with result of command (READ or VERIFY),827				 * DID_SOFT_ERROR is set.828				 */829				if (ioc->bus_type == SPI) {830					if ((pScsiReq->CDB[0] == READ_6  && ((pScsiReq->CDB[1] & 0x02) == 0)) ||831					    pScsiReq->CDB[0] == READ_10 ||832					    pScsiReq->CDB[0] == READ_12 ||833						(pScsiReq->CDB[0] == READ_16 &&834						((pScsiReq->CDB[1] & 0x02) == 0)) ||835					    pScsiReq->CDB[0] == VERIFY  ||836					    pScsiReq->CDB[0] == VERIFY_16) {837						if (scsi_bufflen(sc) !=838							xfer_cnt) {839							sc->result =840							DID_SOFT_ERROR << 16;841						    printk(KERN_WARNING "Errata"842						    "on LSI53C1030 occurred."843						    "sc->req_bufflen=0x%02x,"844						    "xfer_cnt=0x%02x\n",845						    scsi_bufflen(sc),846						    xfer_cnt);847						}848					}849				}850 851				if (xfer_cnt < sc->underflow) {852					if (scsi_status == SAM_STAT_BUSY)853						sc->result = SAM_STAT_BUSY;854					else855						sc->result = DID_SOFT_ERROR << 16;856				}857				if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {858					/* What to do?859				 	*/860					sc->result = DID_SOFT_ERROR << 16;861				}862				else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {863					/*  Not real sure here either...  */864					sc->result = DID_RESET << 16;865				}866			}867 868 869			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT870			    "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",871			    ioc->name, sc->underflow));872			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT873			    "  ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));874 875			/* Report Queue Full876			 */877			if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)878				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);879 880			break;881 882		case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:		/* 0x0044 */883			scsi_set_resid(sc, 0);884			fallthrough;885		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */886		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */887			sc->result = (DID_OK << 16) | scsi_status;888			if (scsi_state == 0) {889				;890			} else if (scsi_state &891			    MPI_SCSI_STATE_AUTOSENSE_VALID) {892 893				/*894				 * For potential trouble on LSI53C1030.895				 * (date:2007.xx.)896				 * It is checked whether the length of897				 * request data is equal to898				 * the length of transfer and residual.899				 * MEDIUM_ERROR is set by incorrect data.900				 */901				if ((ioc->bus_type == SPI) &&902					(sc->sense_buffer[2] & 0x20)) {903					u32	 difftransfer;904					difftransfer =905					sc->sense_buffer[3] << 24 |906					sc->sense_buffer[4] << 16 |907					sc->sense_buffer[5] << 8 |908					sc->sense_buffer[6];909					if (((sc->sense_buffer[3] & 0x80) ==910						0x80) && (scsi_bufflen(sc)911						!= xfer_cnt)) {912						sc->sense_buffer[2] =913						    MEDIUM_ERROR;914						sc->sense_buffer[12] = 0xff;915						sc->sense_buffer[13] = 0xff;916						printk(KERN_WARNING"Errata"917						"on LSI53C1030 occurred."918						"sc->req_bufflen=0x%02x,"919						"xfer_cnt=0x%02x\n" ,920						scsi_bufflen(sc),921						xfer_cnt);922					}923					if (((sc->sense_buffer[3] & 0x80)924						!= 0x80) &&925						(scsi_bufflen(sc) !=926						xfer_cnt + difftransfer)) {927						sc->sense_buffer[2] =928							MEDIUM_ERROR;929						sc->sense_buffer[12] = 0xff;930						sc->sense_buffer[13] = 0xff;931						printk(KERN_WARNING932						"Errata on LSI53C1030 occurred"933						"sc->req_bufflen=0x%02x,"934						" xfer_cnt=0x%02x,"935						"difftransfer=0x%02x\n",936						scsi_bufflen(sc),937						xfer_cnt,938						difftransfer);939					}940				}941 942				/*943				 * If running against circa 200003dd 909 MPT f/w,944				 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL945				 * (QUEUE_FULL) returned from device! --> get 0x0000?128946				 * and with SenseBytes set to 0.947				 */948				if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)949					mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);950 951			}952			else if (scsi_state &953			         (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)954			   ) {955				/*956				 * What to do?957				 */958				sc->result = DID_SOFT_ERROR << 16;959			}960			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {961				/*  Not real sure here either...  */962				sc->result = DID_RESET << 16;963			}964			else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {965				/* Device Inq. data indicates that it supports966				 * QTags, but rejects QTag messages.967				 * This command completed OK.968				 *969				 * Not real sure here either so do nothing...  */970			}971 972			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)973				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);974 975			/* Add handling of:976			 * Reservation Conflict, Busy,977			 * Command Terminated, CHECK978			 */979			break;980 981		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */982			sc->result = DID_SOFT_ERROR << 16;983			break;984 985		case MPI_IOCSTATUS_INVALID_FUNCTION:		/* 0x0001 */986		case MPI_IOCSTATUS_INVALID_SGL:			/* 0x0003 */987		case MPI_IOCSTATUS_INTERNAL_ERROR:		/* 0x0004 */988		case MPI_IOCSTATUS_RESERVED:			/* 0x0005 */989		case MPI_IOCSTATUS_INVALID_FIELD:		/* 0x0007 */990		case MPI_IOCSTATUS_INVALID_STATE:		/* 0x0008 */991		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */992		case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:	/* 0x004A */993		default:994			/*995			 * What to do?996			 */997			sc->result = DID_SOFT_ERROR << 16;998			break;999 1000		}	/* switch(status) */1001 1002#ifdef CONFIG_FUSION_LOGGING1003		if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))1004			mptscsih_info_scsiio(ioc, sc, pScsiReply);1005#endif1006 1007	} /* end of address reply case */1008out:1009	/* Unmap the DMA buffers, if any. */1010	scsi_dma_unmap(sc);1011 1012	scsi_done(sc);			/* Issue the command callback */1013 1014	/* Free Chain buffers */1015	mptscsih_freeChainBuffers(ioc, req_idx);1016	return 1;1017}1018 1019/*1020 *	mptscsih_flush_running_cmds - For each command found, search1021 *		Scsi_Host instance taskQ and reply to OS.1022 *		Called only if recovering from a FW reload.1023 *	@hd: Pointer to a SCSI HOST structure1024 *1025 *	Returns: None.1026 *1027 *	Must be called while new I/Os are being queued.1028 */1029void1030mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)1031{1032	MPT_ADAPTER *ioc = hd->ioc;1033	struct scsi_cmnd *sc;1034	SCSIIORequest_t	*mf = NULL;1035	int		 ii;1036	int		 channel, id;1037 1038	for (ii= 0; ii < ioc->req_depth; ii++) {1039		sc = mptscsih_getclear_scsi_lookup(ioc, ii);1040		if (!sc)1041			continue;1042		mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);1043		if (!mf)1044			continue;1045		channel = mf->Bus;1046		id = mf->TargetID;1047		mptscsih_freeChainBuffers(ioc, ii);1048		mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);1049		if ((unsigned char *)mf != sc->host_scribble)1050			continue;1051		scsi_dma_unmap(sc);1052		sc->result = DID_RESET << 16;1053		sc->host_scribble = NULL;1054		dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT1055		    "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "1056		    "idx=%x\n", ioc->name, channel, id, sc, mf, ii));1057		scsi_done(sc);1058	}1059}1060EXPORT_SYMBOL(mptscsih_flush_running_cmds);1061 1062/*1063 *	mptscsih_search_running_cmds - Delete any commands associated1064 *		with the specified target and lun. Function called only1065 *		when a lun is disable by mid-layer.1066 *		Do NOT access the referenced scsi_cmnd structure or1067 *		members. Will cause either a paging or NULL ptr error.1068 *		(BUT, BUT, BUT, the code does reference it! - mdr)1069 *      @hd: Pointer to a SCSI HOST structure1070 *	@vdevice: per device private data1071 *1072 *	Returns: None.1073 *1074 *	Called from slave_destroy.1075 */1076static void1077mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)1078{1079	SCSIIORequest_t	*mf = NULL;1080	int		 ii;1081	struct scsi_cmnd *sc;1082	struct scsi_lun  lun;1083	MPT_ADAPTER *ioc = hd->ioc;1084	unsigned long	flags;1085 1086	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);1087	for (ii = 0; ii < ioc->req_depth; ii++) {1088		if ((sc = ioc->ScsiLookup[ii]) != NULL) {1089 1090			mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);1091			if (mf == NULL)1092				continue;1093			/* If the device is a hidden raid component, then its1094			 * expected that the mf->function will be RAID_SCSI_IO1095			 */1096			if (vdevice->vtarget->tflags &1097			    MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=1098			    MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)1099				continue;1100 1101			int_to_scsilun(vdevice->lun, &lun);1102			if ((mf->Bus != vdevice->vtarget->channel) ||1103			    (mf->TargetID != vdevice->vtarget->id) ||1104			    memcmp(lun.scsi_lun, mf->LUN, 8))1105				continue;1106 1107			if ((unsigned char *)mf != sc->host_scribble)1108				continue;1109			ioc->ScsiLookup[ii] = NULL;1110			spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);1111			mptscsih_freeChainBuffers(ioc, ii);1112			mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);1113			scsi_dma_unmap(sc);1114			sc->host_scribble = NULL;1115			sc->result = DID_NO_CONNECT << 16;1116			dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,1117			   MYIOC_s_FMT "completing cmds: fw_channel %d, "1118			   "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,1119			   vdevice->vtarget->channel, vdevice->vtarget->id,1120			   sc, mf, ii));1121			scsi_done(sc);1122			spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);1123		}1124	}1125	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);1126	return;1127}1128 1129/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1130 1131/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1132/*1133 *	mptscsih_report_queue_full - Report QUEUE_FULL status returned1134 *	from a SCSI target device.1135 *	@sc: Pointer to scsi_cmnd structure1136 *	@pScsiReply: Pointer to SCSIIOReply_t1137 *	@pScsiReq: Pointer to original SCSI request1138 *1139 *	This routine periodically reports QUEUE_FULL status returned from a1140 *	SCSI target device.  It reports this to the console via kernel1141 *	printk() API call, not more than once every 10 seconds.1142 */1143static void1144mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)1145{1146	long time = jiffies;1147	MPT_SCSI_HOST		*hd;1148	MPT_ADAPTER	*ioc;1149 1150	if (sc->device == NULL)1151		return;1152	if (sc->device->host == NULL)1153		return;1154	if ((hd = shost_priv(sc->device->host)) == NULL)1155		return;1156	ioc = hd->ioc;1157	if (time - hd->last_queue_full > 10 * HZ) {1158		dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%llu) reported QUEUE_FULL!\n",1159				ioc->name, 0, sc->device->id, sc->device->lun));1160		hd->last_queue_full = time;1161	}1162}1163 1164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1165/*1166 *	mptscsih_remove - Removed scsi devices1167 *	@pdev: Pointer to pci_dev structure1168 *1169 *1170 */1171void1172mptscsih_remove(struct pci_dev *pdev)1173{1174	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);1175	struct Scsi_Host 	*host = ioc->sh;1176	MPT_SCSI_HOST		*hd;1177	int sz1;1178 1179	if (host == NULL)1180		hd = NULL;1181	else1182		hd = shost_priv(host);1183 1184	mptscsih_shutdown(pdev);1185 1186	sz1=0;1187 1188	if (ioc->ScsiLookup != NULL) {1189		sz1 = ioc->req_depth * sizeof(void *);1190		kfree(ioc->ScsiLookup);1191		ioc->ScsiLookup = NULL;1192	}1193 1194	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT1195	    "Free'd ScsiLookup (%d) memory\n",1196	    ioc->name, sz1));1197 1198	if (hd)1199		kfree(hd->info_kbuf);1200 1201	/* NULL the Scsi_Host pointer1202	 */1203	ioc->sh = NULL;1204 1205	if (host)1206		scsi_host_put(host);1207	mpt_detach(pdev);1208 1209}1210 1211/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1212/*1213 *	mptscsih_shutdown - reboot notifier1214 *1215 */1216void1217mptscsih_shutdown(struct pci_dev *pdev)1218{1219}1220 1221#ifdef CONFIG_PM1222/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1223/*1224 *	mptscsih_suspend - Fusion MPT scsi driver suspend routine.1225 *1226 *1227 */1228int1229mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)1230{1231	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);1232 1233	scsi_block_requests(ioc->sh);1234	mptscsih_shutdown(pdev);1235	return mpt_suspend(pdev,state);1236}1237 1238/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1239/*1240 *	mptscsih_resume - Fusion MPT scsi driver resume routine.1241 *1242 *1243 */1244int1245mptscsih_resume(struct pci_dev *pdev)1246{1247	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);1248	int rc;1249 1250	rc = mpt_resume(pdev);1251	scsi_unblock_requests(ioc->sh);1252	return rc;1253}1254 1255#endif1256 1257/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1258/**1259 *	mptscsih_info - Return information about MPT adapter1260 *	@SChost: Pointer to Scsi_Host structure1261 *1262 *	(linux scsi_host_template.info routine)1263 *1264 *	Returns pointer to buffer where information was written.1265 */1266const char *1267mptscsih_info(struct Scsi_Host *SChost)1268{1269	MPT_SCSI_HOST *h;1270	int size = 0;1271 1272	h = shost_priv(SChost);1273 1274	if (h->info_kbuf == NULL)1275		if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)1276			return h->info_kbuf;1277	h->info_kbuf[0] = '\0';1278 1279	mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);1280	h->info_kbuf[size-1] = '\0';1281 1282	return h->info_kbuf;1283}1284 1285int mptscsih_show_info(struct seq_file *m, struct Scsi_Host *host)1286{1287	MPT_SCSI_HOST	*hd = shost_priv(host);1288	MPT_ADAPTER	*ioc = hd->ioc;1289 1290	seq_printf(m, "%s: %s, ", ioc->name, ioc->prod_name);1291	seq_printf(m, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);1292	seq_printf(m, "Ports=%d, ", ioc->facts.NumberOfPorts);1293	seq_printf(m, "MaxQ=%d\n", ioc->req_depth);1294 1295	return 0;1296}1297 1298/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1299#define ADD_INDEX_LOG(req_ent)	do { } while(0)1300 1301/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1302/**1303 *	mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.1304 *	@SCpnt: Pointer to scsi_cmnd structure1305 *1306 *	(linux scsi_host_template.queuecommand routine)1307 *	This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest1308 *	from a linux scsi_cmnd request and send it to the IOC.1309 *1310 *	Returns 0. (rtn value discarded by linux scsi mid-layer)1311 */1312int1313mptscsih_qcmd(struct scsi_cmnd *SCpnt)1314{1315	MPT_SCSI_HOST		*hd;1316	MPT_FRAME_HDR		*mf;1317	SCSIIORequest_t		*pScsiReq;1318	VirtDevice		*vdevice = SCpnt->device->hostdata;1319	u32	 datalen;1320	u32	 scsictl;1321	u32	 scsidir;1322	u32	 cmd_len;1323	int	 my_idx;1324	int	 ii;1325	MPT_ADAPTER *ioc;1326 1327	hd = shost_priv(SCpnt->device->host);1328	ioc = hd->ioc;1329 1330	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p\n",1331		ioc->name, SCpnt));1332 1333	if (ioc->taskmgmt_quiesce_io)1334		return SCSI_MLQUEUE_HOST_BUSY;1335 1336	/*1337	 *  Put together a MPT SCSI request...1338	 */1339	if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {1340		dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",1341				ioc->name));1342		return SCSI_MLQUEUE_HOST_BUSY;1343	}1344 1345	pScsiReq = (SCSIIORequest_t *) mf;1346 1347	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);1348 1349	ADD_INDEX_LOG(my_idx);1350 1351	/*    TUR's being issued with scsictl=0x02000000 (DATA_IN)!1352	 *    Seems we may receive a buffer (datalen>0) even when there1353	 *    will be no data transfer!  GRRRRR...1354	 */1355	if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {1356		datalen = scsi_bufflen(SCpnt);1357		scsidir = MPI_SCSIIO_CONTROL_READ;	/* DATA IN  (host<--ioc<--dev) */1358	} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {1359		datalen = scsi_bufflen(SCpnt);1360		scsidir = MPI_SCSIIO_CONTROL_WRITE;	/* DATA OUT (host-->ioc-->dev) */1361	} else {1362		datalen = 0;1363		scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;1364	}1365 1366	/* Default to untagged. Once a target structure has been allocated,1367	 * use the Inquiry data to determine if device supports tagged.1368	 */1369	if ((vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) &&1370	    SCpnt->device->tagged_supported)1371		scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;1372	else1373		scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;1374 1375 1376	/* Use the above information to set up the message frame1377	 */1378	pScsiReq->TargetID = (u8) vdevice->vtarget->id;1379	pScsiReq->Bus = vdevice->vtarget->channel;1380	pScsiReq->ChainOffset = 0;1381	if (vdevice->vtarget->tflags &  MPT_TARGET_FLAGS_RAID_COMPONENT)1382		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;1383	else1384		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;1385	pScsiReq->CDBLength = SCpnt->cmd_len;1386	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;1387	pScsiReq->Reserved = 0;1388	pScsiReq->MsgFlags = mpt_msg_flags(ioc);1389	int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);1390	pScsiReq->Control = cpu_to_le32(scsictl);1391 1392	/*1393	 *  Write SCSI CDB into the message1394	 */1395	cmd_len = SCpnt->cmd_len;1396	for (ii=0; ii < cmd_len; ii++)1397		pScsiReq->CDB[ii] = SCpnt->cmnd[ii];1398 1399	for (ii=cmd_len; ii < 16; ii++)1400		pScsiReq->CDB[ii] = 0;1401 1402	/* DataLength */1403	pScsiReq->DataLength = cpu_to_le32(datalen);1404 1405	/* SenseBuffer low address */1406	pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma1407					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));1408 1409	/* Now add the SG list1410	 * Always have a SGE even if null length.1411	 */1412	if (datalen == 0) {1413		/* Add a NULL SGE */1414		ioc->add_sge((char *)&pScsiReq->SGL,1415			MPT_SGE_FLAGS_SSIMPLE_READ | 0,1416			(dma_addr_t) -1);1417	} else {1418		/* Add a 32 or 64 bit SGE */1419		if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)1420			goto fail;1421	}1422 1423	SCpnt->host_scribble = (unsigned char *)mf;1424	mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);1425 1426	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);1427	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",1428			ioc->name, SCpnt, mf, my_idx));1429	DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);1430	return 0;1431 1432 fail:1433	mptscsih_freeChainBuffers(ioc, my_idx);1434	mpt_free_msg_frame(ioc, mf);1435	return SCSI_MLQUEUE_HOST_BUSY;1436}1437 1438/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1439/*1440 *	mptscsih_freeChainBuffers - Function to free chain buffers associated1441 *	with a SCSI IO request1442 *	@hd: Pointer to the MPT_SCSI_HOST instance1443 *	@req_idx: Index of the SCSI IO request frame.1444 *1445 *	Called if SG chain buffer allocation fails and mptscsih callbacks.1446 *	No return.1447 */1448static void1449mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)1450{1451	MPT_FRAME_HDR *chain;1452	unsigned long flags;1453	int chain_idx;1454	int next;1455 1456	/* Get the first chain index and reset1457	 * tracker state.1458	 */1459	chain_idx = ioc->ReqToChain[req_idx];1460	ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;1461 1462	while (chain_idx != MPT_HOST_NO_CHAIN) {1463 1464		/* Save the next chain buffer index */1465		next = ioc->ChainToChain[chain_idx];1466 1467		/* Free this chain buffer and reset1468		 * tracker1469		 */1470		ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;1471 1472		chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer1473					+ (chain_idx * ioc->req_sz));1474 1475		spin_lock_irqsave(&ioc->FreeQlock, flags);1476		list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);1477		spin_unlock_irqrestore(&ioc->FreeQlock, flags);1478 1479		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",1480				ioc->name, chain_idx));1481 1482		/* handle next */1483		chain_idx = next;1484	}1485	return;1486}1487 1488/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1489/*1490 *	Reset Handling1491 */1492 1493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1494/**1495 *	mptscsih_IssueTaskMgmt - Generic send Task Management function.1496 *	@hd: Pointer to MPT_SCSI_HOST structure1497 *	@type: Task Management type1498 *	@channel: channel number for task management1499 *	@id: Logical Target ID for reset (if appropriate)1500 *	@lun: Logical Unit for reset (if appropriate)1501 *	@ctx2abort: Context for the task to be aborted (if appropriate)1502 *	@timeout: timeout for task management control1503 *1504 *	Remark: _HardResetHandler can be invoked from an interrupt thread (timer)1505 *	or a non-interrupt thread.  In the former, must not call schedule().1506 *1507 *	Not all fields are meaningfull for all task types.1508 *1509 *	Returns 0 for SUCCESS, or FAILED.1510 *1511 **/1512int1513mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, u64 lun,1514	int ctx2abort, ulong timeout)1515{1516	MPT_FRAME_HDR	*mf;1517	SCSITaskMgmt_t	*pScsiTm;1518	int		 ii;1519	int		 retval;1520	MPT_ADAPTER 	*ioc = hd->ioc;1521	u8		 issue_hard_reset;1522	u32		 ioc_raw_state;1523	unsigned long	 time_count;1524 1525	issue_hard_reset = 0;1526	ioc_raw_state = mpt_GetIocState(ioc, 0);1527 1528	if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {1529		printk(MYIOC_s_WARN_FMT1530			"TaskMgmt type=%x: IOC Not operational (0x%x)!\n",1531			ioc->name, type, ioc_raw_state);1532		printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",1533		    ioc->name, __func__);1534		if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)1535			printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "1536			    "FAILED!!\n", ioc->name);1537		return 0;1538	}1539 1540	/* DOORBELL ACTIVE check is not required if1541	*  MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q is supported.1542	*/1543 1544	if (!((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q)1545		 && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) &&1546		(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {1547		printk(MYIOC_s_WARN_FMT1548			"TaskMgmt type=%x: ioc_state: "1549			"DOORBELL_ACTIVE (0x%x)!\n",1550			ioc->name, type, ioc_raw_state);1551		return FAILED;1552	}1553 1554	mutex_lock(&ioc->taskmgmt_cmds.mutex);1555	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {1556		mf = NULL;1557		retval = FAILED;1558		goto out;1559	}1560 1561	/* Return Fail to calling function if no message frames available.1562	 */1563	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {1564		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT1565			"TaskMgmt no msg frames!!\n", ioc->name));1566		retval = FAILED;1567		mpt_clear_taskmgmt_in_progress_flag(ioc);1568		goto out;1569	}1570	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",1571			ioc->name, mf));1572 1573	/* Format the Request1574	 */1575	pScsiTm = (SCSITaskMgmt_t *) mf;1576	pScsiTm->TargetID = id;1577	pScsiTm->Bus = channel;1578	pScsiTm->ChainOffset = 0;1579	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;1580 1581	pScsiTm->Reserved = 0;1582	pScsiTm->TaskType = type;1583	pScsiTm->Reserved1 = 0;1584	pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)1585                    ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;1586 1587	int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);1588 1589	for (ii=0; ii < 7; ii++)1590		pScsiTm->Reserved2[ii] = 0;1591 1592	pScsiTm->TaskMsgContext = ctx2abort;1593 1594	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "1595		"task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,1596		type, timeout));1597 1598	DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);1599 1600	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)1601	time_count = jiffies;1602	if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&1603	    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))1604		mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);1605	else {1606		retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,1607			sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);1608		if (retval) {1609			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT1610				"TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",1611				ioc->name, mf, retval));1612			mpt_free_msg_frame(ioc, mf);1613			mpt_clear_taskmgmt_in_progress_flag(ioc);1614			goto out;1615		}1616	}1617 1618	wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,1619		timeout*HZ);1620	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {1621		retval = FAILED;1622		dtmprintk(ioc, printk(MYIOC_s_ERR_FMT1623		    "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));1624		mpt_clear_taskmgmt_in_progress_flag(ioc);1625		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)1626			goto out;1627		issue_hard_reset = 1;1628		goto out;1629	}1630 1631	retval = mptscsih_taskmgmt_reply(ioc, type,1632	    (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);1633 1634	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT1635	    "TaskMgmt completed (%d seconds)\n",1636	    ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));1637 1638 out:1639 1640	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)1641	if (issue_hard_reset) {1642		printk(MYIOC_s_WARN_FMT1643		       "Issuing Reset from %s!! doorbell=0x%08x\n",1644		       ioc->name, __func__, mpt_GetIocState(ioc, 0));1645		retval = (ioc->bus_type == SAS) ?1646			mpt_HardResetHandler(ioc, CAN_SLEEP) :1647			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);1648		mpt_free_msg_frame(ioc, mf);1649	}1650 1651	retval = (retval == 0) ? 0 : FAILED;1652	mutex_unlock(&ioc->taskmgmt_cmds.mutex);1653	return retval;1654}1655EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);1656 1657static int1658mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)1659{1660	switch (ioc->bus_type) {1661	case FC:1662		return 40;1663	case SAS:1664		return 30;1665	case SPI:1666	default:1667		return 10;1668	}1669}1670 1671/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1672/**1673 *	mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant1674 *	@SCpnt: Pointer to scsi_cmnd structure, IO to be aborted1675 *1676 *	(linux scsi_host_template.eh_abort_handler routine)1677 *1678 *	Returns SUCCESS or FAILED.1679 **/1680int1681mptscsih_abort(struct scsi_cmnd * SCpnt)1682{1683	MPT_SCSI_HOST	*hd;1684	MPT_FRAME_HDR	*mf;1685	u32		 ctx2abort;1686	int		 scpnt_idx;1687	int		 retval;1688	VirtDevice	 *vdevice;1689	MPT_ADAPTER	*ioc;1690 1691	/* If we can't locate our host adapter structure, return FAILED status.1692	 */1693	if ((hd = shost_priv(SCpnt->device->host)) == NULL) {1694		SCpnt->result = DID_RESET << 16;1695		scsi_done(SCpnt);1696		printk(KERN_ERR MYNAM ": task abort: "1697		    "can't locate host! (sc=%p)\n", SCpnt);1698		return FAILED;1699	}1700 1701	ioc = hd->ioc;1702	printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",1703	       ioc->name, SCpnt);1704	scsi_print_command(SCpnt);1705 1706	vdevice = SCpnt->device->hostdata;1707	if (!vdevice || !vdevice->vtarget) {1708		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT1709		    "task abort: device has been deleted (sc=%p)\n",1710		    ioc->name, SCpnt));1711		SCpnt->result = DID_NO_CONNECT << 16;1712		scsi_done(SCpnt);1713		retval = SUCCESS;1714		goto out;1715	}1716 1717	/* Task aborts are not supported for hidden raid components.1718	 */1719	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {1720		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT1721		    "task abort: hidden raid component (sc=%p)\n",1722		    ioc->name, SCpnt));1723		SCpnt->result = DID_RESET << 16;1724		retval = FAILED;1725		goto out;1726	}1727 1728	/* Task aborts are not supported for volumes.1729	 */1730	if (vdevice->vtarget->raidVolume) {1731		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT1732		    "task abort: raid volume (sc=%p)\n",1733		    ioc->name, SCpnt));1734		SCpnt->result = DID_RESET << 16;1735		retval = FAILED;1736		goto out;1737	}1738 1739	/* Find this command1740	 */1741	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {1742		/* Cmd not found in ScsiLookup.1743		 * Do OS callback.1744		 */1745		SCpnt->result = DID_RESET << 16;1746		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "1747		   "Command not in the active list! (sc=%p)\n", ioc->name,1748		   SCpnt));1749		retval = SUCCESS;1750		goto out;1751	}1752 1753	if (ioc->timeouts < -1)1754		ioc->timeouts++;1755 1756	if (mpt_fwfault_debug)1757		mpt_halt_firmware(ioc);1758 1759	/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!1760	 * (the IO to be ABORT'd)1761	 *1762	 * NOTE: Since we do not byteswap MsgContext, we do not1763	 *	 swap it here either.  It is an opaque cookie to1764	 *	 the controller, so it does not matter. -DaveM1765	 */1766	mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);1767	ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;1768	retval = mptscsih_IssueTaskMgmt(hd,1769			 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,1770			 vdevice->vtarget->channel,1771			 vdevice->vtarget->id, vdevice->lun,1772			 ctx2abort, mptscsih_get_tm_timeout(ioc));1773 1774	if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) {1775		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT1776		    "task abort: command still in active list! (sc=%p)\n",1777		    ioc->name, SCpnt));1778		retval = FAILED;1779	} else {1780		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT1781		    "task abort: command cleared from active list! (sc=%p)\n",1782		    ioc->name, SCpnt));1783		retval = SUCCESS;1784	}1785 1786 out:1787	printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n",1788	    ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,1789	    SCpnt);1790 1791	return retval;1792}1793 1794/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1795/**1796 *	mptscsih_dev_reset - Perform a SCSI LOGICAL_UNIT_RESET!1797 *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to1798 *1799 *	(linux scsi_host_template.eh_dev_reset_handler routine)1800 *1801 *	Returns SUCCESS or FAILED.1802 **/1803int1804mptscsih_dev_reset(struct scsi_cmnd * SCpnt)1805{1806	MPT_SCSI_HOST	*hd;1807	int		 retval;1808	VirtDevice	 *vdevice;1809	MPT_ADAPTER	*ioc;1810 1811	/* If we can't locate our host adapter structure, return FAILED status.1812	 */1813	if ((hd = shost_priv(SCpnt->device->host)) == NULL){1814		printk(KERN_ERR MYNAM ": lun reset: "1815		   "Can't locate host! (sc=%p)\n", SCpnt);1816		return FAILED;1817	}1818 1819	ioc = hd->ioc;1820	printk(MYIOC_s_INFO_FMT "attempting lun reset! (sc=%p)\n",1821	       ioc->name, SCpnt);1822	scsi_print_command(SCpnt);1823 1824	vdevice = SCpnt->device->hostdata;1825	if (!vdevice || !vdevice->vtarget) {1826		retval = 0;1827		goto out;1828	}1829 1830	retval = mptscsih_IssueTaskMgmt(hd,1831				MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET,1832				vdevice->vtarget->channel,1833				vdevice->vtarget->id, vdevice->lun, 0,1834				mptscsih_get_tm_timeout(ioc));1835 1836 out:1837	printk (MYIOC_s_INFO_FMT "lun reset: %s (sc=%p)\n",1838	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);1839 1840	if (retval == 0)1841		return SUCCESS;1842	else1843		return FAILED;1844}1845 1846/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1847/**1848 *	mptscsih_target_reset - Perform a SCSI TARGET_RESET!1849 *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to1850 *1851 *	(linux scsi_host_template.eh_target_reset_handler routine)1852 *1853 *	Returns SUCCESS or FAILED.1854 **/1855int1856mptscsih_target_reset(struct scsi_cmnd * SCpnt)1857{1858	MPT_SCSI_HOST	*hd;1859	int		 retval;1860	VirtDevice	 *vdevice;1861	MPT_ADAPTER	*ioc;1862 1863	/* If we can't locate our host adapter structure, return FAILED status.1864	 */1865	if ((hd = shost_priv(SCpnt->device->host)) == NULL){1866		printk(KERN_ERR MYNAM ": target reset: "1867		   "Can't locate host! (sc=%p)\n", SCpnt);1868		return FAILED;1869	}1870 1871	ioc = hd->ioc;1872	printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",1873	       ioc->name, SCpnt);1874	scsi_print_command(SCpnt);1875 1876	vdevice = SCpnt->device->hostdata;1877	if (!vdevice || !vdevice->vtarget) {1878		retval = 0;1879		goto out;1880	}1881 1882	/* Target reset to hidden raid component is not supported1883	 */1884	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {1885		retval = FAILED;1886		goto out;1887	}1888 1889	retval = mptscsih_IssueTaskMgmt(hd,1890				MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,1891				vdevice->vtarget->channel,1892				vdevice->vtarget->id, 0, 0,1893				mptscsih_get_tm_timeout(ioc));1894 1895 out:1896	printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",1897	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);1898 1899	if (retval == 0)1900		return SUCCESS;1901	else1902		return FAILED;1903}1904 1905 1906/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1907/**1908 *	mptscsih_bus_reset - Perform a SCSI BUS_RESET!	new_eh variant1909 *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to1910 *1911 *	(linux scsi_host_template.eh_bus_reset_handler routine)1912 *1913 *	Returns SUCCESS or FAILED.1914 **/1915int1916mptscsih_bus_reset(struct scsi_cmnd * SCpnt)1917{1918	MPT_SCSI_HOST	*hd;1919	int		 retval;1920	VirtDevice	 *vdevice;1921	MPT_ADAPTER	*ioc;1922 1923	/* If we can't locate our host adapter structure, return FAILED status.1924	 */1925	if ((hd = shost_priv(SCpnt->device->host)) == NULL){1926		printk(KERN_ERR MYNAM ": bus reset: "1927		   "Can't locate host! (sc=%p)\n", SCpnt);1928		return FAILED;1929	}1930 1931	ioc = hd->ioc;1932	printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",1933	       ioc->name, SCpnt);1934	scsi_print_command(SCpnt);1935 1936	if (ioc->timeouts < -1)1937		ioc->timeouts++;1938 1939	vdevice = SCpnt->device->hostdata;1940	if (!vdevice || !vdevice->vtarget)1941		return SUCCESS;1942	retval = mptscsih_IssueTaskMgmt(hd,1943					MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,1944					vdevice->vtarget->channel, 0, 0, 0,1945					mptscsih_get_tm_timeout(ioc));1946 1947	printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",1948	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);1949 1950	if (retval == 0)1951		return SUCCESS;1952	else1953		return FAILED;1954}1955 1956/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1957/**1958 *	mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)1959 *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to1960 *1961 *	(linux scsi_host_template.eh_host_reset_handler routine)1962 *1963 *	Returns SUCCESS or FAILED.1964 */1965int1966mptscsih_host_reset(struct scsi_cmnd *SCpnt)1967{1968	MPT_SCSI_HOST *  hd;1969	int              status = SUCCESS;1970	MPT_ADAPTER	*ioc;1971	int		retval;1972 1973	/*  If we can't locate the host to reset, then we failed. */1974	if ((hd = shost_priv(SCpnt->device->host)) == NULL){1975		printk(KERN_ERR MYNAM ": host reset: "1976		    "Can't locate host! (sc=%p)\n", SCpnt);1977		return FAILED;1978	}1979 1980	/* make sure we have no outstanding commands at this stage */1981	mptscsih_flush_running_cmds(hd);1982 1983	ioc = hd->ioc;1984	printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",1985	    ioc->name, SCpnt);1986 1987	/*  If our attempts to reset the host failed, then return a failed1988	 *  status.  The host will be taken off line by the SCSI mid-layer.1989	 */1990	retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);1991	if (retval < 0)1992		status = FAILED;1993	else1994		status = SUCCESS;1995 1996	printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",1997	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);1998 1999	return status;2000}2001 2002static int2003mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,2004	SCSITaskMgmtReply_t *pScsiTmReply)2005{2006	u16			 iocstatus;2007	u32			 termination_count;2008	int			 retval;2009 2010	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {2011		retval = FAILED;2012		goto out;2013	}2014 2015	DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);2016 2017	iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;2018	termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);2019 2020	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT2021	    "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"2022	    "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"2023	    "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,2024	    pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),2025	    le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,2026	    termination_count));2027 2028	if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&2029	    pScsiTmReply->ResponseCode)2030		mptscsih_taskmgmt_response_code(ioc,2031		    pScsiTmReply->ResponseCode);2032 2033	if (iocstatus == MPI_IOCSTATUS_SUCCESS) {2034		retval = 0;2035		goto out;2036	}2037 2038	retval = FAILED;2039	if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {2040		if (termination_count == 1)2041			retval = 0;2042		goto out;2043	}2044 2045	if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||2046	   iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)2047		retval = 0;2048 2049 out:2050	return retval;2051}2052 2053/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2054void2055mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)2056{2057	char *desc;2058 2059	switch (response_code) {2060	case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:2061		desc = "The task completed.";2062		break;2063	case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:2064		desc = "The IOC received an invalid frame status.";2065		break;2066	case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:2067		desc = "The task type is not supported.";2068		break;2069	case MPI_SCSITASKMGMT_RSP_TM_FAILED:2070		desc = "The requested task failed.";2071		break;2072	case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:2073		desc = "The task completed successfully.";2074		break;2075	case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:2076		desc = "The LUN request is invalid.";2077		break;2078	case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:2079		desc = "The task is in the IOC queue and has not been sent to target.";2080		break;2081	default:2082		desc = "unknown";2083		break;2084	}2085	printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",2086		ioc->name, response_code, desc);2087}2088EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);2089 2090/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2091/**2092 *	mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver2093 *	@ioc: Pointer to MPT_ADAPTER structure2094 *	@mf: Pointer to SCSI task mgmt request frame2095 *	@mr: Pointer to SCSI task mgmt reply frame2096 *2097 *	This routine is called from mptbase.c::mpt_interrupt() at the completion2098 *	of any SCSI task management request.2099 *	This routine is registered with the MPT (base) driver at driver2100 *	load/init time via the mpt_register() API call.2101 *2102 *	Returns 1 indicating alloc'd request frame ptr should be freed.2103 **/2104int2105mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,2106	MPT_FRAME_HDR *mr)2107{2108	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT2109		"TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));2110 2111	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;2112 2113	if (!mr)2114		goto out;2115 2116	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;2117	memcpy(ioc->taskmgmt_cmds.reply, mr,2118	    min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));2119 out:2120	if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {2121		mpt_clear_taskmgmt_in_progress_flag(ioc);2122		ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;2123		complete(&ioc->taskmgmt_cmds.done);2124		if (ioc->bus_type == SAS)2125			ioc->schedule_target_reset(ioc);2126		return 1;2127	}2128	return 0;2129}2130 2131/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2132/*2133 *	This is anyones guess quite frankly.2134 */2135int2136mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,2137		sector_t capacity, int geom[])2138{2139	int		heads;2140	int		sectors;2141	sector_t	cylinders;2142	ulong 		dummy;2143 2144	heads = 64;2145	sectors = 32;2146 2147	dummy = heads * sectors;2148	cylinders = capacity;2149	sector_div(cylinders,dummy);2150 2151	/*2152	 * Handle extended translation size for logical drives2153	 * > 1Gb2154	 */2155	if ((ulong)capacity >= 0x200000) {2156		heads = 255;2157		sectors = 63;2158		dummy = heads * sectors;2159		cylinders = capacity;2160		sector_div(cylinders,dummy);2161	}2162 2163	/* return result */2164	geom[0] = heads;2165	geom[1] = sectors;2166	geom[2] = cylinders;2167 2168	return 0;2169}2170 2171/* Search IOC page 3 to determine if this is hidden physical disk2172 *2173 */2174int2175mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)2176{2177	struct inactive_raid_component_info *component_info;2178	int i, j;2179	RaidPhysDiskPage1_t *phys_disk;2180	int rc = 0;2181	int num_paths;2182 2183	if (!ioc->raid_data.pIocPg3)2184		goto out;2185	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {2186		if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&2187		    (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {2188			rc = 1;2189			goto out;2190		}2191	}2192 2193	if (ioc->bus_type != SAS)2194		goto out;2195 2196	/*2197	 * Check if dual path2198	 */2199	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {2200		num_paths = mpt_raid_phys_disk_get_num_paths(ioc,2201		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);2202		if (num_paths < 2)2203			continue;2204		phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +2205		   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);2206		if (!phys_disk)2207			continue;2208		if ((mpt_raid_phys_disk_pg1(ioc,2209		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,2210		    phys_disk))) {2211			kfree(phys_disk);2212			continue;2213		}2214		for (j = 0; j < num_paths; j++) {2215			if ((phys_disk->Path[j].Flags &2216			    MPI_RAID_PHYSDISK1_FLAG_INVALID))2217				continue;2218			if ((phys_disk->Path[j].Flags &2219			    MPI_RAID_PHYSDISK1_FLAG_BROKEN))2220				continue;2221			if ((id == phys_disk->Path[j].PhysDiskID) &&2222			    (channel == phys_disk->Path[j].PhysDiskBus)) {2223				rc = 1;2224				kfree(phys_disk);2225				goto out;2226			}2227		}2228		kfree(phys_disk);2229	}2230 2231 2232	/*2233	 * Check inactive list for matching phys disks2234	 */2235	if (list_empty(&ioc->raid_data.inactive_list))2236		goto out;2237 2238	mutex_lock(&ioc->raid_data.inactive_list_mutex);2239	list_for_each_entry(component_info, &ioc->raid_data.inactive_list,2240	    list) {2241		if ((component_info->d.PhysDiskID == id) &&2242		    (component_info->d.PhysDiskBus == channel))2243			rc = 1;2244	}2245	mutex_unlock(&ioc->raid_data.inactive_list_mutex);2246 2247 out:2248	return rc;2249}2250EXPORT_SYMBOL(mptscsih_is_phys_disk);2251 2252u82253mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)2254{2255	struct inactive_raid_component_info *component_info;2256	int i, j;2257	RaidPhysDiskPage1_t *phys_disk;2258	int rc = -ENXIO;2259	int num_paths;2260 2261	if (!ioc->raid_data.pIocPg3)2262		goto out;2263	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {2264		if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&2265		    (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {2266			rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;2267			goto out;2268		}2269	}2270 2271	if (ioc->bus_type != SAS)2272		goto out;2273 2274	/*2275	 * Check if dual path2276	 */2277	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {2278		num_paths = mpt_raid_phys_disk_get_num_paths(ioc,2279		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);2280		if (num_paths < 2)2281			continue;2282		phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +2283		   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);2284		if (!phys_disk)2285			continue;2286		if ((mpt_raid_phys_disk_pg1(ioc,2287		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,2288		    phys_disk))) {2289			kfree(phys_disk);2290			continue;2291		}2292		for (j = 0; j < num_paths; j++) {2293			if ((phys_disk->Path[j].Flags &2294			    MPI_RAID_PHYSDISK1_FLAG_INVALID))2295				continue;2296			if ((phys_disk->Path[j].Flags &2297			    MPI_RAID_PHYSDISK1_FLAG_BROKEN))2298				continue;2299			if ((id == phys_disk->Path[j].PhysDiskID) &&2300			    (channel == phys_disk->Path[j].PhysDiskBus)) {2301				rc = phys_disk->PhysDiskNum;2302				kfree(phys_disk);2303				goto out;2304			}2305		}2306		kfree(phys_disk);2307	}2308 2309	/*2310	 * Check inactive list for matching phys disks2311	 */2312	if (list_empty(&ioc->raid_data.inactive_list))2313		goto out;2314 2315	mutex_lock(&ioc->raid_data.inactive_list_mutex);2316	list_for_each_entry(component_info, &ioc->raid_data.inactive_list,2317	    list) {2318		if ((component_info->d.PhysDiskID == id) &&2319		    (component_info->d.PhysDiskBus == channel))2320			rc = component_info->d.PhysDiskNum;2321	}2322	mutex_unlock(&ioc->raid_data.inactive_list_mutex);2323 2324 out:2325	return rc;2326}2327EXPORT_SYMBOL(mptscsih_raid_id_to_num);2328 2329/*2330 *	OS entry point to allow for host driver to free allocated memory2331 *	Called if no device present or device being unloaded2332 */2333void2334mptscsih_slave_destroy(struct scsi_device *sdev)2335{2336	struct Scsi_Host	*host = sdev->host;2337	MPT_SCSI_HOST		*hd = shost_priv(host);2338	VirtTarget		*vtarget;2339	VirtDevice		*vdevice;2340	struct scsi_target 	*starget;2341 2342	starget = scsi_target(sdev);2343	vtarget = starget->hostdata;2344	vdevice = sdev->hostdata;2345	if (!vdevice)2346		return;2347 2348	mptscsih_search_running_cmds(hd, vdevice);2349	vtarget->num_luns--;2350	mptscsih_synchronize_cache(hd, vdevice);2351	kfree(vdevice);2352	sdev->hostdata = NULL;2353}2354 2355/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2356/*2357 *	mptscsih_change_queue_depth - This function will set a devices queue depth2358 *	@sdev: per scsi_device pointer2359 *	@qdepth: requested queue depth2360 *2361 *	Adding support for new 'change_queue_depth' api.2362*/2363int2364mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)2365{2366	MPT_SCSI_HOST		*hd = shost_priv(sdev->host);2367	VirtTarget 		*vtarget;2368	struct scsi_target 	*starget;2369	int			max_depth;2370	MPT_ADAPTER		*ioc = hd->ioc;2371 2372	starget = scsi_target(sdev);2373	vtarget = starget->hostdata;2374 2375	if (ioc->bus_type == SPI) {2376		if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))2377			max_depth = 1;2378		else if (sdev->type == TYPE_DISK &&2379			 vtarget->minSyncFactor <= MPT_ULTRA160)2380			max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;2381		else2382			max_depth = MPT_SCSI_CMD_PER_DEV_LOW;2383	} else2384		 max_depth = ioc->sh->can_queue;2385 2386	if (!sdev->tagged_supported)2387		max_depth = 1;2388 2389	if (qdepth > max_depth)2390		qdepth = max_depth;2391 2392	return scsi_change_queue_depth(sdev, qdepth);2393}2394 2395/*2396 *	OS entry point to adjust the queue_depths on a per-device basis.2397 *	Called once per device the bus scan. Use it to force the queue_depth2398 *	member to 1 if a device does not support Q tags.2399 *	Return non-zero if fails.2400 */2401int2402mptscsih_slave_configure(struct scsi_device *sdev)2403{2404	struct Scsi_Host	*sh = sdev->host;2405	VirtTarget		*vtarget;2406	VirtDevice		*vdevice;2407	struct scsi_target 	*starget;2408	MPT_SCSI_HOST		*hd = shost_priv(sh);2409	MPT_ADAPTER		*ioc = hd->ioc;2410 2411	starget = scsi_target(sdev);2412	vtarget = starget->hostdata;2413	vdevice = sdev->hostdata;2414 2415	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT2416		"device @ %p, channel=%d, id=%d, lun=%llu\n",2417		ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));2418	if (ioc->bus_type == SPI)2419		dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT2420		    "sdtr %d wdtr %d ppr %d inq length=%d\n",2421		    ioc->name, sdev->sdtr, sdev->wdtr,2422		    sdev->ppr, sdev->inquiry_len));2423 2424	vdevice->configured_lun = 1;2425 2426	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT2427		"Queue depth=%d, tflags=%x\n",2428		ioc->name, sdev->queue_depth, vtarget->tflags));2429 2430	if (ioc->bus_type == SPI)2431		dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT2432		    "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",2433		    ioc->name, vtarget->negoFlags, vtarget->maxOffset,2434		    vtarget->minSyncFactor));2435 2436	mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);2437	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT2438		"tagged %d, simple %d\n",2439		ioc->name,sdev->tagged_supported, sdev->simple_tags));2440 2441	return 0;2442}2443 2444/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2445/*2446 *  Private routines...2447 */2448 2449/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2450/* Utility function to copy sense data from the scsi_cmnd buffer2451 * to the FC and SCSI target structures.2452 *2453 */2454static void2455mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)2456{2457	VirtDevice	*vdevice;2458	SCSIIORequest_t	*pReq;2459	u32		 sense_count = le32_to_cpu(pScsiReply->SenseCount);2460	MPT_ADAPTER 	*ioc = hd->ioc;2461 2462	/* Get target structure2463	 */2464	pReq = (SCSIIORequest_t *) mf;2465	vdevice = sc->device->hostdata;2466 2467	if (sense_count) {2468		u8 *sense_data;2469		int req_index;2470 2471		/* Copy the sense received into the scsi command block. */2472		req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);2473		sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));2474		memcpy(sc->sense_buffer, sense_data, MPT_SENSE_BUFFER_ALLOC);2475 2476		/* Log SMART data (asc = 0x5D, non-IM case only) if required.2477		 */2478		if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {2479			if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {2480				int idx;2481 2482				idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;2483				ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;2484				ioc->events[idx].eventContext = ioc->eventContext;2485 2486				ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |2487					(MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |2488					(sc->device->channel << 8) | sc->device->id;2489 2490				ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];2491 2492				ioc->eventContext++;2493				if (ioc->pcidev->vendor ==2494				    PCI_VENDOR_ID_IBM) {2495					mptscsih_issue_sep_command(ioc,2496					    vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);2497					vdevice->vtarget->tflags |=2498					    MPT_TARGET_FLAGS_LED_ON;2499				}2500			}2501		}2502	} else {2503		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",2504				ioc->name));2505	}2506}2507 2508/**2509 * mptscsih_get_scsi_lookup - retrieves scmd entry2510 * @ioc: Pointer to MPT_ADAPTER structure2511 * @i: index into the array2512 *2513 * Returns the scsi_cmd pointer2514 */2515struct scsi_cmnd *2516mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)2517{2518	unsigned long	flags;2519	struct scsi_cmnd *scmd;2520 2521	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);2522	scmd = ioc->ScsiLookup[i];2523	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);2524 2525	return scmd;2526}2527EXPORT_SYMBOL(mptscsih_get_scsi_lookup);2528 2529/**2530 * mptscsih_getclear_scsi_lookup -  retrieves and clears scmd entry from ScsiLookup[] array list2531 * @ioc: Pointer to MPT_ADAPTER structure2532 * @i: index into the array2533 *2534 * Returns the scsi_cmd pointer2535 *2536 **/2537static struct scsi_cmnd *2538mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)2539{2540	unsigned long	flags;2541	struct scsi_cmnd *scmd;2542 2543	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);2544	scmd = ioc->ScsiLookup[i];2545	ioc->ScsiLookup[i] = NULL;2546	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);2547 2548	return scmd;2549}2550 2551/**2552 * mptscsih_set_scsi_lookup - write a scmd entry into the ScsiLookup[] array list2553 *2554 * @ioc: Pointer to MPT_ADAPTER structure2555 * @i: index into the array2556 * @scmd: scsi_cmnd pointer2557 *2558 **/2559static void2560mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)2561{2562	unsigned long	flags;2563 2564	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);2565	ioc->ScsiLookup[i] = scmd;2566	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);2567}2568 2569/**2570 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list2571 * @ioc: Pointer to MPT_ADAPTER structure2572 * @sc: scsi_cmnd pointer2573 */2574static int2575SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)2576{2577	unsigned long	flags;2578	int i, index=-1;2579 2580	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);2581	for (i = 0; i < ioc->req_depth; i++) {2582		if (ioc->ScsiLookup[i] == sc) {2583			index = i;2584			goto out;2585		}2586	}2587 2588 out:2589	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);2590	return index;2591}2592 2593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2594int2595mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)2596{2597	MPT_SCSI_HOST	*hd;2598 2599	if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)2600		return 0;2601 2602	hd = shost_priv(ioc->sh);2603	switch (reset_phase) {2604	case MPT_IOC_SETUP_RESET:2605		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT2606		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));2607		break;2608	case MPT_IOC_PRE_RESET:2609		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT2610		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));2611		mptscsih_flush_running_cmds(hd);2612		break;2613	case MPT_IOC_POST_RESET:2614		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT2615		    "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));2616		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {2617			ioc->internal_cmds.status |=2618				MPT_MGMT_STATUS_DID_IOCRESET;2619			complete(&ioc->internal_cmds.done);2620		}2621		break;2622	default:2623		break;2624	}2625	return 1;		/* currently means nothing really */2626}2627 2628/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2629int2630mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)2631{2632	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;2633 2634	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT2635		"MPT event (=%02Xh) routed to SCSI host driver!\n",2636		ioc->name, event));2637 2638	if ((event == MPI_EVENT_IOC_BUS_RESET ||2639	    event == MPI_EVENT_EXT_BUS_RESET) &&2640	    (ioc->bus_type == SPI) && (ioc->soft_resets < -1))2641			ioc->soft_resets++;2642 2643	return 1;		/* currently means nothing really */2644}2645 2646/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2647/*2648 *  Bus Scan and Domain Validation functionality ...2649 */2650 2651/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2652/*2653 *	mptscsih_scandv_complete - Scan and DV callback routine registered2654 *	to Fustion MPT (base) driver.2655 *2656 *	@ioc: Pointer to MPT_ADAPTER structure2657 *	@mf: Pointer to original MPT request frame2658 *	@mr: Pointer to MPT reply frame (NULL if TurboReply)2659 *2660 *	This routine is called from mpt.c::mpt_interrupt() at the completion2661 *	of any SCSI IO request.2662 *	This routine is registered with the Fusion MPT (base) driver at driver2663 *	load/init time via the mpt_register() API call.2664 *2665 *	Returns 1 indicating alloc'd request frame ptr should be freed.2666 *2667 *	Remark: Sets a completion code and (possibly) saves sense data2668 *	in the IOC member localReply structure.2669 *	Used ONLY for DV and other internal commands.2670 */2671int2672mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,2673				MPT_FRAME_HDR *reply)2674{2675	SCSIIORequest_t *pReq;2676	SCSIIOReply_t	*pReply;2677	u8		 cmd;2678	u16		 req_idx;2679	u8	*sense_data;2680	int		 sz;2681 2682	ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;2683	ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;2684	if (!reply)2685		goto out;2686 2687	pReply = (SCSIIOReply_t *) reply;2688	pReq = (SCSIIORequest_t *) req;2689	ioc->internal_cmds.completion_code =2690	    mptscsih_get_completion_code(ioc, req, reply);2691	ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;2692	memcpy(ioc->internal_cmds.reply, reply,2693	    min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));2694	cmd = reply->u.hdr.Function;2695	if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||2696	    (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&2697	    (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {2698		req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);2699		sense_data = ((u8 *)ioc->sense_buf_pool +2700		    (req_idx * MPT_SENSE_BUFFER_ALLOC));2701		sz = min_t(int, pReq->SenseBufferLength,2702		    MPT_SENSE_BUFFER_ALLOC);2703		memcpy(ioc->internal_cmds.sense, sense_data, sz);2704	}2705 out:2706	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))2707		return 0;2708	ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;2709	complete(&ioc->internal_cmds.done);2710	return 1;2711}2712 2713 2714/**2715 *	mptscsih_get_completion_code - get completion code from MPT request2716 *	@ioc: Pointer to MPT_ADAPTER structure2717 *	@req: Pointer to original MPT request frame2718 *	@reply: Pointer to MPT reply frame (NULL if TurboReply)2719 *2720 **/2721static int2722mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,2723				MPT_FRAME_HDR *reply)2724{2725	SCSIIOReply_t	*pReply;2726	MpiRaidActionReply_t *pr;2727	u8		 scsi_status;2728	u16		 status;2729	int		 completion_code;2730 2731	pReply = (SCSIIOReply_t *)reply;2732	status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;2733	scsi_status = pReply->SCSIStatus;2734 2735	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT2736	    "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"2737	    "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,2738	    scsi_status, le32_to_cpu(pReply->IOCLogInfo)));2739 2740	switch (status) {2741 2742	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */2743		completion_code = MPT_SCANDV_SELECTION_TIMEOUT;2744		break;2745 2746	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */2747	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */2748	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */2749	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */2750		completion_code = MPT_SCANDV_DID_RESET;2751		break;2752 2753	case MPI_IOCSTATUS_BUSY:2754	case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:2755		completion_code = MPT_SCANDV_BUSY;2756		break;2757 2758	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */2759	case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */2760	case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */2761		if (pReply->Function == MPI_FUNCTION_CONFIG) {2762			completion_code = MPT_SCANDV_GOOD;2763		} else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {2764			pr = (MpiRaidActionReply_t *)reply;2765			if (le16_to_cpu(pr->ActionStatus) ==2766				MPI_RAID_ACTION_ASTATUS_SUCCESS)2767				completion_code = MPT_SCANDV_GOOD;2768			else2769				completion_code = MPT_SCANDV_SOME_ERROR;2770		} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)2771			completion_code = MPT_SCANDV_SENSE;2772		else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {2773			if (req->u.scsireq.CDB[0] == INQUIRY)2774				completion_code = MPT_SCANDV_ISSUE_SENSE;2775			else2776				completion_code = MPT_SCANDV_DID_RESET;2777		} else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)2778			completion_code = MPT_SCANDV_DID_RESET;2779		else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)2780			completion_code = MPT_SCANDV_DID_RESET;2781		else if (scsi_status == MPI_SCSI_STATUS_BUSY)2782			completion_code = MPT_SCANDV_BUSY;2783		else2784			completion_code = MPT_SCANDV_GOOD;2785		break;2786 2787	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */2788		if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)2789			completion_code = MPT_SCANDV_DID_RESET;2790		else2791			completion_code = MPT_SCANDV_SOME_ERROR;2792		break;2793	default:2794		completion_code = MPT_SCANDV_SOME_ERROR;2795		break;2796 2797	}	/* switch(status) */2798 2799	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT2800	    "  completionCode set to %08xh\n", ioc->name, completion_code));2801	return completion_code;2802}2803 2804/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2805/**2806 *	mptscsih_do_cmd - Do internal command.2807 *	@hd: MPT_SCSI_HOST pointer2808 *	@io: INTERNAL_CMD pointer.2809 *2810 *	Issue the specified internally generated command and do command2811 *	specific cleanup. For bus scan / DV only.2812 *	NOTES: If command is Inquiry and status is good,2813 *	initialize a target structure, save the data2814 *2815 *	Remark: Single threaded access only.2816 *2817 *	Return:2818 *		< 0 if an illegal command or no resources2819 *2820 *		   0 if good2821 *2822 *		 > 0 if command complete but some type of completion error.2823 */2824static int2825mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)2826{2827	MPT_FRAME_HDR	*mf;2828	SCSIIORequest_t	*pScsiReq;2829	int		 my_idx, ii, dir;2830	int		 timeout;2831	char		 cmdLen;2832	char		 CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};2833	u8		 cmd = io->cmd;2834	MPT_ADAPTER *ioc = hd->ioc;2835	int		 ret = 0;2836	unsigned long	 timeleft;2837	unsigned long	 flags;2838 2839	/* don't send internal command during diag reset */2840	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);2841	if (ioc->ioc_reset_in_progress) {2842		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);2843		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT2844			"%s: busy with host reset\n", ioc->name, __func__));2845		return MPT_SCANDV_BUSY;2846	}2847	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);2848 2849	mutex_lock(&ioc->internal_cmds.mutex);2850 2851	/* Set command specific information2852	 */2853	switch (cmd) {2854	case INQUIRY:2855		cmdLen = 6;2856		dir = MPI_SCSIIO_CONTROL_READ;2857		CDB[0] = cmd;2858		CDB[4] = io->size;2859		timeout = 10;2860		break;2861 2862	case TEST_UNIT_READY:2863		cmdLen = 6;2864		dir = MPI_SCSIIO_CONTROL_READ;2865		timeout = 10;2866		break;2867 2868	case START_STOP:2869		cmdLen = 6;2870		dir = MPI_SCSIIO_CONTROL_READ;2871		CDB[0] = cmd;2872		CDB[4] = 1;	/*Spin up the disk */2873		timeout = 15;2874		break;2875 2876	case REQUEST_SENSE:2877		cmdLen = 6;2878		CDB[0] = cmd;2879		CDB[4] = io->size;2880		dir = MPI_SCSIIO_CONTROL_READ;2881		timeout = 10;2882		break;2883 2884	case READ_BUFFER:2885		cmdLen = 10;2886		dir = MPI_SCSIIO_CONTROL_READ;2887		CDB[0] = cmd;2888		if (io->flags & MPT_ICFLAG_ECHO) {2889			CDB[1] = 0x0A;2890		} else {2891			CDB[1] = 0x02;2892		}2893 2894		if (io->flags & MPT_ICFLAG_BUF_CAP) {2895			CDB[1] |= 0x01;2896		}2897		CDB[6] = (io->size >> 16) & 0xFF;2898		CDB[7] = (io->size >>  8) & 0xFF;2899		CDB[8] = io->size & 0xFF;2900		timeout = 10;2901		break;2902 2903	case WRITE_BUFFER:2904		cmdLen = 10;2905		dir = MPI_SCSIIO_CONTROL_WRITE;2906		CDB[0] = cmd;2907		if (io->flags & MPT_ICFLAG_ECHO) {2908			CDB[1] = 0x0A;2909		} else {2910			CDB[1] = 0x02;2911		}2912		CDB[6] = (io->size >> 16) & 0xFF;2913		CDB[7] = (io->size >>  8) & 0xFF;2914		CDB[8] = io->size & 0xFF;2915		timeout = 10;2916		break;2917 2918	case RESERVE:2919		cmdLen = 6;2920		dir = MPI_SCSIIO_CONTROL_READ;2921		CDB[0] = cmd;2922		timeout = 10;2923		break;2924 2925	case RELEASE:2926		cmdLen = 6;2927		dir = MPI_SCSIIO_CONTROL_READ;2928		CDB[0] = cmd;2929		timeout = 10;2930		break;2931 2932	case SYNCHRONIZE_CACHE:2933		cmdLen = 10;2934		dir = MPI_SCSIIO_CONTROL_READ;2935		CDB[0] = cmd;2936//		CDB[1] = 0x02;	/* set immediate bit */2937		timeout = 10;2938		break;2939 2940	default:2941		/* Error Case */2942		ret = -EFAULT;2943		goto out;2944	}2945 2946	/* Get and Populate a free Frame2947	 * MsgContext set in mpt_get_msg_frame call2948	 */2949	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {2950		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",2951		    ioc->name, __func__));2952		ret = MPT_SCANDV_BUSY;2953		goto out;2954	}2955 2956	pScsiReq = (SCSIIORequest_t *) mf;2957 2958	/* Get the request index */2959	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);2960	ADD_INDEX_LOG(my_idx); /* for debug */2961 2962	if (io->flags & MPT_ICFLAG_PHYS_DISK) {2963		pScsiReq->TargetID = io->physDiskNum;2964		pScsiReq->Bus = 0;2965		pScsiReq->ChainOffset = 0;2966		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;2967	} else {2968		pScsiReq->TargetID = io->id;2969		pScsiReq->Bus = io->channel;2970		pScsiReq->ChainOffset = 0;2971		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;2972	}2973 2974	pScsiReq->CDBLength = cmdLen;2975	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;2976 2977	pScsiReq->Reserved = 0;2978 2979	pScsiReq->MsgFlags = mpt_msg_flags(ioc);2980	/* MsgContext set in mpt_get_msg_fram call  */2981 2982	int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);2983 2984	if (io->flags & MPT_ICFLAG_TAGGED_CMD)2985		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);2986	else2987		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);2988 2989	if (cmd == REQUEST_SENSE) {2990		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);2991		devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT2992		    "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));2993	}2994 2995	for (ii = 0; ii < 16; ii++)2996		pScsiReq->CDB[ii] = CDB[ii];2997 2998	pScsiReq->DataLength = cpu_to_le32(io->size);2999	pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma3000					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));3001 3002	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT3003	    "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%llu\n",3004	    ioc->name, __func__, cmd, io->channel, io->id, io->lun));3005 3006	if (dir == MPI_SCSIIO_CONTROL_READ)3007		ioc->add_sge((char *) &pScsiReq->SGL,3008		    MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);3009	else3010		ioc->add_sge((char *) &pScsiReq->SGL,3011		    MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);3012 3013	INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)3014	mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);3015	timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,3016	    timeout*HZ);3017	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {3018		ret = MPT_SCANDV_DID_RESET;3019		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT3020		    "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,3021		    cmd));3022		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {3023			mpt_free_msg_frame(ioc, mf);3024			goto out;3025		}3026		if (!timeleft) {3027			printk(MYIOC_s_WARN_FMT3028			       "Issuing Reset from %s!! doorbell=0x%08xh"3029			       " cmd=0x%02x\n",3030			       ioc->name, __func__, mpt_GetIocState(ioc, 0),3031			       cmd);3032			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);3033			mpt_free_msg_frame(ioc, mf);3034		}3035		goto out;3036	}3037 3038	ret = ioc->internal_cmds.completion_code;3039	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",3040			ioc->name, __func__, ret));3041 3042 out:3043	CLEAR_MGMT_STATUS(ioc->internal_cmds.status)3044	mutex_unlock(&ioc->internal_cmds.mutex);3045	return ret;3046}3047 3048/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/3049/**3050 *	mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.3051 *	@hd: Pointer to a SCSI HOST structure3052 *	@vdevice: virtual target device3053 *3054 *	Uses the ISR, but with special processing.3055 *	MUST be single-threaded.3056 *3057 */3058static void3059mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)3060{3061	INTERNAL_CMD		 iocmd;3062 3063	/* Ignore hidden raid components, this is handled when the command3064	 * is sent to the volume3065	 */3066	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)3067		return;3068 3069	if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||3070	    !vdevice->configured_lun)3071		return;3072 3073	/* Following parameters will not change3074	 * in this routine.3075	 */3076	iocmd.cmd = SYNCHRONIZE_CACHE;3077	iocmd.flags = 0;3078	iocmd.physDiskNum = -1;3079	iocmd.data = NULL;3080	iocmd.data_dma = -1;3081	iocmd.size = 0;3082	iocmd.rsvd = iocmd.rsvd2 = 0;3083	iocmd.channel = vdevice->vtarget->channel;3084	iocmd.id = vdevice->vtarget->id;3085	iocmd.lun = vdevice->lun;3086 3087	mptscsih_do_cmd(hd, &iocmd);3088}3089 3090static ssize_t3091mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,3092			 char *buf)3093{3094	struct Scsi_Host *host = class_to_shost(dev);3095	MPT_SCSI_HOST	*hd = shost_priv(host);3096	MPT_ADAPTER *ioc = hd->ioc;3097 3098	return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",3099	    (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,3100	    (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,3101	    (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,3102	    ioc->facts.FWVersion.Word & 0x000000FF);3103}3104static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);3105 3106static ssize_t3107mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,3108			   char *buf)3109{3110	struct Scsi_Host *host = class_to_shost(dev);3111	MPT_SCSI_HOST	*hd = shost_priv(host);3112	MPT_ADAPTER *ioc = hd->ioc;3113 3114	return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",3115	    (ioc->biosVersion & 0xFF000000) >> 24,3116	    (ioc->biosVersion & 0x00FF0000) >> 16,3117	    (ioc->biosVersion & 0x0000FF00) >> 8,3118	    ioc->biosVersion & 0x000000FF);3119}3120static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);3121 3122static ssize_t3123mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,3124			  char *buf)3125{3126	struct Scsi_Host *host = class_to_shost(dev);3127	MPT_SCSI_HOST	*hd = shost_priv(host);3128	MPT_ADAPTER *ioc = hd->ioc;3129 3130	return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);3131}3132static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);3133 3134static ssize_t3135mptscsih_version_product_show(struct device *dev,3136			      struct device_attribute *attr,3137char *buf)3138{3139	struct Scsi_Host *host = class_to_shost(dev);3140	MPT_SCSI_HOST	*hd = shost_priv(host);3141	MPT_ADAPTER *ioc = hd->ioc;3142 3143	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);3144}3145static DEVICE_ATTR(version_product, S_IRUGO,3146    mptscsih_version_product_show, NULL);3147 3148static ssize_t3149mptscsih_version_nvdata_persistent_show(struct device *dev,3150					struct device_attribute *attr,3151					char *buf)3152{3153	struct Scsi_Host *host = class_to_shost(dev);3154	MPT_SCSI_HOST	*hd = shost_priv(host);3155	MPT_ADAPTER *ioc = hd->ioc;3156 3157	return snprintf(buf, PAGE_SIZE, "%02xh\n",3158	    ioc->nvdata_version_persistent);3159}3160static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,3161    mptscsih_version_nvdata_persistent_show, NULL);3162 3163static ssize_t3164mptscsih_version_nvdata_default_show(struct device *dev,3165				     struct device_attribute *attr, char *buf)3166{3167	struct Scsi_Host *host = class_to_shost(dev);3168	MPT_SCSI_HOST	*hd = shost_priv(host);3169	MPT_ADAPTER *ioc = hd->ioc;3170 3171	return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);3172}3173static DEVICE_ATTR(version_nvdata_default, S_IRUGO,3174    mptscsih_version_nvdata_default_show, NULL);3175 3176static ssize_t3177mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,3178			 char *buf)3179{3180	struct Scsi_Host *host = class_to_shost(dev);3181	MPT_SCSI_HOST	*hd = shost_priv(host);3182	MPT_ADAPTER *ioc = hd->ioc;3183 3184	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);3185}3186static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);3187 3188static ssize_t3189mptscsih_board_assembly_show(struct device *dev,3190			     struct device_attribute *attr, char *buf)3191{3192	struct Scsi_Host *host = class_to_shost(dev);3193	MPT_SCSI_HOST	*hd = shost_priv(host);3194	MPT_ADAPTER *ioc = hd->ioc;3195 3196	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);3197}3198static DEVICE_ATTR(board_assembly, S_IRUGO,3199    mptscsih_board_assembly_show, NULL);3200 3201static ssize_t3202mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,3203			   char *buf)3204{3205	struct Scsi_Host *host = class_to_shost(dev);3206	MPT_SCSI_HOST	*hd = shost_priv(host);3207	MPT_ADAPTER *ioc = hd->ioc;3208 3209	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);3210}3211static DEVICE_ATTR(board_tracer, S_IRUGO,3212    mptscsih_board_tracer_show, NULL);3213 3214static ssize_t3215mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,3216		       char *buf)3217{3218	struct Scsi_Host *host = class_to_shost(dev);3219	MPT_SCSI_HOST	*hd = shost_priv(host);3220	MPT_ADAPTER *ioc = hd->ioc;3221 3222	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);3223}3224static DEVICE_ATTR(io_delay, S_IRUGO,3225    mptscsih_io_delay_show, NULL);3226 3227static ssize_t3228mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,3229			   char *buf)3230{3231	struct Scsi_Host *host = class_to_shost(dev);3232	MPT_SCSI_HOST	*hd = shost_priv(host);3233	MPT_ADAPTER *ioc = hd->ioc;3234 3235	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);3236}3237static DEVICE_ATTR(device_delay, S_IRUGO,3238    mptscsih_device_delay_show, NULL);3239 3240static ssize_t3241mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,3242			  char *buf)3243{3244	struct Scsi_Host *host = class_to_shost(dev);3245	MPT_SCSI_HOST	*hd = shost_priv(host);3246	MPT_ADAPTER *ioc = hd->ioc;3247 3248	return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);3249}3250static ssize_t3251mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,3252			   const char *buf, size_t count)3253{3254	struct Scsi_Host *host = class_to_shost(dev);3255	MPT_SCSI_HOST	*hd = shost_priv(host);3256	MPT_ADAPTER *ioc = hd->ioc;3257	int val = 0;3258 3259	if (sscanf(buf, "%x", &val) != 1)3260		return -EINVAL;3261 3262	ioc->debug_level = val;3263	printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",3264				ioc->name, ioc->debug_level);3265	return strlen(buf);3266}3267static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,3268	mptscsih_debug_level_show, mptscsih_debug_level_store);3269 3270static struct attribute *mptscsih_host_attrs[] = {3271	&dev_attr_version_fw.attr,3272	&dev_attr_version_bios.attr,3273	&dev_attr_version_mpi.attr,3274	&dev_attr_version_product.attr,3275	&dev_attr_version_nvdata_persistent.attr,3276	&dev_attr_version_nvdata_default.attr,3277	&dev_attr_board_name.attr,3278	&dev_attr_board_assembly.attr,3279	&dev_attr_board_tracer.attr,3280	&dev_attr_io_delay.attr,3281	&dev_attr_device_delay.attr,3282	&dev_attr_debug_level.attr,3283	NULL,3284};3285 3286static const struct attribute_group mptscsih_host_attr_group = {3287	.attrs = mptscsih_host_attrs3288};3289 3290const struct attribute_group *mptscsih_host_attr_groups[] = {3291	&mptscsih_host_attr_group,3292	NULL3293};3294EXPORT_SYMBOL(mptscsih_host_attr_groups);3295 3296EXPORT_SYMBOL(mptscsih_remove);3297EXPORT_SYMBOL(mptscsih_shutdown);3298#ifdef CONFIG_PM3299EXPORT_SYMBOL(mptscsih_suspend);3300EXPORT_SYMBOL(mptscsih_resume);3301#endif3302EXPORT_SYMBOL(mptscsih_show_info);3303EXPORT_SYMBOL(mptscsih_info);3304EXPORT_SYMBOL(mptscsih_qcmd);3305EXPORT_SYMBOL(mptscsih_slave_destroy);3306EXPORT_SYMBOL(mptscsih_slave_configure);3307EXPORT_SYMBOL(mptscsih_abort);3308EXPORT_SYMBOL(mptscsih_dev_reset);3309EXPORT_SYMBOL(mptscsih_target_reset);3310EXPORT_SYMBOL(mptscsih_bus_reset);3311EXPORT_SYMBOL(mptscsih_host_reset);3312EXPORT_SYMBOL(mptscsih_bios_param);3313EXPORT_SYMBOL(mptscsih_io_done);3314EXPORT_SYMBOL(mptscsih_taskmgmt_complete);3315EXPORT_SYMBOL(mptscsih_scandv_complete);3316EXPORT_SYMBOL(mptscsih_event_process);3317EXPORT_SYMBOL(mptscsih_ioc_reset);3318EXPORT_SYMBOL(mptscsih_change_queue_depth);3319 3320/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/3321