11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/drivers/message/fusion/mptscsih.c
3f36789e2SPrakash, Sathya  *      For use with LSI PCI chip/adapter(s)
4f36789e2SPrakash, Sathya  *      running LSI Fusion MPT (Message Passing Technology) firmware.
51da177e4SLinus Torvalds  *
6cddc0ab7SPrakash, Sathya  *  Copyright (c) 1999-2008 LSI Corporation
716d20101SEric Moore  *  (mailto:DL-MPTFusionLinux@lsi.com)
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
111da177e4SLinus Torvalds /*
121da177e4SLinus Torvalds     This program is free software; you can redistribute it and/or modify
131da177e4SLinus Torvalds     it under the terms of the GNU General Public License as published by
141da177e4SLinus Torvalds     the Free Software Foundation; version 2 of the License.
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds     This program is distributed in the hope that it will be useful,
171da177e4SLinus Torvalds     but WITHOUT ANY WARRANTY; without even the implied warranty of
181da177e4SLinus Torvalds     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
191da177e4SLinus Torvalds     GNU General Public License for more details.
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds     NO WARRANTY
221da177e4SLinus Torvalds     THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
231da177e4SLinus Torvalds     CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
241da177e4SLinus Torvalds     LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
251da177e4SLinus Torvalds     MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
261da177e4SLinus Torvalds     solely responsible for determining the appropriateness of using and
271da177e4SLinus Torvalds     distributing the Program and assumes all risks associated with its
281da177e4SLinus Torvalds     exercise of rights under this Agreement, including but not limited to
291da177e4SLinus Torvalds     the risks and costs of program errors, damage to or loss of data,
301da177e4SLinus Torvalds     programs or equipment, and unavailability or interruption of operations.
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds     DISCLAIMER OF LIABILITY
331da177e4SLinus Torvalds     NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
341da177e4SLinus Torvalds     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
351da177e4SLinus Torvalds     DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
361da177e4SLinus Torvalds     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
371da177e4SLinus Torvalds     TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
381da177e4SLinus Torvalds     USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
391da177e4SLinus Torvalds     HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds     You should have received a copy of the GNU General Public License
421da177e4SLinus Torvalds     along with this program; if not, write to the Free Software
431da177e4SLinus Torvalds     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
441da177e4SLinus Torvalds */
451da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds #include <linux/module.h>
481da177e4SLinus Torvalds #include <linux/kernel.h>
495a0e3ad6STejun Heo #include <linux/slab.h>
501da177e4SLinus Torvalds #include <linux/init.h>
511da177e4SLinus Torvalds #include <linux/errno.h>
521da177e4SLinus Torvalds #include <linux/kdev_t.h>
531da177e4SLinus Torvalds #include <linux/blkdev.h>
541da177e4SLinus Torvalds #include <linux/delay.h>	/* for mdelay */
55b8a51443SThomas Gleixner #include <linux/interrupt.h>
561da177e4SLinus Torvalds #include <linux/reboot.h>	/* notifier code */
571da177e4SLinus Torvalds #include <linux/workqueue.h>
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds #include <scsi/scsi.h>
601da177e4SLinus Torvalds #include <scsi/scsi_cmnd.h>
611da177e4SLinus Torvalds #include <scsi/scsi_device.h>
621da177e4SLinus Torvalds #include <scsi/scsi_host.h>
631da177e4SLinus Torvalds #include <scsi/scsi_tcq.h>
64e0fc15beSMoore, Eric Dean #include <scsi/scsi_dbg.h>
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds #include "mptbase.h"
671da177e4SLinus Torvalds #include "mptscsih.h"
68bf451522SEric Moore #include "lsi/mpi_log_sas.h"
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
711da177e4SLinus Torvalds #define my_NAME		"Fusion MPT SCSI Host driver"
721da177e4SLinus Torvalds #define my_VERSION	MPT_LINUX_VERSION_COMMON
731da177e4SLinus Torvalds #define MYNAM		"mptscsih"
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds MODULE_AUTHOR(MODULEAUTHOR);
761da177e4SLinus Torvalds MODULE_DESCRIPTION(my_NAME);
771da177e4SLinus Torvalds MODULE_LICENSE("GPL");
789f4203b3SEric Moore MODULE_VERSION(my_VERSION);
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
811da177e4SLinus Torvalds /*
821da177e4SLinus Torvalds  *  Other private/forward protos...
831da177e4SLinus Torvalds  */
84db7051b2SKashyap, Desai struct scsi_cmnd	*mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
85e8206381SEric Moore static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
86e8206381SEric Moore static void	mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
87e8206381SEric Moore static int	SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
880d0c7974SMoore, Eric Dean  int		mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
891da177e4SLinus Torvalds static void	mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
900d0c7974SMoore, Eric Dean  int		mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds static int	mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
931da177e4SLinus Torvalds 				 SCSIIORequest_t *pReq, int req_idx);
941da177e4SLinus Torvalds static void	mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
950d0c7974SMoore, Eric Dean  static void	mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
961da177e4SLinus Torvalds 
971ba9ab2eSKashyap, Desai int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
989cb78c16SHannes Reinecke 		u64 lun, int ctx2abort, ulong timeout);
991da177e4SLinus Torvalds 
1000d0c7974SMoore, Eric Dean  int		mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
1010d0c7974SMoore, Eric Dean  int		mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
1021da177e4SLinus Torvalds 
103e7deff33SKashyap, Desai void
1041ba9ab2eSKashyap, Desai mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
10537c60f37SKashyap, Desai static int	mptscsih_get_completion_code(MPT_ADAPTER *ioc,
10637c60f37SKashyap, Desai 		MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
1070d0c7974SMoore, Eric Dean  int		mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
1081da177e4SLinus Torvalds static int	mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
109c7c82987SMoore, Eric Dean static void	mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
1101da177e4SLinus Torvalds 
1111ba9ab2eSKashyap, Desai static int
1121ba9ab2eSKashyap, Desai mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
1131ba9ab2eSKashyap, Desai 				SCSITaskMgmtReply_t *pScsiTmReply);
1140d0c7974SMoore, Eric Dean  void 		mptscsih_remove(struct pci_dev *);
115d18c3db5SGreg Kroah-Hartman void 		mptscsih_shutdown(struct pci_dev *);
1161da177e4SLinus Torvalds #ifdef CONFIG_PM
1170d0c7974SMoore, Eric Dean  int 		mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
1180d0c7974SMoore, Eric Dean  int 		mptscsih_resume(struct pci_dev *pdev);
1191da177e4SLinus Torvalds #endif
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1231da177e4SLinus Torvalds /*
1241da177e4SLinus Torvalds  *	mptscsih_getFreeChainBuffer - Function to get a free chain
1251da177e4SLinus Torvalds  *	from the MPT_SCSI_HOST FreeChainQ.
1261da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
1271da177e4SLinus Torvalds  *	@req_idx: Index of the SCSI IO request frame. (output)
1281da177e4SLinus Torvalds  *
1291da177e4SLinus Torvalds  *	return SUCCESS or FAILED
1301da177e4SLinus Torvalds  */
1311da177e4SLinus Torvalds static inline int
mptscsih_getFreeChainBuffer(MPT_ADAPTER * ioc,int * retIndex)1321da177e4SLinus Torvalds mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
1331da177e4SLinus Torvalds {
1341da177e4SLinus Torvalds 	MPT_FRAME_HDR *chainBuf;
1351da177e4SLinus Torvalds 	unsigned long flags;
1361da177e4SLinus Torvalds 	int rc;
1371da177e4SLinus Torvalds 	int chain_idx;
1381da177e4SLinus Torvalds 
1396757d6b4SPrakash, Sathya 	dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
1401da177e4SLinus Torvalds 	    ioc->name));
1411da177e4SLinus Torvalds 	spin_lock_irqsave(&ioc->FreeQlock, flags);
1421da177e4SLinus Torvalds 	if (!list_empty(&ioc->FreeChainQ)) {
1431da177e4SLinus Torvalds 		int offset;
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 		chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
1461da177e4SLinus Torvalds 				u.frame.linkage.list);
1471da177e4SLinus Torvalds 		list_del(&chainBuf->u.frame.linkage.list);
1481da177e4SLinus Torvalds 		offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
1491da177e4SLinus Torvalds 		chain_idx = offset / ioc->req_sz;
1501da177e4SLinus Torvalds 		rc = SUCCESS;
15129dd3609SEric Moore 		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
15229dd3609SEric Moore 		    "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
153c6678e0cSChristoph Hellwig 		    ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
1541da177e4SLinus Torvalds 	} else {
1551da177e4SLinus Torvalds 		rc = FAILED;
1561da177e4SLinus Torvalds 		chain_idx = MPT_HOST_NO_CHAIN;
15729dd3609SEric Moore 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
1581da177e4SLinus Torvalds 		    ioc->name));
1591da177e4SLinus Torvalds 	}
1601da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	*retIndex = chain_idx;
1631da177e4SLinus Torvalds 	return rc;
1641da177e4SLinus Torvalds } /* mptscsih_getFreeChainBuffer() */
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1671da177e4SLinus Torvalds /*
1681da177e4SLinus Torvalds  *	mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
1691da177e4SLinus Torvalds  *	SCSIIORequest_t Message Frame.
1701da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
1711da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure
1721da177e4SLinus Torvalds  *	@pReq: Pointer to SCSIIORequest_t structure
1731da177e4SLinus Torvalds  *
1741da177e4SLinus Torvalds  *	Returns ...
1751da177e4SLinus Torvalds  */
1761da177e4SLinus Torvalds static int
mptscsih_AddSGE(MPT_ADAPTER * ioc,struct scsi_cmnd * SCpnt,SCSIIORequest_t * pReq,int req_idx)1771da177e4SLinus Torvalds mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
1781da177e4SLinus Torvalds 		SCSIIORequest_t *pReq, int req_idx)
1791da177e4SLinus Torvalds {
1801da177e4SLinus Torvalds 	char 	*psge;
1811da177e4SLinus Torvalds 	char	*chainSge;
1821da177e4SLinus Torvalds 	struct scatterlist *sg;
1831da177e4SLinus Torvalds 	int	 frm_sz;
1841da177e4SLinus Torvalds 	int	 sges_left, sg_done;
1851da177e4SLinus Torvalds 	int	 chain_idx = MPT_HOST_NO_CHAIN;
1861da177e4SLinus Torvalds 	int	 sgeOffset;
1871da177e4SLinus Torvalds 	int	 numSgeSlots, numSgeThisFrame;
1881da177e4SLinus Torvalds 	u32	 sgflags, sgdir, thisxfer = 0;
1891da177e4SLinus Torvalds 	int	 chain_dma_off = 0;
1901da177e4SLinus Torvalds 	int	 newIndex;
1911da177e4SLinus Torvalds 	int	 ii;
1921da177e4SLinus Torvalds 	dma_addr_t v2;
1931da177e4SLinus Torvalds 	u32	RequestNB;
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 	sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
1961da177e4SLinus Torvalds 	if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {
1971da177e4SLinus Torvalds 		sgdir = MPT_TRANSFER_HOST_TO_IOC;
1981da177e4SLinus Torvalds 	} else {
1991da177e4SLinus Torvalds 		sgdir = MPT_TRANSFER_IOC_TO_HOST;
2001da177e4SLinus Torvalds 	}
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	psge = (char *) &pReq->SGL;
2031da177e4SLinus Torvalds 	frm_sz = ioc->req_sz;
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 	/* Map the data portion, if any.
2061da177e4SLinus Torvalds 	 * sges_left  = 0 if no data transfer.
2071da177e4SLinus Torvalds 	 */
2081928d73fSFUJITA Tomonori 	sges_left = scsi_dma_map(SCpnt);
2091928d73fSFUJITA Tomonori 	if (sges_left < 0)
2101da177e4SLinus Torvalds 		return FAILED;
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 	/* Handle the SG case.
2131da177e4SLinus Torvalds 	 */
2141928d73fSFUJITA Tomonori 	sg = scsi_sglist(SCpnt);
2151da177e4SLinus Torvalds 	sg_done  = 0;
2161da177e4SLinus Torvalds 	sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
2171da177e4SLinus Torvalds 	chainSge = NULL;
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	/* Prior to entering this loop - the following must be set
2201da177e4SLinus Torvalds 	 * current MF:  sgeOffset (bytes)
2211da177e4SLinus Torvalds 	 *              chainSge (Null if original MF is not a chain buffer)
2221da177e4SLinus Torvalds 	 *              sg_done (num SGE done for this MF)
2231da177e4SLinus Torvalds 	 */
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds nextSGEset:
22614d0f0b0SKashyap, Desai 	numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
2271da177e4SLinus Torvalds 	numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
2281da177e4SLinus Torvalds 
22914d0f0b0SKashyap, Desai 	sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	/* Get first (num - 1) SG elements
2321da177e4SLinus Torvalds 	 * Skip any SG entries with a length of 0
2331da177e4SLinus Torvalds 	 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
2341da177e4SLinus Torvalds 	 */
2351da177e4SLinus Torvalds 	for (ii=0; ii < (numSgeThisFrame-1); ii++) {
2361da177e4SLinus Torvalds 		thisxfer = sg_dma_len(sg);
2371da177e4SLinus Torvalds 		if (thisxfer == 0) {
2382f187862SKashyap, Desai 			/* Get next SG element from the OS */
2392f187862SKashyap, Desai 			sg = sg_next(sg);
2401da177e4SLinus Torvalds 			sg_done++;
2411da177e4SLinus Torvalds 			continue;
2421da177e4SLinus Torvalds 		}
2431da177e4SLinus Torvalds 
2441da177e4SLinus Torvalds 		v2 = sg_dma_address(sg);
24514d0f0b0SKashyap, Desai 		ioc->add_sge(psge, sgflags | thisxfer, v2);
2461da177e4SLinus Torvalds 
2472f187862SKashyap, Desai 		/* Get next SG element from the OS */
2482f187862SKashyap, Desai 		sg = sg_next(sg);
24914d0f0b0SKashyap, Desai 		psge += ioc->SGE_size;
25014d0f0b0SKashyap, Desai 		sgeOffset += ioc->SGE_size;
2511da177e4SLinus Torvalds 		sg_done++;
2521da177e4SLinus Torvalds 	}
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	if (numSgeThisFrame == sges_left) {
2551da177e4SLinus Torvalds 		/* Add last element, end of buffer and end of list flags.
2561da177e4SLinus Torvalds 		 */
2571da177e4SLinus Torvalds 		sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
2581da177e4SLinus Torvalds 				MPT_SGE_FLAGS_END_OF_BUFFER |
2591da177e4SLinus Torvalds 				MPT_SGE_FLAGS_END_OF_LIST;
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 		/* Add last SGE and set termination flags.
2621da177e4SLinus Torvalds 		 * Note: Last SGE may have a length of 0 - which should be ok.
2631da177e4SLinus Torvalds 		 */
2641da177e4SLinus Torvalds 		thisxfer = sg_dma_len(sg);
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 		v2 = sg_dma_address(sg);
26714d0f0b0SKashyap, Desai 		ioc->add_sge(psge, sgflags | thisxfer, v2);
26814d0f0b0SKashyap, Desai 		sgeOffset += ioc->SGE_size;
2691da177e4SLinus Torvalds 		sg_done++;
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 		if (chainSge) {
2721da177e4SLinus Torvalds 			/* The current buffer is a chain buffer,
2731da177e4SLinus Torvalds 			 * but there is not another one.
2741da177e4SLinus Torvalds 			 * Update the chain element
2751da177e4SLinus Torvalds 			 * Offset and Length fields.
2761da177e4SLinus Torvalds 			 */
27714d0f0b0SKashyap, Desai 			ioc->add_chain((char *)chainSge, 0, sgeOffset,
27814d0f0b0SKashyap, Desai 				ioc->ChainBufferDMA + chain_dma_off);
2791da177e4SLinus Torvalds 		} else {
2801da177e4SLinus Torvalds 			/* The current buffer is the original MF
2811da177e4SLinus Torvalds 			 * and there is no Chain buffer.
2821da177e4SLinus Torvalds 			 */
2831da177e4SLinus Torvalds 			pReq->ChainOffset = 0;
2841da177e4SLinus Torvalds 			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;
2856757d6b4SPrakash, Sathya 			dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2861da177e4SLinus Torvalds 			    "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
2871da177e4SLinus Torvalds 			ioc->RequestNB[req_idx] = RequestNB;
2881da177e4SLinus Torvalds 		}
2891da177e4SLinus Torvalds 	} else {
2901da177e4SLinus Torvalds 		/* At least one chain buffer is needed.
2911da177e4SLinus Torvalds 		 * Complete the first MF
2921da177e4SLinus Torvalds 		 *  - last SGE element, set the LastElement bit
2931da177e4SLinus Torvalds 		 *  - set ChainOffset (words) for orig MF
2941da177e4SLinus Torvalds 		 *             (OR finish previous MF chain buffer)
2951da177e4SLinus Torvalds 		 *  - update MFStructPtr ChainIndex
2961da177e4SLinus Torvalds 		 *  - Populate chain element
2971da177e4SLinus Torvalds 		 * Also
2981da177e4SLinus Torvalds 		 * Loop until done.
2991da177e4SLinus Torvalds 		 */
3001da177e4SLinus Torvalds 
3016757d6b4SPrakash, Sathya 		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
3021da177e4SLinus Torvalds 				ioc->name, sg_done));
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 		/* Set LAST_ELEMENT flag for last non-chain element
3051da177e4SLinus Torvalds 		 * in the buffer. Since psge points at the NEXT
3061da177e4SLinus Torvalds 		 * SGE element, go back one SGE element, update the flags
3071da177e4SLinus Torvalds 		 * and reset the pointer. (Note: sgflags & thisxfer are already
3081da177e4SLinus Torvalds 		 * set properly).
3091da177e4SLinus Torvalds 		 */
3101da177e4SLinus Torvalds 		if (sg_done) {
31114d0f0b0SKashyap, Desai 			u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
3121da177e4SLinus Torvalds 			sgflags = le32_to_cpu(*ptmp);
3131da177e4SLinus Torvalds 			sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
3141da177e4SLinus Torvalds 			*ptmp = cpu_to_le32(sgflags);
3151da177e4SLinus Torvalds 		}
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds 		if (chainSge) {
3181da177e4SLinus Torvalds 			/* The current buffer is a chain buffer.
3191da177e4SLinus Torvalds 			 * chainSge points to the previous Chain Element.
3201da177e4SLinus Torvalds 			 * Update its chain element Offset and Length (must
3211da177e4SLinus Torvalds 			 * include chain element size) fields.
3221da177e4SLinus Torvalds 			 * Old chain element is now complete.
3231da177e4SLinus Torvalds 			 */
3241da177e4SLinus Torvalds 			u8 nextChain = (u8) (sgeOffset >> 2);
32514d0f0b0SKashyap, Desai 			sgeOffset += ioc->SGE_size;
32614d0f0b0SKashyap, Desai 			ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
32714d0f0b0SKashyap, Desai 					 ioc->ChainBufferDMA + chain_dma_off);
3281da177e4SLinus Torvalds 		} else {
3291da177e4SLinus Torvalds 			/* The original MF buffer requires a chain buffer -
3301da177e4SLinus Torvalds 			 * set the offset.
3311da177e4SLinus Torvalds 			 * Last element in this MF is a chain element.
3321da177e4SLinus Torvalds 			 */
3331da177e4SLinus Torvalds 			pReq->ChainOffset = (u8) (sgeOffset >> 2);
3341da177e4SLinus Torvalds 			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;
3356757d6b4SPrakash, Sathya 			dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
3361da177e4SLinus Torvalds 			ioc->RequestNB[req_idx] = RequestNB;
3371da177e4SLinus Torvalds 		}
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 		sges_left -= sg_done;
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds 		/* NOTE: psge points to the beginning of the chain element
3431da177e4SLinus Torvalds 		 * in current buffer. Get a chain buffer.
3441da177e4SLinus Torvalds 		 */
345c6678e0cSChristoph Hellwig 		if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
3466757d6b4SPrakash, Sathya 			dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
347c6678e0cSChristoph Hellwig 			    "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
3481da177e4SLinus Torvalds  			    ioc->name, pReq->CDB[0], SCpnt));
3491da177e4SLinus Torvalds 			return FAILED;
350c6678e0cSChristoph Hellwig 		}
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 		/* Update the tracking arrays.
3531da177e4SLinus Torvalds 		 * If chainSge == NULL, update ReqToChain, else ChainToChain
3541da177e4SLinus Torvalds 		 */
3551da177e4SLinus Torvalds 		if (chainSge) {
3561da177e4SLinus Torvalds 			ioc->ChainToChain[chain_idx] = newIndex;
3571da177e4SLinus Torvalds 		} else {
3581da177e4SLinus Torvalds 			ioc->ReqToChain[req_idx] = newIndex;
3591da177e4SLinus Torvalds 		}
3601da177e4SLinus Torvalds 		chain_idx = newIndex;
3611da177e4SLinus Torvalds 		chain_dma_off = ioc->req_sz * chain_idx;
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 		/* Populate the chainSGE for the current buffer.
3641da177e4SLinus Torvalds 		 * - Set chain buffer pointer to psge and fill
3651da177e4SLinus Torvalds 		 *   out the Address and Flags fields.
3661da177e4SLinus Torvalds 		 */
3671da177e4SLinus Torvalds 		chainSge = (char *) psge;
36829dd3609SEric Moore 		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Current buff @ %p (index 0x%x)",
36929dd3609SEric Moore 		    ioc->name, psge, req_idx));
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 		/* Start the SGE for the next buffer
3721da177e4SLinus Torvalds 		 */
3731da177e4SLinus Torvalds 		psge = (char *) (ioc->ChainBuffer + chain_dma_off);
3741da177e4SLinus Torvalds 		sgeOffset = 0;
3751da177e4SLinus Torvalds 		sg_done = 0;
3761da177e4SLinus Torvalds 
37729dd3609SEric Moore 		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Chain buff @ %p (index 0x%x)\n",
37829dd3609SEric Moore 		    ioc->name, psge, chain_idx));
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 		/* Start the SGE for the next buffer
3811da177e4SLinus Torvalds 		 */
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 		goto nextSGEset;
3841da177e4SLinus Torvalds 	}
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds 	return SUCCESS;
3871da177e4SLinus Torvalds } /* mptscsih_AddSGE() */
3881da177e4SLinus Torvalds 
389786899b0SEric Moore static void
mptscsih_issue_sep_command(MPT_ADAPTER * ioc,VirtTarget * vtarget,U32 SlotStatus)390786899b0SEric Moore mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
391786899b0SEric Moore     U32 SlotStatus)
392786899b0SEric Moore {
393786899b0SEric Moore 	MPT_FRAME_HDR *mf;
394786899b0SEric Moore 	SEPRequest_t 	 *SEPMsg;
395786899b0SEric Moore 
396cc78d30aSEric Moore 	if (ioc->bus_type != SAS)
397cc78d30aSEric Moore 		return;
398cc78d30aSEric Moore 
399cc78d30aSEric Moore 	/* Not supported for hidden raid components
400cc78d30aSEric Moore 	 */
401cc78d30aSEric Moore 	if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
402786899b0SEric Moore 		return;
403786899b0SEric Moore 
404786899b0SEric Moore 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
4056757d6b4SPrakash, Sathya 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
406cadbd4a5SHarvey Harrison 		    ioc->name,__func__));
407786899b0SEric Moore 		return;
408786899b0SEric Moore 	}
409786899b0SEric Moore 
410786899b0SEric Moore 	SEPMsg = (SEPRequest_t *)mf;
411786899b0SEric Moore 	SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
412793955f5SEric Moore 	SEPMsg->Bus = vtarget->channel;
413793955f5SEric Moore 	SEPMsg->TargetID = vtarget->id;
414786899b0SEric Moore 	SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
415786899b0SEric Moore 	SEPMsg->SlotStatus = SlotStatus;
4166757d6b4SPrakash, Sathya 	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
417793955f5SEric Moore 	    "Sending SEP cmd=%x channel=%d id=%d\n",
418793955f5SEric Moore 	    ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
419786899b0SEric Moore 	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
420786899b0SEric Moore }
421786899b0SEric Moore 
4226757d6b4SPrakash, Sathya #ifdef CONFIG_FUSION_LOGGING
423c6c727a1SEric Moore /**
4246757d6b4SPrakash, Sathya  *	mptscsih_info_scsiio - debug print info on reply frame
425c6c727a1SEric Moore  *	@ioc: Pointer to MPT_ADAPTER structure
426c6c727a1SEric Moore  *	@sc: original scsi cmnd pointer
4276757d6b4SPrakash, Sathya  *	@pScsiReply: Pointer to MPT reply frame
4286757d6b4SPrakash, Sathya  *
4296757d6b4SPrakash, Sathya  *	MPT_DEBUG_REPLY needs to be enabled to obtain this info
430c6c727a1SEric Moore  *
431c6c727a1SEric Moore  *	Refer to lsi/mpi.h.
432c6c727a1SEric Moore  **/
433c6c727a1SEric Moore static void
mptscsih_info_scsiio(MPT_ADAPTER * ioc,struct scsi_cmnd * sc,SCSIIOReply_t * pScsiReply)4346757d6b4SPrakash, Sathya mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
435c6c727a1SEric Moore {
436c6c727a1SEric Moore 	char	*desc = NULL;
4376757d6b4SPrakash, Sathya 	char	*desc1 = NULL;
4386757d6b4SPrakash, Sathya 	u16	ioc_status;
4396757d6b4SPrakash, Sathya 	u8	skey, asc, ascq;
4406757d6b4SPrakash, Sathya 
4416757d6b4SPrakash, Sathya 	ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
442c6c727a1SEric Moore 
443c6c727a1SEric Moore 	switch (ioc_status) {
444c6c727a1SEric Moore 
4456757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SUCCESS:
4466757d6b4SPrakash, Sathya 		desc = "success";
447c6c727a1SEric Moore 		break;
4486757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_INVALID_BUS:
4496757d6b4SPrakash, Sathya 		desc = "invalid bus";
450c6c727a1SEric Moore 		break;
4516757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
4526757d6b4SPrakash, Sathya 		desc = "invalid target_id";
453c6c727a1SEric Moore 		break;
4546757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
4556757d6b4SPrakash, Sathya 		desc = "device not there";
456c6c727a1SEric Moore 		break;
4576757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
4586757d6b4SPrakash, Sathya 		desc = "data overrun";
459c6c727a1SEric Moore 		break;
4606757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
4616757d6b4SPrakash, Sathya 		desc = "data underrun";
462c6c727a1SEric Moore 		break;
4636757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
4646757d6b4SPrakash, Sathya 		desc = "I/O data error";
465c6c727a1SEric Moore 		break;
4666757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
4676757d6b4SPrakash, Sathya 		desc = "protocol error";
468c6c727a1SEric Moore 		break;
4696757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
4706757d6b4SPrakash, Sathya 		desc = "task terminated";
471c6c727a1SEric Moore 		break;
4726757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
4736757d6b4SPrakash, Sathya 		desc = "residual mismatch";
474c6c727a1SEric Moore 		break;
4756757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
4766757d6b4SPrakash, Sathya 		desc = "task management failed";
4776757d6b4SPrakash, Sathya 		break;
4786757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
4796757d6b4SPrakash, Sathya 		desc = "IOC terminated";
4806757d6b4SPrakash, Sathya 		break;
4816757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
4826757d6b4SPrakash, Sathya 		desc = "ext terminated";
4836757d6b4SPrakash, Sathya 		break;
4846757d6b4SPrakash, Sathya 	default:
4856757d6b4SPrakash, Sathya 		desc = "";
486c6c727a1SEric Moore 		break;
487c6c727a1SEric Moore 	}
488c6c727a1SEric Moore 
4896757d6b4SPrakash, Sathya 	switch (pScsiReply->SCSIStatus)
4906757d6b4SPrakash, Sathya 	{
491c6c727a1SEric Moore 
4926757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_SUCCESS:
4936757d6b4SPrakash, Sathya 		desc1 = "success";
4946757d6b4SPrakash, Sathya 		break;
4956757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_CHECK_CONDITION:
4966757d6b4SPrakash, Sathya 		desc1 = "check condition";
4976757d6b4SPrakash, Sathya 		break;
4986757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_CONDITION_MET:
4996757d6b4SPrakash, Sathya 		desc1 = "condition met";
5006757d6b4SPrakash, Sathya 		break;
5016757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_BUSY:
5026757d6b4SPrakash, Sathya 		desc1 = "busy";
5036757d6b4SPrakash, Sathya 		break;
5046757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_INTERMEDIATE:
5056757d6b4SPrakash, Sathya 		desc1 = "intermediate";
5066757d6b4SPrakash, Sathya 		break;
5076757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
5086757d6b4SPrakash, Sathya 		desc1 = "intermediate condmet";
5096757d6b4SPrakash, Sathya 		break;
5106757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
5116757d6b4SPrakash, Sathya 		desc1 = "reservation conflict";
5126757d6b4SPrakash, Sathya 		break;
5136757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_COMMAND_TERMINATED:
5146757d6b4SPrakash, Sathya 		desc1 = "command terminated";
5156757d6b4SPrakash, Sathya 		break;
5166757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_TASK_SET_FULL:
5176757d6b4SPrakash, Sathya 		desc1 = "task set full";
5186757d6b4SPrakash, Sathya 		break;
5196757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_ACA_ACTIVE:
5206757d6b4SPrakash, Sathya 		desc1 = "aca active";
5216757d6b4SPrakash, Sathya 		break;
5226757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
5236757d6b4SPrakash, Sathya 		desc1 = "fcpext device logged out";
5246757d6b4SPrakash, Sathya 		break;
5256757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
5266757d6b4SPrakash, Sathya 		desc1 = "fcpext no link";
5276757d6b4SPrakash, Sathya 		break;
5286757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
5296757d6b4SPrakash, Sathya 		desc1 = "fcpext unassigned";
5306757d6b4SPrakash, Sathya 		break;
5316757d6b4SPrakash, Sathya 	default:
5326757d6b4SPrakash, Sathya 		desc1 = "";
5336757d6b4SPrakash, Sathya 		break;
5346757d6b4SPrakash, Sathya 	}
535c6c727a1SEric Moore 
5366757d6b4SPrakash, Sathya 	scsi_print_command(sc);
5379cb78c16SHannes Reinecke 	printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %llu\n",
5382f187862SKashyap, Desai 	    ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
53929dd3609SEric Moore 	printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
54029dd3609SEric Moore 	    "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
54129dd3609SEric Moore 	    scsi_get_resid(sc));
54229dd3609SEric Moore 	printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
54329dd3609SEric Moore 	    "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
5446757d6b4SPrakash, Sathya 	    le32_to_cpu(pScsiReply->TransferCount), sc->result);
5452f187862SKashyap, Desai 
54629dd3609SEric Moore 	printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
5476757d6b4SPrakash, Sathya 	    "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
54829dd3609SEric Moore 	    ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
5496757d6b4SPrakash, Sathya 	    pScsiReply->SCSIState);
5506757d6b4SPrakash, Sathya 
5516757d6b4SPrakash, Sathya 	if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
5526757d6b4SPrakash, Sathya 		skey = sc->sense_buffer[2] & 0x0F;
5536757d6b4SPrakash, Sathya 		asc = sc->sense_buffer[12];
5546757d6b4SPrakash, Sathya 		ascq = sc->sense_buffer[13];
5556757d6b4SPrakash, Sathya 
55629dd3609SEric Moore 		printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
55729dd3609SEric Moore 		    "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
5586757d6b4SPrakash, Sathya 	}
5596757d6b4SPrakash, Sathya 
5606757d6b4SPrakash, Sathya 	/*
5616757d6b4SPrakash, Sathya 	 *  Look for + dump FCP ResponseInfo[]!
5626757d6b4SPrakash, Sathya 	 */
5636757d6b4SPrakash, Sathya 	if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
5646757d6b4SPrakash, Sathya 	    pScsiReply->ResponseInfo)
56529dd3609SEric Moore 		printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
56629dd3609SEric Moore 		    ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
567c6c727a1SEric Moore }
568c6c727a1SEric Moore #endif
569c6c727a1SEric Moore 
5701da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5711da177e4SLinus Torvalds /*
5721da177e4SLinus Torvalds  *	mptscsih_io_done - Main SCSI IO callback routine registered to
5731da177e4SLinus Torvalds  *	Fusion MPT (base) driver
5741da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
5751da177e4SLinus Torvalds  *	@mf: Pointer to original MPT request frame
5761da177e4SLinus Torvalds  *	@r: Pointer to MPT reply frame (NULL if TurboReply)
5771da177e4SLinus Torvalds  *
5781da177e4SLinus Torvalds  *	This routine is called from mpt.c::mpt_interrupt() at the completion
5791da177e4SLinus Torvalds  *	of any SCSI IO request.
5801da177e4SLinus Torvalds  *	This routine is registered with the Fusion MPT (base) driver at driver
5811da177e4SLinus Torvalds  *	load/init time via the mpt_register() API call.
5821da177e4SLinus Torvalds  *
5831da177e4SLinus Torvalds  *	Returns 1 indicating alloc'd request frame ptr should be freed.
5841da177e4SLinus Torvalds  */
5850d0c7974SMoore, Eric Dean  int
mptscsih_io_done(MPT_ADAPTER * ioc,MPT_FRAME_HDR * mf,MPT_FRAME_HDR * mr)5861da177e4SLinus Torvalds mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
5871da177e4SLinus Torvalds {
5881da177e4SLinus Torvalds 	struct scsi_cmnd	*sc;
5891da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
5901da177e4SLinus Torvalds 	SCSIIORequest_t	*pScsiReq;
5911da177e4SLinus Torvalds 	SCSIIOReply_t	*pScsiReply;
5922254c86dSMoore, Eric 	u16		 req_idx, req_idx_MR;
593a69de507SEric Moore 	VirtDevice	 *vdevice;
594786899b0SEric Moore 	VirtTarget	 *vtarget;
5951da177e4SLinus Torvalds 
596e7eae9f6SEric Moore 	hd = shost_priv(ioc->sh);
5971da177e4SLinus Torvalds 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
5982254c86dSMoore, Eric 	req_idx_MR = (mr != NULL) ?
5992254c86dSMoore, Eric 	    le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
6002f187862SKashyap, Desai 
6012f187862SKashyap, Desai 	/* Special case, where already freed message frame is received from
6022f187862SKashyap, Desai 	 * Firmware. It happens with Resetting IOC.
6032f187862SKashyap, Desai 	 * Return immediately. Do not care
6042f187862SKashyap, Desai 	 */
6052254c86dSMoore, Eric 	if ((req_idx != req_idx_MR) ||
6062f187862SKashyap, Desai 	    (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))
6072254c86dSMoore, Eric 		return 0;
6082254c86dSMoore, Eric 
609e8206381SEric Moore 	sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
6101da177e4SLinus Torvalds 	if (sc == NULL) {
6111da177e4SLinus Torvalds 		MPIHeader_t *hdr = (MPIHeader_t *)mf;
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds 		/* Remark: writeSDP1 will use the ScsiDoneCtx
6141da177e4SLinus Torvalds 		 * If a SCSI I/O cmd, device disabled by OS and
6151da177e4SLinus Torvalds 		 * completion done. Cannot touch sc struct. Just free mem.
6161da177e4SLinus Torvalds 		 */
6171da177e4SLinus Torvalds 		if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
6181da177e4SLinus Torvalds 			printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
6191da177e4SLinus Torvalds 			ioc->name);
6201da177e4SLinus Torvalds 
6211da177e4SLinus Torvalds 		mptscsih_freeChainBuffers(ioc, req_idx);
6221da177e4SLinus Torvalds 		return 1;
6231da177e4SLinus Torvalds 	}
6241da177e4SLinus Torvalds 
6253dc0b03fSEric Moore 	if ((unsigned char *)mf != sc->host_scribble) {
6263dc0b03fSEric Moore 		mptscsih_freeChainBuffers(ioc, req_idx);
6273dc0b03fSEric Moore 		return 1;
6283dc0b03fSEric Moore 	}
6293dc0b03fSEric Moore 
630fea98403SKashyap, Desai 	if (ioc->bus_type == SAS) {
631fea98403SKashyap, Desai 		VirtDevice *vdevice = sc->device->hostdata;
632fea98403SKashyap, Desai 
633fea98403SKashyap, Desai 		if (!vdevice || !vdevice->vtarget ||
634fea98403SKashyap, Desai 		    vdevice->vtarget->deleted) {
635fea98403SKashyap, Desai 			sc->result = DID_NO_CONNECT << 16;
636fea98403SKashyap, Desai 			goto out;
637fea98403SKashyap, Desai 		}
638fea98403SKashyap, Desai 	}
639fea98403SKashyap, Desai 
6403dc0b03fSEric Moore 	sc->host_scribble = NULL;
6411da177e4SLinus Torvalds 	sc->result = DID_OK << 16;		/* Set default reply as OK */
6421da177e4SLinus Torvalds 	pScsiReq = (SCSIIORequest_t *) mf;
6431da177e4SLinus Torvalds 	pScsiReply = (SCSIIOReply_t *) mr;
6441da177e4SLinus Torvalds 
645c6678e0cSChristoph Hellwig 	if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
6466757d6b4SPrakash, Sathya 		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
647c6678e0cSChristoph Hellwig 			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
648c6678e0cSChristoph Hellwig 			ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
649c6678e0cSChristoph Hellwig 	}else{
6506757d6b4SPrakash, Sathya 		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
651c6678e0cSChristoph Hellwig 			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
652c6678e0cSChristoph Hellwig 			ioc->name, mf, mr, sc, req_idx));
653c6678e0cSChristoph Hellwig 	}
654c6678e0cSChristoph Hellwig 
6551da177e4SLinus Torvalds 	if (pScsiReply == NULL) {
6561da177e4SLinus Torvalds 		/* special context reply handling */
6571da177e4SLinus Torvalds 		;
6581da177e4SLinus Torvalds 	} else {
6591da177e4SLinus Torvalds 		u32	 xfer_cnt;
6601da177e4SLinus Torvalds 		u16	 status;
6611da177e4SLinus Torvalds 		u8	 scsi_state, scsi_status;
662c6c727a1SEric Moore 		u32	 log_info;
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
665c9de7dc4SKashyap, Desai 
6661da177e4SLinus Torvalds 		scsi_state = pScsiReply->SCSIState;
6671da177e4SLinus Torvalds 		scsi_status = pScsiReply->SCSIStatus;
6681da177e4SLinus Torvalds 		xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
6691928d73fSFUJITA Tomonori 		scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
670c6c727a1SEric Moore 		log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
6711da177e4SLinus Torvalds 
672466544d8SMoore, Eric Dean 		/*
673466544d8SMoore, Eric Dean 		 *  if we get a data underrun indication, yet no data was
674466544d8SMoore, Eric Dean 		 *  transferred and the SCSI status indicates that the
675466544d8SMoore, Eric Dean 		 *  command was never started, change the data underrun
676466544d8SMoore, Eric Dean 		 *  to success
677466544d8SMoore, Eric Dean 		 */
678466544d8SMoore, Eric Dean 		if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
679466544d8SMoore, Eric Dean 		    (scsi_status == MPI_SCSI_STATUS_BUSY ||
680466544d8SMoore, Eric Dean 		     scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
681466544d8SMoore, Eric Dean 		     scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
682466544d8SMoore, Eric Dean 			status = MPI_IOCSTATUS_SUCCESS;
683466544d8SMoore, Eric Dean 		}
684466544d8SMoore, Eric Dean 
6851da177e4SLinus Torvalds 		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
6860d0c7974SMoore, Eric Dean  			mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 		/*
6891da177e4SLinus Torvalds 		 *  Look for + dump FCP ResponseInfo[]!
6901da177e4SLinus Torvalds 		 */
691466544d8SMoore, Eric Dean 		if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
692466544d8SMoore, Eric Dean 		    pScsiReply->ResponseInfo) {
6939cb78c16SHannes Reinecke 			printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%llu] "
69429dd3609SEric Moore 			"FCP_ResponseInfo=%08xh\n", ioc->name,
695c6c727a1SEric Moore 			sc->device->host->host_no, sc->device->channel,
696c6c727a1SEric Moore 			sc->device->id, sc->device->lun,
6971da177e4SLinus Torvalds 			le32_to_cpu(pScsiReply->ResponseInfo));
6981da177e4SLinus Torvalds 		}
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 		switch(status) {
7011da177e4SLinus Torvalds 		case MPI_IOCSTATUS_BUSY:			/* 0x0002 */
702d23321b4SKashyap, Desai 		case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:	/* 0x0006 */
7031da177e4SLinus Torvalds 			/* CHECKME!
7041da177e4SLinus Torvalds 			 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
7051da177e4SLinus Torvalds 			 * But not: DID_BUS_BUSY lest one risk
7061da177e4SLinus Torvalds 			 * killing interrupt handler:-(
7071da177e4SLinus Torvalds 			 */
7081da177e4SLinus Torvalds 			sc->result = SAM_STAT_BUSY;
7091da177e4SLinus Torvalds 			break;
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_INVALID_BUS:		/* 0x0041 */
7121da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:	/* 0x0042 */
7131da177e4SLinus Torvalds 			sc->result = DID_BAD_TARGET << 16;
7141da177e4SLinus Torvalds 			break;
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
7171da177e4SLinus Torvalds 			/* Spoof to SCSI Selection Timeout! */
71865207fedSMoore, Eric 			if (ioc->bus_type != FC)
7191da177e4SLinus Torvalds 				sc->result = DID_NO_CONNECT << 16;
72065207fedSMoore, Eric 			/* else fibre, just stall until rescan event */
72165207fedSMoore, Eric 			else
72265207fedSMoore, Eric 				sc->result = DID_REQUEUE << 16;
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 			if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
7251da177e4SLinus Torvalds 				hd->sel_timeout[pScsiReq->TargetID]++;
726786899b0SEric Moore 
727a69de507SEric Moore 			vdevice = sc->device->hostdata;
728a69de507SEric Moore 			if (!vdevice)
729786899b0SEric Moore 				break;
730a69de507SEric Moore 			vtarget = vdevice->vtarget;
731786899b0SEric Moore 			if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
732786899b0SEric Moore 				mptscsih_issue_sep_command(ioc, vtarget,
733786899b0SEric Moore 				    MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
734786899b0SEric Moore 				vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
735786899b0SEric Moore 			}
7361da177e4SLinus Torvalds 			break;
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
739bf451522SEric Moore 			if ( ioc->bus_type == SAS ) {
740c9de7dc4SKashyap, Desai 				u16 ioc_status =
741c9de7dc4SKashyap, Desai 				    le16_to_cpu(pScsiReply->IOCStatus);
742c9de7dc4SKashyap, Desai 				if ((ioc_status &
743c9de7dc4SKashyap, Desai 					MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
744c9de7dc4SKashyap, Desai 					&&
745c9de7dc4SKashyap, Desai 					((log_info & SAS_LOGINFO_MASK) ==
746c9de7dc4SKashyap, Desai 					SAS_LOGINFO_NEXUS_LOSS)) {
747c9de7dc4SKashyap, Desai 						VirtDevice *vdevice =
748c9de7dc4SKashyap, Desai 						sc->device->hostdata;
749c9de7dc4SKashyap, Desai 
750c9de7dc4SKashyap, Desai 					    /* flag the device as being in
751c9de7dc4SKashyap, Desai 					     * device removal delay so we can
752c9de7dc4SKashyap, Desai 					     * notify the midlayer to hold off
753c9de7dc4SKashyap, Desai 					     * on timeout eh */
754c9de7dc4SKashyap, Desai 						if (vdevice && vdevice->
755c9de7dc4SKashyap, Desai 							vtarget &&
756c9de7dc4SKashyap, Desai 							vdevice->vtarget->
757c9de7dc4SKashyap, Desai 							raidVolume)
758c9de7dc4SKashyap, Desai 							printk(KERN_INFO
759c9de7dc4SKashyap, Desai 							"Skipping Raid Volume"
760c9de7dc4SKashyap, Desai 							"for inDMD\n");
761c9de7dc4SKashyap, Desai 						else if (vdevice &&
762c9de7dc4SKashyap, Desai 							vdevice->vtarget)
763c9de7dc4SKashyap, Desai 							vdevice->vtarget->
764c9de7dc4SKashyap, Desai 								inDMD = 1;
765c9de7dc4SKashyap, Desai 
7664d069566SKashyap, Desai 					    sc->result =
7674d069566SKashyap, Desai 						    (DID_TRANSPORT_DISRUPTED
7684d069566SKashyap, Desai 						    << 16);
769bf451522SEric Moore 					    break;
770bf451522SEric Moore 				}
77186dd4242SEric Moore 			} else if (ioc->bus_type == FC) {
77286dd4242SEric Moore 				/*
77386dd4242SEric Moore 				 * The FC IOC may kill a request for variety of
77486dd4242SEric Moore 				 * reasons, some of which may be recovered by a
77586dd4242SEric Moore 				 * retry, some which are unlikely to be
77686dd4242SEric Moore 				 * recovered. Return DID_ERROR instead of
77786dd4242SEric Moore 				 * DID_RESET to permit retry of the command,
77886dd4242SEric Moore 				 * just not an infinite number of them
77986dd4242SEric Moore 				 */
78086dd4242SEric Moore 				sc->result = DID_ERROR << 16;
78186dd4242SEric Moore 				break;
782bf451522SEric Moore 			}
783bf451522SEric Moore 
784bf451522SEric Moore 			/*
785bf451522SEric Moore 			 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
786bf451522SEric Moore 			 */
787df561f66SGustavo A. R. Silva 			fallthrough;
788bf451522SEric Moore 
789bf451522SEric Moore 		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
7901da177e4SLinus Torvalds 			/* Linux handles an unsolicited DID_RESET better
7911da177e4SLinus Torvalds 			 * than an unsolicited DID_ABORT.
7921da177e4SLinus Torvalds 			 */
7931da177e4SLinus Torvalds 			sc->result = DID_RESET << 16;
7943012d60bSAlan Cox 			break;
7951da177e4SLinus Torvalds 
7962f187862SKashyap, Desai 		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
7972f187862SKashyap, Desai 			if (ioc->bus_type == FC)
7982f187862SKashyap, Desai 				sc->result = DID_ERROR << 16;
7992f187862SKashyap, Desai 			else
8002f187862SKashyap, Desai 				sc->result = DID_RESET << 16;
8011da177e4SLinus Torvalds 			break;
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
8041928d73fSFUJITA Tomonori 			scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
805466544d8SMoore, Eric Dean 			if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
8061da177e4SLinus Torvalds 				sc->result=DID_SOFT_ERROR << 16;
807466544d8SMoore, Eric Dean 			else /* Sufficient data transfer occurred */
808466544d8SMoore, Eric Dean 				sc->result = (DID_OK << 16) | scsi_status;
80929dd3609SEric Moore 			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
810c6c727a1SEric Moore 			    "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
81129dd3609SEric Moore 			    ioc->name, sc->result, sc->device->channel, sc->device->id));
8121da177e4SLinus Torvalds 			break;
8131da177e4SLinus Torvalds 
8141da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
8151da177e4SLinus Torvalds 			/*
8161da177e4SLinus Torvalds 			 *  Do upfront check for valid SenseData and give it
8171da177e4SLinus Torvalds 			 *  precedence!
8181da177e4SLinus Torvalds 			 */
8191da177e4SLinus Torvalds 			sc->result = (DID_OK << 16) | scsi_status;
8209b53b392SKashyap, Desai 			if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
8219b53b392SKashyap, Desai 
8229b53b392SKashyap, Desai 				/*
8239b53b392SKashyap, Desai 				 * For an Errata on LSI53C1030
8249b53b392SKashyap, Desai 				 * When the length of request data
8259b53b392SKashyap, Desai 				 * and transfer data are different
8269b53b392SKashyap, Desai 				 * with result of command (READ or VERIFY),
8279b53b392SKashyap, Desai 				 * DID_SOFT_ERROR is set.
8281da177e4SLinus Torvalds 				 */
8299b53b392SKashyap, Desai 				if (ioc->bus_type == SPI) {
830e466e1c6SKashyap, Desai 					if ((pScsiReq->CDB[0] == READ_6  && ((pScsiReq->CDB[1] & 0x02) == 0)) ||
8319b53b392SKashyap, Desai 					    pScsiReq->CDB[0] == READ_10 ||
8329b53b392SKashyap, Desai 					    pScsiReq->CDB[0] == READ_12 ||
833513382c9Snagalakshmi.nandigama@lsi.com 						(pScsiReq->CDB[0] == READ_16 &&
834513382c9Snagalakshmi.nandigama@lsi.com 						((pScsiReq->CDB[1] & 0x02) == 0)) ||
8359b53b392SKashyap, Desai 					    pScsiReq->CDB[0] == VERIFY  ||
8369b53b392SKashyap, Desai 					    pScsiReq->CDB[0] == VERIFY_16) {
8379b53b392SKashyap, Desai 						if (scsi_bufflen(sc) !=
8389b53b392SKashyap, Desai 							xfer_cnt) {
8399b53b392SKashyap, Desai 							sc->result =
8409b53b392SKashyap, Desai 							DID_SOFT_ERROR << 16;
8419b53b392SKashyap, Desai 						    printk(KERN_WARNING "Errata"
8429b53b392SKashyap, Desai 						    "on LSI53C1030 occurred."
8439b53b392SKashyap, Desai 						    "sc->req_bufflen=0x%02x,"
8449b53b392SKashyap, Desai 						    "xfer_cnt=0x%02x\n",
8459b53b392SKashyap, Desai 						    scsi_bufflen(sc),
8469b53b392SKashyap, Desai 						    xfer_cnt);
8479b53b392SKashyap, Desai 						}
8489b53b392SKashyap, Desai 					}
8499b53b392SKashyap, Desai 				}
8509b53b392SKashyap, Desai 
8511da177e4SLinus Torvalds 				if (xfer_cnt < sc->underflow) {
852466544d8SMoore, Eric Dean 					if (scsi_status == SAM_STAT_BUSY)
853466544d8SMoore, Eric Dean 						sc->result = SAM_STAT_BUSY;
854466544d8SMoore, Eric Dean 					else
8551da177e4SLinus Torvalds 						sc->result = DID_SOFT_ERROR << 16;
8561da177e4SLinus Torvalds 				}
8571da177e4SLinus Torvalds 				if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
8581da177e4SLinus Torvalds 					/* What to do?
8591da177e4SLinus Torvalds 				 	*/
8601da177e4SLinus Torvalds 					sc->result = DID_SOFT_ERROR << 16;
8611da177e4SLinus Torvalds 				}
8621da177e4SLinus Torvalds 				else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
8631da177e4SLinus Torvalds 					/*  Not real sure here either...  */
8641da177e4SLinus Torvalds 					sc->result = DID_RESET << 16;
8651da177e4SLinus Torvalds 				}
8661da177e4SLinus Torvalds 			}
8671da177e4SLinus Torvalds 
8686757d6b4SPrakash, Sathya 
86929dd3609SEric Moore 			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
87029dd3609SEric Moore 			    "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
87129dd3609SEric Moore 			    ioc->name, sc->underflow));
87229dd3609SEric Moore 			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
87329dd3609SEric Moore 			    "  ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
8746757d6b4SPrakash, Sathya 
8751da177e4SLinus Torvalds 			/* Report Queue Full
8761da177e4SLinus Torvalds 			 */
8771da177e4SLinus Torvalds 			if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
8781da177e4SLinus Torvalds 				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds 			break;
8811da177e4SLinus Torvalds 
8827e55147fSMoore, Eric 		case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:		/* 0x0044 */
8831928d73fSFUJITA Tomonori 			scsi_set_resid(sc, 0);
884df561f66SGustavo A. R. Silva 			fallthrough;
8851da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
8861da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
8871da177e4SLinus Torvalds 			sc->result = (DID_OK << 16) | scsi_status;
8881da177e4SLinus Torvalds 			if (scsi_state == 0) {
8891da177e4SLinus Torvalds 				;
8909b53b392SKashyap, Desai 			} else if (scsi_state &
8919b53b392SKashyap, Desai 			    MPI_SCSI_STATE_AUTOSENSE_VALID) {
8929b53b392SKashyap, Desai 
8939b53b392SKashyap, Desai 				/*
8949b53b392SKashyap, Desai 				 * For potential trouble on LSI53C1030.
8959b53b392SKashyap, Desai 				 * (date:2007.xx.)
8969b53b392SKashyap, Desai 				 * It is checked whether the length of
8979b53b392SKashyap, Desai 				 * request data is equal to
8989b53b392SKashyap, Desai 				 * the length of transfer and residual.
8999b53b392SKashyap, Desai 				 * MEDIUM_ERROR is set by incorrect data.
9009b53b392SKashyap, Desai 				 */
9019b53b392SKashyap, Desai 				if ((ioc->bus_type == SPI) &&
9029b53b392SKashyap, Desai 					(sc->sense_buffer[2] & 0x20)) {
9039b53b392SKashyap, Desai 					u32	 difftransfer;
9049b53b392SKashyap, Desai 					difftransfer =
9059b53b392SKashyap, Desai 					sc->sense_buffer[3] << 24 |
9069b53b392SKashyap, Desai 					sc->sense_buffer[4] << 16 |
9079b53b392SKashyap, Desai 					sc->sense_buffer[5] << 8 |
9089b53b392SKashyap, Desai 					sc->sense_buffer[6];
9099b53b392SKashyap, Desai 					if (((sc->sense_buffer[3] & 0x80) ==
9109b53b392SKashyap, Desai 						0x80) && (scsi_bufflen(sc)
9119b53b392SKashyap, Desai 						!= xfer_cnt)) {
9129b53b392SKashyap, Desai 						sc->sense_buffer[2] =
9139b53b392SKashyap, Desai 						    MEDIUM_ERROR;
9149b53b392SKashyap, Desai 						sc->sense_buffer[12] = 0xff;
9159b53b392SKashyap, Desai 						sc->sense_buffer[13] = 0xff;
9169b53b392SKashyap, Desai 						printk(KERN_WARNING"Errata"
9179b53b392SKashyap, Desai 						"on LSI53C1030 occurred."
9189b53b392SKashyap, Desai 						"sc->req_bufflen=0x%02x,"
9199b53b392SKashyap, Desai 						"xfer_cnt=0x%02x\n" ,
9209b53b392SKashyap, Desai 						scsi_bufflen(sc),
9219b53b392SKashyap, Desai 						xfer_cnt);
9229b53b392SKashyap, Desai 					}
9239b53b392SKashyap, Desai 					if (((sc->sense_buffer[3] & 0x80)
9249b53b392SKashyap, Desai 						!= 0x80) &&
9259b53b392SKashyap, Desai 						(scsi_bufflen(sc) !=
9269b53b392SKashyap, Desai 						xfer_cnt + difftransfer)) {
9279b53b392SKashyap, Desai 						sc->sense_buffer[2] =
9289b53b392SKashyap, Desai 							MEDIUM_ERROR;
9299b53b392SKashyap, Desai 						sc->sense_buffer[12] = 0xff;
9309b53b392SKashyap, Desai 						sc->sense_buffer[13] = 0xff;
9319b53b392SKashyap, Desai 						printk(KERN_WARNING
9329b53b392SKashyap, Desai 						"Errata on LSI53C1030 occurred"
9339b53b392SKashyap, Desai 						"sc->req_bufflen=0x%02x,"
9349b53b392SKashyap, Desai 						" xfer_cnt=0x%02x,"
9359b53b392SKashyap, Desai 						"difftransfer=0x%02x\n",
9369b53b392SKashyap, Desai 						scsi_bufflen(sc),
9379b53b392SKashyap, Desai 						xfer_cnt,
9389b53b392SKashyap, Desai 						difftransfer);
9399b53b392SKashyap, Desai 					}
9409b53b392SKashyap, Desai 				}
9419b53b392SKashyap, Desai 
9421da177e4SLinus Torvalds 				/*
9431da177e4SLinus Torvalds 				 * If running against circa 200003dd 909 MPT f/w,
9441da177e4SLinus Torvalds 				 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
9451da177e4SLinus Torvalds 				 * (QUEUE_FULL) returned from device! --> get 0x0000?128
9461da177e4SLinus Torvalds 				 * and with SenseBytes set to 0.
9471da177e4SLinus Torvalds 				 */
9481da177e4SLinus Torvalds 				if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
9491da177e4SLinus Torvalds 					mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds 			}
9521da177e4SLinus Torvalds 			else if (scsi_state &
9531da177e4SLinus Torvalds 			         (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
9541da177e4SLinus Torvalds 			   ) {
9551da177e4SLinus Torvalds 				/*
9561da177e4SLinus Torvalds 				 * What to do?
9571da177e4SLinus Torvalds 				 */
9581da177e4SLinus Torvalds 				sc->result = DID_SOFT_ERROR << 16;
9591da177e4SLinus Torvalds 			}
9601da177e4SLinus Torvalds 			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
9611da177e4SLinus Torvalds 				/*  Not real sure here either...  */
9621da177e4SLinus Torvalds 				sc->result = DID_RESET << 16;
9631da177e4SLinus Torvalds 			}
9641da177e4SLinus Torvalds 			else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
9651da177e4SLinus Torvalds 				/* Device Inq. data indicates that it supports
9661da177e4SLinus Torvalds 				 * QTags, but rejects QTag messages.
9671da177e4SLinus Torvalds 				 * This command completed OK.
9681da177e4SLinus Torvalds 				 *
9691da177e4SLinus Torvalds 				 * Not real sure here either so do nothing...  */
9701da177e4SLinus Torvalds 			}
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
9731da177e4SLinus Torvalds 				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 			/* Add handling of:
9761da177e4SLinus Torvalds 			 * Reservation Conflict, Busy,
9771da177e4SLinus Torvalds 			 * Command Terminated, CHECK
9781da177e4SLinus Torvalds 			 */
9791da177e4SLinus Torvalds 			break;
9801da177e4SLinus Torvalds 
9811da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
9821da177e4SLinus Torvalds 			sc->result = DID_SOFT_ERROR << 16;
9831da177e4SLinus Torvalds 			break;
9841da177e4SLinus Torvalds 
9851da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_FUNCTION:		/* 0x0001 */
9861da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_SGL:			/* 0x0003 */
9871da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INTERNAL_ERROR:		/* 0x0004 */
9881da177e4SLinus Torvalds 		case MPI_IOCSTATUS_RESERVED:			/* 0x0005 */
9891da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_FIELD:		/* 0x0007 */
9901da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_STATE:		/* 0x0008 */
9911da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
9921da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:	/* 0x004A */
9931da177e4SLinus Torvalds 		default:
9941da177e4SLinus Torvalds 			/*
9951da177e4SLinus Torvalds 			 * What to do?
9961da177e4SLinus Torvalds 			 */
9971da177e4SLinus Torvalds 			sc->result = DID_SOFT_ERROR << 16;
9981da177e4SLinus Torvalds 			break;
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds 		}	/* switch(status) */
10011da177e4SLinus Torvalds 
10026757d6b4SPrakash, Sathya #ifdef CONFIG_FUSION_LOGGING
10036757d6b4SPrakash, Sathya 		if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
10046757d6b4SPrakash, Sathya 			mptscsih_info_scsiio(ioc, sc, pScsiReply);
1005c6c727a1SEric Moore #endif
1006c6c727a1SEric Moore 
10071da177e4SLinus Torvalds 	} /* end of address reply case */
1008fea98403SKashyap, Desai out:
10091da177e4SLinus Torvalds 	/* Unmap the DMA buffers, if any. */
10101928d73fSFUJITA Tomonori 	scsi_dma_unmap(sc);
10111da177e4SLinus Torvalds 
10121ae6d167SBart Van Assche 	scsi_done(sc);			/* Issue the command callback */
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds 	/* Free Chain buffers */
10151da177e4SLinus Torvalds 	mptscsih_freeChainBuffers(ioc, req_idx);
10161da177e4SLinus Torvalds 	return 1;
10171da177e4SLinus Torvalds }
10181da177e4SLinus Torvalds 
10191da177e4SLinus Torvalds /*
10201da177e4SLinus Torvalds  *	mptscsih_flush_running_cmds - For each command found, search
10211da177e4SLinus Torvalds  *		Scsi_Host instance taskQ and reply to OS.
10221da177e4SLinus Torvalds  *		Called only if recovering from a FW reload.
10231da177e4SLinus Torvalds  *	@hd: Pointer to a SCSI HOST structure
10241da177e4SLinus Torvalds  *
10251da177e4SLinus Torvalds  *	Returns: None.
10261da177e4SLinus Torvalds  *
10271da177e4SLinus Torvalds  *	Must be called while new I/Os are being queued.
10281da177e4SLinus Torvalds  */
1029e62cca19Skashyap.desai@lsi.com void
mptscsih_flush_running_cmds(MPT_SCSI_HOST * hd)10301da177e4SLinus Torvalds mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
10311da177e4SLinus Torvalds {
10321da177e4SLinus Torvalds 	MPT_ADAPTER *ioc = hd->ioc;
1033e8206381SEric Moore 	struct scsi_cmnd *sc;
1034e8206381SEric Moore 	SCSIIORequest_t	*mf = NULL;
10351da177e4SLinus Torvalds 	int		 ii;
1036e8206381SEric Moore 	int		 channel, id;
10371da177e4SLinus Torvalds 
1038e8206381SEric Moore 	for (ii= 0; ii < ioc->req_depth; ii++) {
1039e8206381SEric Moore 		sc = mptscsih_getclear_scsi_lookup(ioc, ii);
1040e8206381SEric Moore 		if (!sc)
10413dc0b03fSEric Moore 			continue;
1042e8206381SEric Moore 		mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
1043e8206381SEric Moore 		if (!mf)
1044e8206381SEric Moore 			continue;
1045e8206381SEric Moore 		channel = mf->Bus;
1046e8206381SEric Moore 		id = mf->TargetID;
1047e8206381SEric Moore 		mptscsih_freeChainBuffers(ioc, ii);
1048e8206381SEric Moore 		mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
1049e8206381SEric Moore 		if ((unsigned char *)mf != sc->host_scribble)
1050e8206381SEric Moore 			continue;
1051e8206381SEric Moore 		scsi_dma_unmap(sc);
1052e8206381SEric Moore 		sc->result = DID_RESET << 16;
1053e8206381SEric Moore 		sc->host_scribble = NULL;
10542f187862SKashyap, Desai 		dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
10552f187862SKashyap, Desai 		    "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
10562f187862SKashyap, Desai 		    "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
10571ae6d167SBart Van Assche 		scsi_done(sc);
10581da177e4SLinus Torvalds 	}
10591da177e4SLinus Torvalds }
1060e62cca19Skashyap.desai@lsi.com EXPORT_SYMBOL(mptscsih_flush_running_cmds);
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds /*
10631da177e4SLinus Torvalds  *	mptscsih_search_running_cmds - Delete any commands associated
10641da177e4SLinus Torvalds  *		with the specified target and lun. Function called only
10651da177e4SLinus Torvalds  *		when a lun is disable by mid-layer.
10661da177e4SLinus Torvalds  *		Do NOT access the referenced scsi_cmnd structure or
10671da177e4SLinus Torvalds  *		members. Will cause either a paging or NULL ptr error.
106805e8ec17SMichael Reed  *		(BUT, BUT, BUT, the code does reference it! - mdr)
10691da177e4SLinus Torvalds  *      @hd: Pointer to a SCSI HOST structure
1070c7c82987SMoore, Eric Dean  *	@vdevice: per device private data
10711da177e4SLinus Torvalds  *
10721da177e4SLinus Torvalds  *	Returns: None.
10731da177e4SLinus Torvalds  *
10741da177e4SLinus Torvalds  *	Called from slave_destroy.
10751da177e4SLinus Torvalds  */
10761da177e4SLinus Torvalds static void
mptscsih_search_running_cmds(MPT_SCSI_HOST * hd,VirtDevice * vdevice)1077c7c82987SMoore, Eric Dean mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
10781da177e4SLinus Torvalds {
10791da177e4SLinus Torvalds 	SCSIIORequest_t	*mf = NULL;
10801da177e4SLinus Torvalds 	int		 ii;
1081466544d8SMoore, Eric Dean 	struct scsi_cmnd *sc;
1082793955f5SEric Moore 	struct scsi_lun  lun;
1083e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
1084e8206381SEric Moore 	unsigned long	flags;
10851da177e4SLinus Torvalds 
1086e8206381SEric Moore 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
1087e8206381SEric Moore 	for (ii = 0; ii < ioc->req_depth; ii++) {
1088e8206381SEric Moore 		if ((sc = ioc->ScsiLookup[ii]) != NULL) {
10891da177e4SLinus Torvalds 
1090e80b002bSEric Moore 			mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
10913dc0b03fSEric Moore 			if (mf == NULL)
10923dc0b03fSEric Moore 				continue;
1093cc78d30aSEric Moore 			/* If the device is a hidden raid component, then its
1094cc78d30aSEric Moore 			 * expected that the mf->function will be RAID_SCSI_IO
1095cc78d30aSEric Moore 			 */
1096cc78d30aSEric Moore 			if (vdevice->vtarget->tflags &
1097cc78d30aSEric Moore 			    MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1098cc78d30aSEric Moore 			    MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1099cc78d30aSEric Moore 				continue;
1100cc78d30aSEric Moore 
1101793955f5SEric Moore 			int_to_scsilun(vdevice->lun, &lun);
1102793955f5SEric Moore 			if ((mf->Bus != vdevice->vtarget->channel) ||
1103793955f5SEric Moore 			    (mf->TargetID != vdevice->vtarget->id) ||
1104793955f5SEric Moore 			    memcmp(lun.scsi_lun, mf->LUN, 8))
11051da177e4SLinus Torvalds 				continue;
11061da177e4SLinus Torvalds 
11073dc0b03fSEric Moore 			if ((unsigned char *)mf != sc->host_scribble)
11083dc0b03fSEric Moore 				continue;
1109e8206381SEric Moore 			ioc->ScsiLookup[ii] = NULL;
1110e8206381SEric Moore 			spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
1111e8206381SEric Moore 			mptscsih_freeChainBuffers(ioc, ii);
1112e8206381SEric Moore 			mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
11131928d73fSFUJITA Tomonori 			scsi_dma_unmap(sc);
1114466544d8SMoore, Eric Dean 			sc->host_scribble = NULL;
1115466544d8SMoore, Eric Dean 			sc->result = DID_NO_CONNECT << 16;
11162f187862SKashyap, Desai 			dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
11172f187862SKashyap, Desai 			   MYIOC_s_FMT "completing cmds: fw_channel %d, "
11182f187862SKashyap, Desai 			   "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
11192f187862SKashyap, Desai 			   vdevice->vtarget->channel, vdevice->vtarget->id,
11202f187862SKashyap, Desai 			   sc, mf, ii));
11211ae6d167SBart Van Assche 			scsi_done(sc);
1122e8206381SEric Moore 			spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
11231da177e4SLinus Torvalds 		}
11241da177e4SLinus Torvalds 	}
1125e8206381SEric Moore 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
11261da177e4SLinus Torvalds 	return;
11271da177e4SLinus Torvalds }
11281da177e4SLinus Torvalds 
11291da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11321da177e4SLinus Torvalds /*
11331da177e4SLinus Torvalds  *	mptscsih_report_queue_full - Report QUEUE_FULL status returned
11341da177e4SLinus Torvalds  *	from a SCSI target device.
11351da177e4SLinus Torvalds  *	@sc: Pointer to scsi_cmnd structure
11361da177e4SLinus Torvalds  *	@pScsiReply: Pointer to SCSIIOReply_t
11371da177e4SLinus Torvalds  *	@pScsiReq: Pointer to original SCSI request
11381da177e4SLinus Torvalds  *
11391da177e4SLinus Torvalds  *	This routine periodically reports QUEUE_FULL status returned from a
11401da177e4SLinus Torvalds  *	SCSI target device.  It reports this to the console via kernel
11411da177e4SLinus Torvalds  *	printk() API call, not more than once every 10 seconds.
11421da177e4SLinus Torvalds  */
11431da177e4SLinus Torvalds static void
mptscsih_report_queue_full(struct scsi_cmnd * sc,SCSIIOReply_t * pScsiReply,SCSIIORequest_t * pScsiReq)11441da177e4SLinus Torvalds mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
11451da177e4SLinus Torvalds {
11461da177e4SLinus Torvalds 	long time = jiffies;
11471da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
1148e80b002bSEric Moore 	MPT_ADAPTER	*ioc;
11491da177e4SLinus Torvalds 
11500d0c7974SMoore, Eric Dean  	if (sc->device == NULL)
11510d0c7974SMoore, Eric Dean  		return;
11520d0c7974SMoore, Eric Dean  	if (sc->device->host == NULL)
11530d0c7974SMoore, Eric Dean  		return;
1154e7eae9f6SEric Moore 	if ((hd = shost_priv(sc->device->host)) == NULL)
11550d0c7974SMoore, Eric Dean  		return;
1156e80b002bSEric Moore 	ioc = hd->ioc;
11570d0c7974SMoore, Eric Dean  	if (time - hd->last_queue_full > 10 * HZ) {
11589cb78c16SHannes Reinecke 		dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%llu) reported QUEUE_FULL!\n",
1159e80b002bSEric Moore 				ioc->name, 0, sc->device->id, sc->device->lun));
11600d0c7974SMoore, Eric Dean  		hd->last_queue_full = time;
11611da177e4SLinus Torvalds 	}
11621da177e4SLinus Torvalds }
11631da177e4SLinus Torvalds 
11641da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11651da177e4SLinus Torvalds /*
11661da177e4SLinus Torvalds  *	mptscsih_remove - Removed scsi devices
11671da177e4SLinus Torvalds  *	@pdev: Pointer to pci_dev structure
11681da177e4SLinus Torvalds  *
11691da177e4SLinus Torvalds  *
11701da177e4SLinus Torvalds  */
11710d0c7974SMoore, Eric Dean  void
mptscsih_remove(struct pci_dev * pdev)11721da177e4SLinus Torvalds mptscsih_remove(struct pci_dev *pdev)
11731da177e4SLinus Torvalds {
11741da177e4SLinus Torvalds 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
11751da177e4SLinus Torvalds 	struct Scsi_Host 	*host = ioc->sh;
11761da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
11770d0c7974SMoore, Eric Dean  	int sz1;
11781da177e4SLinus Torvalds 
11792f4843b1SHelge Deller 	if (host == NULL)
11802f4843b1SHelge Deller 		hd = NULL;
11812f4843b1SHelge Deller 	else
11822f4843b1SHelge Deller 		hd = shost_priv(host);
11830d0c7974SMoore, Eric Dean  
1184d18c3db5SGreg Kroah-Hartman 	mptscsih_shutdown(pdev);
11851da177e4SLinus Torvalds 
11861da177e4SLinus Torvalds 	sz1=0;
11871da177e4SLinus Torvalds 
1188e8206381SEric Moore 	if (ioc->ScsiLookup != NULL) {
1189e80b002bSEric Moore 		sz1 = ioc->req_depth * sizeof(void *);
1190e8206381SEric Moore 		kfree(ioc->ScsiLookup);
1191e8206381SEric Moore 		ioc->ScsiLookup = NULL;
11921da177e4SLinus Torvalds 	}
11931da177e4SLinus Torvalds 
1194e80b002bSEric Moore 	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
11951da177e4SLinus Torvalds 	    "Free'd ScsiLookup (%d) memory\n",
1196e80b002bSEric Moore 	    ioc->name, sz1));
11971da177e4SLinus Torvalds 
11982f4843b1SHelge Deller 	if (hd)
11990d0c7974SMoore, Eric Dean  		kfree(hd->info_kbuf);
12000d0c7974SMoore, Eric Dean  
12011da177e4SLinus Torvalds 	/* NULL the Scsi_Host pointer
12021da177e4SLinus Torvalds 	 */
1203e80b002bSEric Moore 	ioc->sh = NULL;
12041da177e4SLinus Torvalds 
12052f4843b1SHelge Deller 	if (host)
12061da177e4SLinus Torvalds 		scsi_host_put(host);
12070d0c7974SMoore, Eric Dean  	mpt_detach(pdev);
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds }
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12121da177e4SLinus Torvalds /*
12131da177e4SLinus Torvalds  *	mptscsih_shutdown - reboot notifier
12141da177e4SLinus Torvalds  *
12151da177e4SLinus Torvalds  */
12160d0c7974SMoore, Eric Dean  void
mptscsih_shutdown(struct pci_dev * pdev)1217d18c3db5SGreg Kroah-Hartman mptscsih_shutdown(struct pci_dev *pdev)
12181da177e4SLinus Torvalds {
12191da177e4SLinus Torvalds }
12201da177e4SLinus Torvalds 
12211da177e4SLinus Torvalds #ifdef CONFIG_PM
12221da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12231da177e4SLinus Torvalds /*
12240d0c7974SMoore, Eric Dean   *	mptscsih_suspend - Fusion MPT scsi driver suspend routine.
12251da177e4SLinus Torvalds  *
12261da177e4SLinus Torvalds  *
12271da177e4SLinus Torvalds  */
12280d0c7974SMoore, Eric Dean  int
mptscsih_suspend(struct pci_dev * pdev,pm_message_t state)12298d189f72SPavel Machek mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
12301da177e4SLinus Torvalds {
12314d4109d0SPrakash, Sathya 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
12324d4109d0SPrakash, Sathya 
12334d4109d0SPrakash, Sathya 	scsi_block_requests(ioc->sh);
1234d18c3db5SGreg Kroah-Hartman 	mptscsih_shutdown(pdev);
12350d0c7974SMoore, Eric Dean  	return mpt_suspend(pdev,state);
12361da177e4SLinus Torvalds }
12371da177e4SLinus Torvalds 
12381da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12391da177e4SLinus Torvalds /*
12401da177e4SLinus Torvalds  *	mptscsih_resume - Fusion MPT scsi driver resume routine.
12411da177e4SLinus Torvalds  *
12421da177e4SLinus Torvalds  *
12431da177e4SLinus Torvalds  */
12440d0c7974SMoore, Eric Dean  int
mptscsih_resume(struct pci_dev * pdev)12451da177e4SLinus Torvalds mptscsih_resume(struct pci_dev *pdev)
12461da177e4SLinus Torvalds {
12474d4109d0SPrakash, Sathya 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
12484d4109d0SPrakash, Sathya 	int rc;
12494d4109d0SPrakash, Sathya 
12504d4109d0SPrakash, Sathya 	rc = mpt_resume(pdev);
12514d4109d0SPrakash, Sathya 	scsi_unblock_requests(ioc->sh);
12524d4109d0SPrakash, Sathya 	return rc;
12531da177e4SLinus Torvalds }
12541da177e4SLinus Torvalds 
12551da177e4SLinus Torvalds #endif
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12581da177e4SLinus Torvalds /**
12591da177e4SLinus Torvalds  *	mptscsih_info - Return information about MPT adapter
12601da177e4SLinus Torvalds  *	@SChost: Pointer to Scsi_Host structure
12611da177e4SLinus Torvalds  *
12621da177e4SLinus Torvalds  *	(linux scsi_host_template.info routine)
12631da177e4SLinus Torvalds  *
12641da177e4SLinus Torvalds  *	Returns pointer to buffer where information was written.
12651da177e4SLinus Torvalds  */
12660d0c7974SMoore, Eric Dean  const char *
mptscsih_info(struct Scsi_Host * SChost)12671da177e4SLinus Torvalds mptscsih_info(struct Scsi_Host *SChost)
12681da177e4SLinus Torvalds {
12691da177e4SLinus Torvalds 	MPT_SCSI_HOST *h;
12701da177e4SLinus Torvalds 	int size = 0;
12711da177e4SLinus Torvalds 
1272e7eae9f6SEric Moore 	h = shost_priv(SChost);
12730d0c7974SMoore, Eric Dean  
12740d0c7974SMoore, Eric Dean  	if (h->info_kbuf == NULL)
12750d0c7974SMoore, Eric Dean  		if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
12760d0c7974SMoore, Eric Dean  			return h->info_kbuf;
12770d0c7974SMoore, Eric Dean  	h->info_kbuf[0] = '\0';
12780d0c7974SMoore, Eric Dean  
12790d0c7974SMoore, Eric Dean  	mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
12800d0c7974SMoore, Eric Dean  	h->info_kbuf[size-1] = '\0';
12811da177e4SLinus Torvalds 
12820d0c7974SMoore, Eric Dean  	return h->info_kbuf;
12831da177e4SLinus Torvalds }
12841da177e4SLinus Torvalds 
mptscsih_show_info(struct seq_file * m,struct Scsi_Host * host)1285cac19703SAl Viro int mptscsih_show_info(struct seq_file *m, struct Scsi_Host *host)
12861da177e4SLinus Torvalds {
1287e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
12881da177e4SLinus Torvalds 	MPT_ADAPTER	*ioc = hd->ioc;
12891da177e4SLinus Torvalds 
1290cac19703SAl Viro 	seq_printf(m, "%s: %s, ", ioc->name, ioc->prod_name);
1291cac19703SAl Viro 	seq_printf(m, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1292cac19703SAl Viro 	seq_printf(m, "Ports=%d, ", ioc->facts.NumberOfPorts);
1293cac19703SAl Viro 	seq_printf(m, "MaxQ=%d\n", ioc->req_depth);
12941da177e4SLinus Torvalds 
1295cac19703SAl Viro 	return 0;
12961da177e4SLinus Torvalds }
12971da177e4SLinus Torvalds 
12981da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12991da177e4SLinus Torvalds #define ADD_INDEX_LOG(req_ent)	do { } while(0)
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13021da177e4SLinus Torvalds /**
13031da177e4SLinus Torvalds  *	mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
13041da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure
13051da177e4SLinus Torvalds  *
13061da177e4SLinus Torvalds  *	(linux scsi_host_template.queuecommand routine)
13071da177e4SLinus Torvalds  *	This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
13081da177e4SLinus Torvalds  *	from a linux scsi_cmnd request and send it to the IOC.
13091da177e4SLinus Torvalds  *
13101da177e4SLinus Torvalds  *	Returns 0. (rtn value discarded by linux scsi mid-layer)
13111da177e4SLinus Torvalds  */
13120d0c7974SMoore, Eric Dean  int
mptscsih_qcmd(struct scsi_cmnd * SCpnt)1313a48ac9e5SMatthew Wilcox mptscsih_qcmd(struct scsi_cmnd *SCpnt)
13141da177e4SLinus Torvalds {
13151da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
13161da177e4SLinus Torvalds 	MPT_FRAME_HDR		*mf;
13171da177e4SLinus Torvalds 	SCSIIORequest_t		*pScsiReq;
1318a69de507SEric Moore 	VirtDevice		*vdevice = SCpnt->device->hostdata;
13191da177e4SLinus Torvalds 	u32	 datalen;
13201da177e4SLinus Torvalds 	u32	 scsictl;
13211da177e4SLinus Torvalds 	u32	 scsidir;
13221da177e4SLinus Torvalds 	u32	 cmd_len;
13231da177e4SLinus Torvalds 	int	 my_idx;
13241da177e4SLinus Torvalds 	int	 ii;
13256757d6b4SPrakash, Sathya 	MPT_ADAPTER *ioc;
13261da177e4SLinus Torvalds 
1327e7eae9f6SEric Moore 	hd = shost_priv(SCpnt->device->host);
13286757d6b4SPrakash, Sathya 	ioc = hd->ioc;
13291da177e4SLinus Torvalds 
1330a48ac9e5SMatthew Wilcox 	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p\n",
1331a48ac9e5SMatthew Wilcox 		ioc->name, SCpnt));
13321da177e4SLinus Torvalds 
133356cee8d5SKashyap, Desai 	if (ioc->taskmgmt_quiesce_io)
13341da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
13351da177e4SLinus Torvalds 
13361da177e4SLinus Torvalds 	/*
13371da177e4SLinus Torvalds 	 *  Put together a MPT SCSI request...
13381da177e4SLinus Torvalds 	 */
1339e80b002bSEric Moore 	if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
13406757d6b4SPrakash, Sathya 		dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
13416757d6b4SPrakash, Sathya 				ioc->name));
13421da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
13431da177e4SLinus Torvalds 	}
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 	pScsiReq = (SCSIIORequest_t *) mf;
13461da177e4SLinus Torvalds 
13471da177e4SLinus Torvalds 	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
13481da177e4SLinus Torvalds 
13491da177e4SLinus Torvalds 	ADD_INDEX_LOG(my_idx);
13501da177e4SLinus Torvalds 
13510d0c7974SMoore, Eric Dean  	/*    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
13521da177e4SLinus Torvalds 	 *    Seems we may receive a buffer (datalen>0) even when there
13531da177e4SLinus Torvalds 	 *    will be no data transfer!  GRRRRR...
13541da177e4SLinus Torvalds 	 */
13551da177e4SLinus Torvalds 	if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
13561928d73fSFUJITA Tomonori 		datalen = scsi_bufflen(SCpnt);
13571da177e4SLinus Torvalds 		scsidir = MPI_SCSIIO_CONTROL_READ;	/* DATA IN  (host<--ioc<--dev) */
13581da177e4SLinus Torvalds 	} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
13591928d73fSFUJITA Tomonori 		datalen = scsi_bufflen(SCpnt);
13601da177e4SLinus Torvalds 		scsidir = MPI_SCSIIO_CONTROL_WRITE;	/* DATA OUT (host-->ioc-->dev) */
13611da177e4SLinus Torvalds 	} else {
13621da177e4SLinus Torvalds 		datalen = 0;
13631da177e4SLinus Torvalds 		scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
13641da177e4SLinus Torvalds 	}
13651da177e4SLinus Torvalds 
13661da177e4SLinus Torvalds 	/* Default to untagged. Once a target structure has been allocated,
13671da177e4SLinus Torvalds 	 * use the Inquiry data to determine if device supports tagged.
13681da177e4SLinus Torvalds 	 */
13694e6f767dSChristoph Hellwig 	if ((vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) &&
13704e6f767dSChristoph Hellwig 	    SCpnt->device->tagged_supported)
13711da177e4SLinus Torvalds 		scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
13724e6f767dSChristoph Hellwig 	else
137365f89c23SKashyap, Desai 		scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
137465f89c23SKashyap, Desai 
13751da177e4SLinus Torvalds 
13761da177e4SLinus Torvalds 	/* Use the above information to set up the message frame
13771da177e4SLinus Torvalds 	 */
1378a69de507SEric Moore 	pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1379a69de507SEric Moore 	pScsiReq->Bus = vdevice->vtarget->channel;
13801da177e4SLinus Torvalds 	pScsiReq->ChainOffset = 0;
1381a69de507SEric Moore 	if (vdevice->vtarget->tflags &  MPT_TARGET_FLAGS_RAID_COMPONENT)
1382c92f222eSJames Bottomley 		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1383c92f222eSJames Bottomley 	else
13841da177e4SLinus Torvalds 		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
13851da177e4SLinus Torvalds 	pScsiReq->CDBLength = SCpnt->cmd_len;
13861da177e4SLinus Torvalds 	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
13871da177e4SLinus Torvalds 	pScsiReq->Reserved = 0;
138814d0f0b0SKashyap, Desai 	pScsiReq->MsgFlags = mpt_msg_flags(ioc);
1389793955f5SEric Moore 	int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
13901da177e4SLinus Torvalds 	pScsiReq->Control = cpu_to_le32(scsictl);
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	/*
13931da177e4SLinus Torvalds 	 *  Write SCSI CDB into the message
13941da177e4SLinus Torvalds 	 */
13951da177e4SLinus Torvalds 	cmd_len = SCpnt->cmd_len;
13961da177e4SLinus Torvalds 	for (ii=0; ii < cmd_len; ii++)
13971da177e4SLinus Torvalds 		pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
13981da177e4SLinus Torvalds 
13991da177e4SLinus Torvalds 	for (ii=cmd_len; ii < 16; ii++)
14001da177e4SLinus Torvalds 		pScsiReq->CDB[ii] = 0;
14011da177e4SLinus Torvalds 
14021da177e4SLinus Torvalds 	/* DataLength */
14031da177e4SLinus Torvalds 	pScsiReq->DataLength = cpu_to_le32(datalen);
14041da177e4SLinus Torvalds 
14051da177e4SLinus Torvalds 	/* SenseBuffer low address */
1406e80b002bSEric Moore 	pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
14071da177e4SLinus Torvalds 					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
14081da177e4SLinus Torvalds 
14091da177e4SLinus Torvalds 	/* Now add the SG list
14101da177e4SLinus Torvalds 	 * Always have a SGE even if null length.
14111da177e4SLinus Torvalds 	 */
14121da177e4SLinus Torvalds 	if (datalen == 0) {
14131da177e4SLinus Torvalds 		/* Add a NULL SGE */
141414d0f0b0SKashyap, Desai 		ioc->add_sge((char *)&pScsiReq->SGL,
141514d0f0b0SKashyap, Desai 			MPT_SGE_FLAGS_SSIMPLE_READ | 0,
14161da177e4SLinus Torvalds 			(dma_addr_t) -1);
14171da177e4SLinus Torvalds 	} else {
14181da177e4SLinus Torvalds 		/* Add a 32 or 64 bit SGE */
1419e80b002bSEric Moore 		if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
14201da177e4SLinus Torvalds 			goto fail;
14211da177e4SLinus Torvalds 	}
14221da177e4SLinus Torvalds 
14233dc0b03fSEric Moore 	SCpnt->host_scribble = (unsigned char *)mf;
1424e8206381SEric Moore 	mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
14251da177e4SLinus Torvalds 
1426e80b002bSEric Moore 	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
14276757d6b4SPrakash, Sathya 	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
14286757d6b4SPrakash, Sathya 			ioc->name, SCpnt, mf, my_idx));
142929dd3609SEric Moore 	DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
14301da177e4SLinus Torvalds 	return 0;
14311da177e4SLinus Torvalds 
14321da177e4SLinus Torvalds  fail:
1433e80b002bSEric Moore 	mptscsih_freeChainBuffers(ioc, my_idx);
1434e80b002bSEric Moore 	mpt_free_msg_frame(ioc, mf);
14351da177e4SLinus Torvalds 	return SCSI_MLQUEUE_HOST_BUSY;
14361da177e4SLinus Torvalds }
14371da177e4SLinus Torvalds 
14381da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
14391da177e4SLinus Torvalds /*
14401da177e4SLinus Torvalds  *	mptscsih_freeChainBuffers - Function to free chain buffers associated
14411da177e4SLinus Torvalds  *	with a SCSI IO request
14421da177e4SLinus Torvalds  *	@hd: Pointer to the MPT_SCSI_HOST instance
14431da177e4SLinus Torvalds  *	@req_idx: Index of the SCSI IO request frame.
14441da177e4SLinus Torvalds  *
14451da177e4SLinus Torvalds  *	Called if SG chain buffer allocation fails and mptscsih callbacks.
14461da177e4SLinus Torvalds  *	No return.
14471da177e4SLinus Torvalds  */
14481da177e4SLinus Torvalds static void
mptscsih_freeChainBuffers(MPT_ADAPTER * ioc,int req_idx)14491da177e4SLinus Torvalds mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
14501da177e4SLinus Torvalds {
14511da177e4SLinus Torvalds 	MPT_FRAME_HDR *chain;
14521da177e4SLinus Torvalds 	unsigned long flags;
14531da177e4SLinus Torvalds 	int chain_idx;
14541da177e4SLinus Torvalds 	int next;
14551da177e4SLinus Torvalds 
14561da177e4SLinus Torvalds 	/* Get the first chain index and reset
14571da177e4SLinus Torvalds 	 * tracker state.
14581da177e4SLinus Torvalds 	 */
14591da177e4SLinus Torvalds 	chain_idx = ioc->ReqToChain[req_idx];
14601da177e4SLinus Torvalds 	ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds 	while (chain_idx != MPT_HOST_NO_CHAIN) {
14631da177e4SLinus Torvalds 
14641da177e4SLinus Torvalds 		/* Save the next chain buffer index */
14651da177e4SLinus Torvalds 		next = ioc->ChainToChain[chain_idx];
14661da177e4SLinus Torvalds 
14671da177e4SLinus Torvalds 		/* Free this chain buffer and reset
14681da177e4SLinus Torvalds 		 * tracker
14691da177e4SLinus Torvalds 		 */
14701da177e4SLinus Torvalds 		ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
14711da177e4SLinus Torvalds 
14721da177e4SLinus Torvalds 		chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
14731da177e4SLinus Torvalds 					+ (chain_idx * ioc->req_sz));
14741da177e4SLinus Torvalds 
14751da177e4SLinus Torvalds 		spin_lock_irqsave(&ioc->FreeQlock, flags);
14761da177e4SLinus Torvalds 		list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
14771da177e4SLinus Torvalds 		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
14781da177e4SLinus Torvalds 
14796757d6b4SPrakash, Sathya 		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
14801da177e4SLinus Torvalds 				ioc->name, chain_idx));
14811da177e4SLinus Torvalds 
14821da177e4SLinus Torvalds 		/* handle next */
14831da177e4SLinus Torvalds 		chain_idx = next;
14841da177e4SLinus Torvalds 	}
14851da177e4SLinus Torvalds 	return;
14861da177e4SLinus Torvalds }
14871da177e4SLinus Torvalds 
14881da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
14891da177e4SLinus Torvalds /*
14901da177e4SLinus Torvalds  *	Reset Handling
14911da177e4SLinus Torvalds  */
14921da177e4SLinus Torvalds 
14931da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1494cd2c6191SEric Moore /**
14951da177e4SLinus Torvalds  *	mptscsih_IssueTaskMgmt - Generic send Task Management function.
14961da177e4SLinus Torvalds  *	@hd: Pointer to MPT_SCSI_HOST structure
14971da177e4SLinus Torvalds  *	@type: Task Management type
14981544d677SRandy Dunlap  *	@channel: channel number for task management
1499793955f5SEric Moore  *	@id: Logical Target ID for reset (if appropriate)
15001da177e4SLinus Torvalds  *	@lun: Logical Unit for reset (if appropriate)
15011da177e4SLinus Torvalds  *	@ctx2abort: Context for the task to be aborted (if appropriate)
15021544d677SRandy Dunlap  *	@timeout: timeout for task management control
15031da177e4SLinus Torvalds  *
15041da177e4SLinus Torvalds  *	Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
15051da177e4SLinus Torvalds  *	or a non-interrupt thread.  In the former, must not call schedule().
15061da177e4SLinus Torvalds  *
15071da177e4SLinus Torvalds  *	Not all fields are meaningfull for all task types.
15081da177e4SLinus Torvalds  *
1509cd2c6191SEric Moore  *	Returns 0 for SUCCESS, or FAILED.
1510cd2c6191SEric Moore  *
1511cd2c6191SEric Moore  **/
15121ba9ab2eSKashyap, Desai int
mptscsih_IssueTaskMgmt(MPT_SCSI_HOST * hd,u8 type,u8 channel,u8 id,u64 lun,int ctx2abort,ulong timeout)15139cb78c16SHannes Reinecke mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, u64 lun,
15141ba9ab2eSKashyap, Desai 	int ctx2abort, ulong timeout)
15151da177e4SLinus Torvalds {
15161da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
15171da177e4SLinus Torvalds 	SCSITaskMgmt_t	*pScsiTm;
15181da177e4SLinus Torvalds 	int		 ii;
15191da177e4SLinus Torvalds 	int		 retval;
1520e80b002bSEric Moore 	MPT_ADAPTER 	*ioc = hd->ioc;
15211ba9ab2eSKashyap, Desai 	u8		 issue_hard_reset;
15221ba9ab2eSKashyap, Desai 	u32		 ioc_raw_state;
15231ba9ab2eSKashyap, Desai 	unsigned long	 time_count;
15241ba9ab2eSKashyap, Desai 
15251ba9ab2eSKashyap, Desai 	issue_hard_reset = 0;
15261ba9ab2eSKashyap, Desai 	ioc_raw_state = mpt_GetIocState(ioc, 0);
15271ba9ab2eSKashyap, Desai 
15281ba9ab2eSKashyap, Desai 	if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
15291ba9ab2eSKashyap, Desai 		printk(MYIOC_s_WARN_FMT
15301ba9ab2eSKashyap, Desai 			"TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
15311ba9ab2eSKashyap, Desai 			ioc->name, type, ioc_raw_state);
15321ba9ab2eSKashyap, Desai 		printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
15331ba9ab2eSKashyap, Desai 		    ioc->name, __func__);
15341ba9ab2eSKashyap, Desai 		if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
15351ba9ab2eSKashyap, Desai 			printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
15361ba9ab2eSKashyap, Desai 			    "FAILED!!\n", ioc->name);
15371ba9ab2eSKashyap, Desai 		return 0;
15381ba9ab2eSKashyap, Desai 	}
15391ba9ab2eSKashyap, Desai 
154098cbe371Skashyap.desai@lsi.com 	/* DOORBELL ACTIVE check is not required if
154198cbe371Skashyap.desai@lsi.com 	*  MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q is supported.
154298cbe371Skashyap.desai@lsi.com 	*/
154398cbe371Skashyap.desai@lsi.com 
154498cbe371Skashyap.desai@lsi.com 	if (!((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q)
154598cbe371Skashyap.desai@lsi.com 		 && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) &&
154698cbe371Skashyap.desai@lsi.com 		(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
15471ba9ab2eSKashyap, Desai 		printk(MYIOC_s_WARN_FMT
15481ba9ab2eSKashyap, Desai 			"TaskMgmt type=%x: ioc_state: "
15491ba9ab2eSKashyap, Desai 			"DOORBELL_ACTIVE (0x%x)!\n",
15501ba9ab2eSKashyap, Desai 			ioc->name, type, ioc_raw_state);
15511ba9ab2eSKashyap, Desai 		return FAILED;
15521ba9ab2eSKashyap, Desai 	}
15531ba9ab2eSKashyap, Desai 
15541ba9ab2eSKashyap, Desai 	mutex_lock(&ioc->taskmgmt_cmds.mutex);
15551ba9ab2eSKashyap, Desai 	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
15561ba9ab2eSKashyap, Desai 		mf = NULL;
15571ba9ab2eSKashyap, Desai 		retval = FAILED;
15581ba9ab2eSKashyap, Desai 		goto out;
15591ba9ab2eSKashyap, Desai 	}
15601da177e4SLinus Torvalds 
15611da177e4SLinus Torvalds 	/* Return Fail to calling function if no message frames available.
15621da177e4SLinus Torvalds 	 */
1563e80b002bSEric Moore 	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
15641ba9ab2eSKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
15651ba9ab2eSKashyap, Desai 			"TaskMgmt no msg frames!!\n", ioc->name));
15661ba9ab2eSKashyap, Desai 		retval = FAILED;
15671ba9ab2eSKashyap, Desai 		mpt_clear_taskmgmt_in_progress_flag(ioc);
15681ba9ab2eSKashyap, Desai 		goto out;
15691da177e4SLinus Torvalds 	}
15701ba9ab2eSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1571e80b002bSEric Moore 			ioc->name, mf));
15721da177e4SLinus Torvalds 
15731da177e4SLinus Torvalds 	/* Format the Request
15741da177e4SLinus Torvalds 	 */
15751da177e4SLinus Torvalds 	pScsiTm = (SCSITaskMgmt_t *) mf;
1576793955f5SEric Moore 	pScsiTm->TargetID = id;
15771da177e4SLinus Torvalds 	pScsiTm->Bus = channel;
15781da177e4SLinus Torvalds 	pScsiTm->ChainOffset = 0;
15791da177e4SLinus Torvalds 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
15801da177e4SLinus Torvalds 
15811da177e4SLinus Torvalds 	pScsiTm->Reserved = 0;
15821da177e4SLinus Torvalds 	pScsiTm->TaskType = type;
15831da177e4SLinus Torvalds 	pScsiTm->Reserved1 = 0;
15841da177e4SLinus Torvalds 	pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
15851da177e4SLinus Torvalds                     ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
15861da177e4SLinus Torvalds 
1587793955f5SEric Moore 	int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
15881da177e4SLinus Torvalds 
15891da177e4SLinus Torvalds 	for (ii=0; ii < 7; ii++)
15901da177e4SLinus Torvalds 		pScsiTm->Reserved2[ii] = 0;
15911da177e4SLinus Torvalds 
15921da177e4SLinus Torvalds 	pScsiTm->TaskMsgContext = ctx2abort;
15931da177e4SLinus Torvalds 
15941ba9ab2eSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
15951ba9ab2eSKashyap, Desai 		"task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
15961ba9ab2eSKashyap, Desai 		type, timeout));
15971da177e4SLinus Torvalds 
15986757d6b4SPrakash, Sathya 	DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
15991da177e4SLinus Torvalds 
16001ba9ab2eSKashyap, Desai 	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
16011ba9ab2eSKashyap, Desai 	time_count = jiffies;
1602e80b002bSEric Moore 	if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1603e80b002bSEric Moore 	    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1604e80b002bSEric Moore 		mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
16057a195f46SPrakash, Sathya 	else {
1606e80b002bSEric Moore 		retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
16077a195f46SPrakash, Sathya 			sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
16087a195f46SPrakash, Sathya 		if (retval) {
16091ba9ab2eSKashyap, Desai 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
16101ba9ab2eSKashyap, Desai 				"TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
16111ba9ab2eSKashyap, Desai 				ioc->name, mf, retval));
1612e80b002bSEric Moore 			mpt_free_msg_frame(ioc, mf);
16131ba9ab2eSKashyap, Desai 			mpt_clear_taskmgmt_in_progress_flag(ioc);
16141ba9ab2eSKashyap, Desai 			goto out;
16151da177e4SLinus Torvalds 		}
16161ba9ab2eSKashyap, Desai 	}
16171ba9ab2eSKashyap, Desai 
1618bef7afbfSJason Yan 	wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
16191ba9ab2eSKashyap, Desai 		timeout*HZ);
16201ba9ab2eSKashyap, Desai 	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
16211ba9ab2eSKashyap, Desai 		retval = FAILED;
16221ba9ab2eSKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
16231ba9ab2eSKashyap, Desai 		    "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
16241ba9ab2eSKashyap, Desai 		mpt_clear_taskmgmt_in_progress_flag(ioc);
16251ba9ab2eSKashyap, Desai 		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
16261ba9ab2eSKashyap, Desai 			goto out;
16271ba9ab2eSKashyap, Desai 		issue_hard_reset = 1;
16281ba9ab2eSKashyap, Desai 		goto out;
16291ba9ab2eSKashyap, Desai 	}
16301ba9ab2eSKashyap, Desai 
16311ba9ab2eSKashyap, Desai 	retval = mptscsih_taskmgmt_reply(ioc, type,
16321ba9ab2eSKashyap, Desai 	    (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
16331ba9ab2eSKashyap, Desai 
16341ba9ab2eSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
16351ba9ab2eSKashyap, Desai 	    "TaskMgmt completed (%d seconds)\n",
16361ba9ab2eSKashyap, Desai 	    ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
16371ba9ab2eSKashyap, Desai 
16381ba9ab2eSKashyap, Desai  out:
16391ba9ab2eSKashyap, Desai 
16401ba9ab2eSKashyap, Desai 	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
16411ba9ab2eSKashyap, Desai 	if (issue_hard_reset) {
164297009a29SKei Tokunaga 		printk(MYIOC_s_WARN_FMT
164397009a29SKei Tokunaga 		       "Issuing Reset from %s!! doorbell=0x%08x\n",
164497009a29SKei Tokunaga 		       ioc->name, __func__, mpt_GetIocState(ioc, 0));
164598cbe371Skashyap.desai@lsi.com 		retval = (ioc->bus_type == SAS) ?
164698cbe371Skashyap.desai@lsi.com 			mpt_HardResetHandler(ioc, CAN_SLEEP) :
164798cbe371Skashyap.desai@lsi.com 			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
16481ba9ab2eSKashyap, Desai 		mpt_free_msg_frame(ioc, mf);
16491ba9ab2eSKashyap, Desai 	}
16501ba9ab2eSKashyap, Desai 
16511ba9ab2eSKashyap, Desai 	retval = (retval == 0) ? 0 : FAILED;
16521ba9ab2eSKashyap, Desai 	mutex_unlock(&ioc->taskmgmt_cmds.mutex);
16531ba9ab2eSKashyap, Desai 	return retval;
16541ba9ab2eSKashyap, Desai }
16551ba9ab2eSKashyap, Desai EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
16561da177e4SLinus Torvalds 
1657d66c7a0fSChristoph Hellwig static int
mptscsih_get_tm_timeout(MPT_ADAPTER * ioc)1658d66c7a0fSChristoph Hellwig mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1659d66c7a0fSChristoph Hellwig {
1660d66c7a0fSChristoph Hellwig 	switch (ioc->bus_type) {
1661d66c7a0fSChristoph Hellwig 	case FC:
1662d66c7a0fSChristoph Hellwig 		return 40;
1663d66c7a0fSChristoph Hellwig 	case SAS:
166469b2e9b4SKashyap, Desai 		return 30;
1665d66c7a0fSChristoph Hellwig 	case SPI:
1666d66c7a0fSChristoph Hellwig 	default:
166722ab019bSBernd Schubert 		return 10;
1668d66c7a0fSChristoph Hellwig 	}
1669d66c7a0fSChristoph Hellwig }
1670d66c7a0fSChristoph Hellwig 
16711da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
16721da177e4SLinus Torvalds /**
16731da177e4SLinus Torvalds  *	mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
16741da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
16751da177e4SLinus Torvalds  *
16761da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_abort_handler routine)
16771da177e4SLinus Torvalds  *
16781da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
1679cd2c6191SEric Moore  **/
16800d0c7974SMoore, Eric Dean  int
mptscsih_abort(struct scsi_cmnd * SCpnt)16811da177e4SLinus Torvalds mptscsih_abort(struct scsi_cmnd * SCpnt)
16821da177e4SLinus Torvalds {
16831da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
16841da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
16851da177e4SLinus Torvalds 	u32		 ctx2abort;
16861da177e4SLinus Torvalds 	int		 scpnt_idx;
1687466544d8SMoore, Eric Dean 	int		 retval;
1688958d4a32SEric Moore 	VirtDevice	 *vdevice;
1689958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
16901da177e4SLinus Torvalds 
16911da177e4SLinus Torvalds 	/* If we can't locate our host adapter structure, return FAILED status.
16921da177e4SLinus Torvalds 	 */
1693e7eae9f6SEric Moore 	if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
16941da177e4SLinus Torvalds 		SCpnt->result = DID_RESET << 16;
16951ae6d167SBart Van Assche 		scsi_done(SCpnt);
169629dd3609SEric Moore 		printk(KERN_ERR MYNAM ": task abort: "
169729dd3609SEric Moore 		    "can't locate host! (sc=%p)\n", SCpnt);
16981da177e4SLinus Torvalds 		return FAILED;
16991da177e4SLinus Torvalds 	}
17001da177e4SLinus Torvalds 
1701958d4a32SEric Moore 	ioc = hd->ioc;
1702958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1703958d4a32SEric Moore 	       ioc->name, SCpnt);
1704958d4a32SEric Moore 	scsi_print_command(SCpnt);
1705958d4a32SEric Moore 
1706958d4a32SEric Moore 	vdevice = SCpnt->device->hostdata;
1707958d4a32SEric Moore 	if (!vdevice || !vdevice->vtarget) {
170829dd3609SEric Moore 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
170929dd3609SEric Moore 		    "task abort: device has been deleted (sc=%p)\n",
171029dd3609SEric Moore 		    ioc->name, SCpnt));
1711958d4a32SEric Moore 		SCpnt->result = DID_NO_CONNECT << 16;
17121ae6d167SBart Van Assche 		scsi_done(SCpnt);
171369b2e9b4SKashyap, Desai 		retval = SUCCESS;
1714958d4a32SEric Moore 		goto out;
1715958d4a32SEric Moore 	}
1716958d4a32SEric Moore 
1717cc78d30aSEric Moore 	/* Task aborts are not supported for hidden raid components.
1718cc78d30aSEric Moore 	 */
1719cc78d30aSEric Moore 	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
172029dd3609SEric Moore 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
172129dd3609SEric Moore 		    "task abort: hidden raid component (sc=%p)\n",
172229dd3609SEric Moore 		    ioc->name, SCpnt));
1723cc78d30aSEric Moore 		SCpnt->result = DID_RESET << 16;
1724cc78d30aSEric Moore 		retval = FAILED;
1725cc78d30aSEric Moore 		goto out;
1726cc78d30aSEric Moore 	}
1727cc78d30aSEric Moore 
172869b2e9b4SKashyap, Desai 	/* Task aborts are not supported for volumes.
172969b2e9b4SKashyap, Desai 	 */
173069b2e9b4SKashyap, Desai 	if (vdevice->vtarget->raidVolume) {
173169b2e9b4SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
173269b2e9b4SKashyap, Desai 		    "task abort: raid volume (sc=%p)\n",
173369b2e9b4SKashyap, Desai 		    ioc->name, SCpnt));
173469b2e9b4SKashyap, Desai 		SCpnt->result = DID_RESET << 16;
173569b2e9b4SKashyap, Desai 		retval = FAILED;
173669b2e9b4SKashyap, Desai 		goto out;
173769b2e9b4SKashyap, Desai 	}
173869b2e9b4SKashyap, Desai 
17391da177e4SLinus Torvalds 	/* Find this command
17401da177e4SLinus Torvalds 	 */
1741e8206381SEric Moore 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
17421da177e4SLinus Torvalds 		/* Cmd not found in ScsiLookup.
17431da177e4SLinus Torvalds 		 * Do OS callback.
17441da177e4SLinus Torvalds 		 */
17451da177e4SLinus Torvalds 		SCpnt->result = DID_RESET << 16;
174629dd3609SEric Moore 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
1747958d4a32SEric Moore 		   "Command not in the active list! (sc=%p)\n", ioc->name,
1748958d4a32SEric Moore 		   SCpnt));
17499858ae38SKashyap, Desai 		retval = SUCCESS;
1750958d4a32SEric Moore 		goto out;
17511da177e4SLinus Torvalds 	}
17521da177e4SLinus Torvalds 
17532f187862SKashyap, Desai 	if (ioc->timeouts < -1)
17542f187862SKashyap, Desai 		ioc->timeouts++;
175565207fedSMoore, Eric 
17562f4c782cSKashyap, Desai 	if (mpt_fwfault_debug)
17572f4c782cSKashyap, Desai 		mpt_halt_firmware(ioc);
17582f4c782cSKashyap, Desai 
17591da177e4SLinus Torvalds 	/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
17601da177e4SLinus Torvalds 	 * (the IO to be ABORT'd)
17611da177e4SLinus Torvalds 	 *
17621da177e4SLinus Torvalds 	 * NOTE: Since we do not byteswap MsgContext, we do not
17631da177e4SLinus Torvalds 	 *	 swap it here either.  It is an opaque cookie to
17641da177e4SLinus Torvalds 	 *	 the controller, so it does not matter. -DaveM
17651da177e4SLinus Torvalds 	 */
1766e80b002bSEric Moore 	mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
17671da177e4SLinus Torvalds 	ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
17681ba9ab2eSKashyap, Desai 	retval = mptscsih_IssueTaskMgmt(hd,
17691ba9ab2eSKashyap, Desai 			 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
17701ba9ab2eSKashyap, Desai 			 vdevice->vtarget->channel,
17711ba9ab2eSKashyap, Desai 			 vdevice->vtarget->id, vdevice->lun,
1772958d4a32SEric Moore 			 ctx2abort, mptscsih_get_tm_timeout(ioc));
17731da177e4SLinus Torvalds 
1774aeaeb5ceSChristoph Hellwig 	if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) {
17752f187862SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
17762f187862SKashyap, Desai 		    "task abort: command still in active list! (sc=%p)\n",
17772f187862SKashyap, Desai 		    ioc->name, SCpnt));
17783dc0b03fSEric Moore 		retval = FAILED;
17792f187862SKashyap, Desai 	} else {
17802f187862SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
17812f187862SKashyap, Desai 		    "task abort: command cleared from active list! (sc=%p)\n",
17822f187862SKashyap, Desai 		    ioc->name, SCpnt));
17832f187862SKashyap, Desai 		retval = SUCCESS;
17842f187862SKashyap, Desai 	}
17853dc0b03fSEric Moore 
1786958d4a32SEric Moore  out:
1787aeaeb5ceSChristoph Hellwig 	printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n",
1788bcfe42e9SKashyap, Desai 	    ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,
1789aeaeb5ceSChristoph Hellwig 	    SCpnt);
17901da177e4SLinus Torvalds 
17912f187862SKashyap, Desai 	return retval;
17921da177e4SLinus Torvalds }
17931da177e4SLinus Torvalds 
17941da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
17951da177e4SLinus Torvalds /**
17961da177e4SLinus Torvalds  *	mptscsih_dev_reset - Perform a SCSI TARGET_RESET!  new_eh variant
17971da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
17981da177e4SLinus Torvalds  *
17991da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_dev_reset_handler routine)
18001da177e4SLinus Torvalds  *
18011da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
1802cd2c6191SEric Moore  **/
18030d0c7974SMoore, Eric Dean  int
mptscsih_dev_reset(struct scsi_cmnd * SCpnt)18041da177e4SLinus Torvalds mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
18051da177e4SLinus Torvalds {
18061da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
1807466544d8SMoore, Eric Dean 	int		 retval;
1808958d4a32SEric Moore 	VirtDevice	 *vdevice;
1809958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
18101da177e4SLinus Torvalds 
18111da177e4SLinus Torvalds 	/* If we can't locate our host adapter structure, return FAILED status.
18121da177e4SLinus Torvalds 	 */
1813e7eae9f6SEric Moore 	if ((hd = shost_priv(SCpnt->device->host)) == NULL){
181429dd3609SEric Moore 		printk(KERN_ERR MYNAM ": target reset: "
181529dd3609SEric Moore 		   "Can't locate host! (sc=%p)\n", SCpnt);
18161da177e4SLinus Torvalds 		return FAILED;
18171da177e4SLinus Torvalds 	}
18181da177e4SLinus Torvalds 
1819958d4a32SEric Moore 	ioc = hd->ioc;
1820958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1821958d4a32SEric Moore 	       ioc->name, SCpnt);
1822466544d8SMoore, Eric Dean 	scsi_print_command(SCpnt);
18231da177e4SLinus Torvalds 
1824958d4a32SEric Moore 	vdevice = SCpnt->device->hostdata;
1825958d4a32SEric Moore 	if (!vdevice || !vdevice->vtarget) {
1826bcfe42e9SKashyap, Desai 		retval = 0;
1827958d4a32SEric Moore 		goto out;
1828958d4a32SEric Moore 	}
1829958d4a32SEric Moore 
1830cc78d30aSEric Moore 	/* Target reset to hidden raid component is not supported
1831cc78d30aSEric Moore 	 */
1832cc78d30aSEric Moore 	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1833cc78d30aSEric Moore 		retval = FAILED;
1834cc78d30aSEric Moore 		goto out;
1835cc78d30aSEric Moore 	}
1836cc78d30aSEric Moore 
18371ba9ab2eSKashyap, Desai 	retval = mptscsih_IssueTaskMgmt(hd,
18381ba9ab2eSKashyap, Desai 				MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
18391ba9ab2eSKashyap, Desai 				vdevice->vtarget->channel,
18401ba9ab2eSKashyap, Desai 				vdevice->vtarget->id, 0, 0,
1841958d4a32SEric Moore 				mptscsih_get_tm_timeout(ioc));
1842958d4a32SEric Moore 
1843958d4a32SEric Moore  out:
1844958d4a32SEric Moore 	printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1845958d4a32SEric Moore 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1846466544d8SMoore, Eric Dean 
1847466544d8SMoore, Eric Dean 	if (retval == 0)
1848466544d8SMoore, Eric Dean 		return SUCCESS;
1849cd2c6191SEric Moore 	else
1850466544d8SMoore, Eric Dean 		return FAILED;
18511da177e4SLinus Torvalds }
18521da177e4SLinus Torvalds 
1853cd2c6191SEric Moore 
18541da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
18551da177e4SLinus Torvalds /**
18561da177e4SLinus Torvalds  *	mptscsih_bus_reset - Perform a SCSI BUS_RESET!	new_eh variant
18571da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
18581da177e4SLinus Torvalds  *
18591da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_bus_reset_handler routine)
18601da177e4SLinus Torvalds  *
18611da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
1862cd2c6191SEric Moore  **/
18630d0c7974SMoore, Eric Dean  int
mptscsih_bus_reset(struct scsi_cmnd * SCpnt)18641da177e4SLinus Torvalds mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
18651da177e4SLinus Torvalds {
18661da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
1867466544d8SMoore, Eric Dean 	int		 retval;
1868a69de507SEric Moore 	VirtDevice	 *vdevice;
1869958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
18701da177e4SLinus Torvalds 
18711da177e4SLinus Torvalds 	/* If we can't locate our host adapter structure, return FAILED status.
18721da177e4SLinus Torvalds 	 */
1873e7eae9f6SEric Moore 	if ((hd = shost_priv(SCpnt->device->host)) == NULL){
187429dd3609SEric Moore 		printk(KERN_ERR MYNAM ": bus reset: "
187529dd3609SEric Moore 		   "Can't locate host! (sc=%p)\n", SCpnt);
18761da177e4SLinus Torvalds 		return FAILED;
18771da177e4SLinus Torvalds 	}
18781da177e4SLinus Torvalds 
1879958d4a32SEric Moore 	ioc = hd->ioc;
1880958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1881958d4a32SEric Moore 	       ioc->name, SCpnt);
1882466544d8SMoore, Eric Dean 	scsi_print_command(SCpnt);
18831da177e4SLinus Torvalds 
18842f187862SKashyap, Desai 	if (ioc->timeouts < -1)
18852f187862SKashyap, Desai 		ioc->timeouts++;
18861da177e4SLinus Torvalds 
1887a69de507SEric Moore 	vdevice = SCpnt->device->hostdata;
18882f187862SKashyap, Desai 	if (!vdevice || !vdevice->vtarget)
18892f187862SKashyap, Desai 		return SUCCESS;
18901ba9ab2eSKashyap, Desai 	retval = mptscsih_IssueTaskMgmt(hd,
18911ba9ab2eSKashyap, Desai 					MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
18921ba9ab2eSKashyap, Desai 					vdevice->vtarget->channel, 0, 0, 0,
18931ba9ab2eSKashyap, Desai 					mptscsih_get_tm_timeout(ioc));
18941da177e4SLinus Torvalds 
1895958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1896958d4a32SEric Moore 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1897466544d8SMoore, Eric Dean 
1898466544d8SMoore, Eric Dean 	if (retval == 0)
1899466544d8SMoore, Eric Dean 		return SUCCESS;
1900cd2c6191SEric Moore 	else
1901466544d8SMoore, Eric Dean 		return FAILED;
19021da177e4SLinus Torvalds }
19031da177e4SLinus Torvalds 
19041da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
19051da177e4SLinus Torvalds /**
1906d9489fb6SRandy Dunlap  *	mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
19071da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
19081da177e4SLinus Torvalds  *
19091da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_host_reset_handler routine)
19101da177e4SLinus Torvalds  *
19111da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
19121da177e4SLinus Torvalds  */
19130d0c7974SMoore, Eric Dean  int
mptscsih_host_reset(struct scsi_cmnd * SCpnt)19141da177e4SLinus Torvalds mptscsih_host_reset(struct scsi_cmnd *SCpnt)
19151da177e4SLinus Torvalds {
19161da177e4SLinus Torvalds 	MPT_SCSI_HOST *  hd;
19172f187862SKashyap, Desai 	int              status = SUCCESS;
1918958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
19192f187862SKashyap, Desai 	int		retval;
19201da177e4SLinus Torvalds 
19211da177e4SLinus Torvalds 	/*  If we can't locate the host to reset, then we failed. */
1922e7eae9f6SEric Moore 	if ((hd = shost_priv(SCpnt->device->host)) == NULL){
192329dd3609SEric Moore 		printk(KERN_ERR MYNAM ": host reset: "
192429dd3609SEric Moore 		    "Can't locate host! (sc=%p)\n", SCpnt);
19251da177e4SLinus Torvalds 		return FAILED;
19261da177e4SLinus Torvalds 	}
19271da177e4SLinus Torvalds 
1928a6da74cbSJames Bottomley 	/* make sure we have no outstanding commands at this stage */
1929a6da74cbSJames Bottomley 	mptscsih_flush_running_cmds(hd);
1930a6da74cbSJames Bottomley 
1931958d4a32SEric Moore 	ioc = hd->ioc;
1932958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1933958d4a32SEric Moore 	    ioc->name, SCpnt);
19341da177e4SLinus Torvalds 
19351da177e4SLinus Torvalds 	/*  If our attempts to reset the host failed, then return a failed
19361da177e4SLinus Torvalds 	 *  status.  The host will be taken off line by the SCSI mid-layer.
19371da177e4SLinus Torvalds 	 */
1938d0f698c4SKashyap, Desai 	retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
19392f187862SKashyap, Desai 	if (retval < 0)
19402f187862SKashyap, Desai 		status = FAILED;
19412f187862SKashyap, Desai 	else
19422f187862SKashyap, Desai 		status = SUCCESS;
19431da177e4SLinus Torvalds 
1944958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1945958d4a32SEric Moore 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
19461da177e4SLinus Torvalds 
19472f187862SKashyap, Desai 	return status;
19481da177e4SLinus Torvalds }
19491da177e4SLinus Torvalds 
19501da177e4SLinus Torvalds static int
mptscsih_taskmgmt_reply(MPT_ADAPTER * ioc,u8 type,SCSITaskMgmtReply_t * pScsiTmReply)19511ba9ab2eSKashyap, Desai mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
19521ba9ab2eSKashyap, Desai 	SCSITaskMgmtReply_t *pScsiTmReply)
19531da177e4SLinus Torvalds {
19541ba9ab2eSKashyap, Desai 	u16			 iocstatus;
19551ba9ab2eSKashyap, Desai 	u32			 termination_count;
19561ba9ab2eSKashyap, Desai 	int			 retval;
19571da177e4SLinus Torvalds 
19581ba9ab2eSKashyap, Desai 	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
19591ba9ab2eSKashyap, Desai 		retval = FAILED;
19601ba9ab2eSKashyap, Desai 		goto out;
19611da177e4SLinus Torvalds 	}
19621da177e4SLinus Torvalds 
19631ba9ab2eSKashyap, Desai 	DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
19641da177e4SLinus Torvalds 
19651ba9ab2eSKashyap, Desai 	iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
19661ba9ab2eSKashyap, Desai 	termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
19671ba9ab2eSKashyap, Desai 
19681ba9ab2eSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
19691ba9ab2eSKashyap, Desai 	    "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
19701ba9ab2eSKashyap, Desai 	    "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
19711ba9ab2eSKashyap, Desai 	    "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
19721ba9ab2eSKashyap, Desai 	    pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
19731ba9ab2eSKashyap, Desai 	    le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
19741ba9ab2eSKashyap, Desai 	    termination_count));
19751ba9ab2eSKashyap, Desai 
19761ba9ab2eSKashyap, Desai 	if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
19771ba9ab2eSKashyap, Desai 	    pScsiTmReply->ResponseCode)
19781ba9ab2eSKashyap, Desai 		mptscsih_taskmgmt_response_code(ioc,
19791ba9ab2eSKashyap, Desai 		    pScsiTmReply->ResponseCode);
19801ba9ab2eSKashyap, Desai 
19811ba9ab2eSKashyap, Desai 	if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
19821ba9ab2eSKashyap, Desai 		retval = 0;
19831ba9ab2eSKashyap, Desai 		goto out;
19841da177e4SLinus Torvalds 	}
19851da177e4SLinus Torvalds 
19861ba9ab2eSKashyap, Desai 	retval = FAILED;
19871ba9ab2eSKashyap, Desai 	if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
19881ba9ab2eSKashyap, Desai 		if (termination_count == 1)
19891ba9ab2eSKashyap, Desai 			retval = 0;
19901ba9ab2eSKashyap, Desai 		goto out;
19911ba9ab2eSKashyap, Desai 	}
19921ba9ab2eSKashyap, Desai 
19931ba9ab2eSKashyap, Desai 	if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
19941ba9ab2eSKashyap, Desai 	   iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
19951ba9ab2eSKashyap, Desai 		retval = 0;
19961ba9ab2eSKashyap, Desai 
19971ba9ab2eSKashyap, Desai  out:
19981ba9ab2eSKashyap, Desai 	return retval;
19991da177e4SLinus Torvalds }
20001da177e4SLinus Torvalds 
20011da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2002e7deff33SKashyap, Desai void
mptscsih_taskmgmt_response_code(MPT_ADAPTER * ioc,u8 response_code)20039f63bb73SMoore, Eric mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
20049f63bb73SMoore, Eric {
20059f63bb73SMoore, Eric 	char *desc;
20069f63bb73SMoore, Eric 
20079f63bb73SMoore, Eric 	switch (response_code) {
20089f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
20099f63bb73SMoore, Eric 		desc = "The task completed.";
20109f63bb73SMoore, Eric 		break;
20119f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
20129f63bb73SMoore, Eric 		desc = "The IOC received an invalid frame status.";
20139f63bb73SMoore, Eric 		break;
20149f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
20159f63bb73SMoore, Eric 		desc = "The task type is not supported.";
20169f63bb73SMoore, Eric 		break;
20179f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_FAILED:
20189f63bb73SMoore, Eric 		desc = "The requested task failed.";
20199f63bb73SMoore, Eric 		break;
20209f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
20219f63bb73SMoore, Eric 		desc = "The task completed successfully.";
20229f63bb73SMoore, Eric 		break;
20239f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
20249f63bb73SMoore, Eric 		desc = "The LUN request is invalid.";
20259f63bb73SMoore, Eric 		break;
20269f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
20279f63bb73SMoore, Eric 		desc = "The task is in the IOC queue and has not been sent to target.";
20289f63bb73SMoore, Eric 		break;
20299f63bb73SMoore, Eric 	default:
20309f63bb73SMoore, Eric 		desc = "unknown";
20319f63bb73SMoore, Eric 		break;
20329f63bb73SMoore, Eric 	}
20339f63bb73SMoore, Eric 	printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
20349f63bb73SMoore, Eric 		ioc->name, response_code, desc);
20359f63bb73SMoore, Eric }
2036e7deff33SKashyap, Desai EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
20379f63bb73SMoore, Eric 
20389f63bb73SMoore, Eric /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
20391da177e4SLinus Torvalds /**
20401da177e4SLinus Torvalds  *	mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
20411da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
20421da177e4SLinus Torvalds  *	@mf: Pointer to SCSI task mgmt request frame
20431da177e4SLinus Torvalds  *	@mr: Pointer to SCSI task mgmt reply frame
20441da177e4SLinus Torvalds  *
20451da177e4SLinus Torvalds  *	This routine is called from mptbase.c::mpt_interrupt() at the completion
20461da177e4SLinus Torvalds  *	of any SCSI task management request.
20471da177e4SLinus Torvalds  *	This routine is registered with the MPT (base) driver at driver
20481da177e4SLinus Torvalds  *	load/init time via the mpt_register() API call.
20491da177e4SLinus Torvalds  *
20501da177e4SLinus Torvalds  *	Returns 1 indicating alloc'd request frame ptr should be freed.
2051cd2c6191SEric Moore  **/
20520d0c7974SMoore, Eric Dean  int
mptscsih_taskmgmt_complete(MPT_ADAPTER * ioc,MPT_FRAME_HDR * mf,MPT_FRAME_HDR * mr)20531ba9ab2eSKashyap, Desai mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
20541ba9ab2eSKashyap, Desai 	MPT_FRAME_HDR *mr)
20551da177e4SLinus Torvalds {
20561ba9ab2eSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
20571ba9ab2eSKashyap, Desai 		"TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
20581da177e4SLinus Torvalds 
20591ba9ab2eSKashyap, Desai 	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
20601da177e4SLinus Torvalds 
20611ba9ab2eSKashyap, Desai 	if (!mr)
2062cd2c6191SEric Moore 		goto out;
2063cd2c6191SEric Moore 
20641ba9ab2eSKashyap, Desai 	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
20651ba9ab2eSKashyap, Desai 	memcpy(ioc->taskmgmt_cmds.reply, mr,
20661ba9ab2eSKashyap, Desai 	    min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
2067cd2c6191SEric Moore  out:
20681ba9ab2eSKashyap, Desai 	if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
20691ba9ab2eSKashyap, Desai 		mpt_clear_taskmgmt_in_progress_flag(ioc);
20701ba9ab2eSKashyap, Desai 		ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
20711ba9ab2eSKashyap, Desai 		complete(&ioc->taskmgmt_cmds.done);
2072b68bf096SKashyap, Desai 		if (ioc->bus_type == SAS)
2073b68bf096SKashyap, Desai 			ioc->schedule_target_reset(ioc);
20741da177e4SLinus Torvalds 		return 1;
20751da177e4SLinus Torvalds 	}
20761ba9ab2eSKashyap, Desai 	return 0;
20771ba9ab2eSKashyap, Desai }
20781da177e4SLinus Torvalds 
20791da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
20801da177e4SLinus Torvalds /*
20811da177e4SLinus Torvalds  *	This is anyones guess quite frankly.
20821da177e4SLinus Torvalds  */
20830d0c7974SMoore, Eric Dean  int
mptscsih_bios_param(struct scsi_device * sdev,struct block_device * bdev,sector_t capacity,int geom[])20841da177e4SLinus Torvalds mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
20851da177e4SLinus Torvalds 		sector_t capacity, int geom[])
20861da177e4SLinus Torvalds {
20871da177e4SLinus Torvalds 	int		heads;
20881da177e4SLinus Torvalds 	int		sectors;
20891da177e4SLinus Torvalds 	sector_t	cylinders;
20901da177e4SLinus Torvalds 	ulong 		dummy;
20911da177e4SLinus Torvalds 
20921da177e4SLinus Torvalds 	heads = 64;
20931da177e4SLinus Torvalds 	sectors = 32;
20941da177e4SLinus Torvalds 
20951da177e4SLinus Torvalds 	dummy = heads * sectors;
20961da177e4SLinus Torvalds 	cylinders = capacity;
20971da177e4SLinus Torvalds 	sector_div(cylinders,dummy);
20981da177e4SLinus Torvalds 
20991da177e4SLinus Torvalds 	/*
21001da177e4SLinus Torvalds 	 * Handle extended translation size for logical drives
21011da177e4SLinus Torvalds 	 * > 1Gb
21021da177e4SLinus Torvalds 	 */
21031da177e4SLinus Torvalds 	if ((ulong)capacity >= 0x200000) {
21041da177e4SLinus Torvalds 		heads = 255;
21051da177e4SLinus Torvalds 		sectors = 63;
21061da177e4SLinus Torvalds 		dummy = heads * sectors;
21071da177e4SLinus Torvalds 		cylinders = capacity;
21081da177e4SLinus Torvalds 		sector_div(cylinders,dummy);
21091da177e4SLinus Torvalds 	}
21101da177e4SLinus Torvalds 
21111da177e4SLinus Torvalds 	/* return result */
21121da177e4SLinus Torvalds 	geom[0] = heads;
21131da177e4SLinus Torvalds 	geom[1] = sectors;
21141da177e4SLinus Torvalds 	geom[2] = cylinders;
21151da177e4SLinus Torvalds 
21161da177e4SLinus Torvalds 	return 0;
21171da177e4SLinus Torvalds }
21181da177e4SLinus Torvalds 
2119f44e5461SMoore, Eric /* Search IOC page 3 to determine if this is hidden physical disk
2120f44e5461SMoore, Eric  *
2121f44e5461SMoore, Eric  */
2122f44e5461SMoore, Eric int
mptscsih_is_phys_disk(MPT_ADAPTER * ioc,u8 channel,u8 id)2123793955f5SEric Moore mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
2124f44e5461SMoore, Eric {
2125b506ade9SEric Moore 	struct inactive_raid_component_info *component_info;
2126a7938b0bSKashyap, Desai 	int i, j;
2127a7938b0bSKashyap, Desai 	RaidPhysDiskPage1_t *phys_disk;
2128793955f5SEric Moore 	int rc = 0;
2129a7938b0bSKashyap, Desai 	int num_paths;
2130f44e5461SMoore, Eric 
2131793955f5SEric Moore 	if (!ioc->raid_data.pIocPg3)
2132793955f5SEric Moore 		goto out;
2133f44e5461SMoore, Eric 	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2134793955f5SEric Moore 		if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2135793955f5SEric Moore 		    (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2136793955f5SEric Moore 			rc = 1;
2137793955f5SEric Moore 			goto out;
2138f44e5461SMoore, Eric 		}
2139793955f5SEric Moore 	}
2140793955f5SEric Moore 
2141a7938b0bSKashyap, Desai 	if (ioc->bus_type != SAS)
2142a7938b0bSKashyap, Desai 		goto out;
2143a7938b0bSKashyap, Desai 
2144a7938b0bSKashyap, Desai 	/*
2145a7938b0bSKashyap, Desai 	 * Check if dual path
2146a7938b0bSKashyap, Desai 	 */
2147a7938b0bSKashyap, Desai 	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2148a7938b0bSKashyap, Desai 		num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2149a7938b0bSKashyap, Desai 		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2150a7938b0bSKashyap, Desai 		if (num_paths < 2)
2151a7938b0bSKashyap, Desai 			continue;
2152a7938b0bSKashyap, Desai 		phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2153a7938b0bSKashyap, Desai 		   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2154a7938b0bSKashyap, Desai 		if (!phys_disk)
2155a7938b0bSKashyap, Desai 			continue;
2156a7938b0bSKashyap, Desai 		if ((mpt_raid_phys_disk_pg1(ioc,
2157a7938b0bSKashyap, Desai 		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2158a7938b0bSKashyap, Desai 		    phys_disk))) {
2159a7938b0bSKashyap, Desai 			kfree(phys_disk);
2160a7938b0bSKashyap, Desai 			continue;
2161a7938b0bSKashyap, Desai 		}
2162a7938b0bSKashyap, Desai 		for (j = 0; j < num_paths; j++) {
2163a7938b0bSKashyap, Desai 			if ((phys_disk->Path[j].Flags &
2164a7938b0bSKashyap, Desai 			    MPI_RAID_PHYSDISK1_FLAG_INVALID))
2165a7938b0bSKashyap, Desai 				continue;
2166a7938b0bSKashyap, Desai 			if ((phys_disk->Path[j].Flags &
2167a7938b0bSKashyap, Desai 			    MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2168a7938b0bSKashyap, Desai 				continue;
2169a7938b0bSKashyap, Desai 			if ((id == phys_disk->Path[j].PhysDiskID) &&
2170a7938b0bSKashyap, Desai 			    (channel == phys_disk->Path[j].PhysDiskBus)) {
2171a7938b0bSKashyap, Desai 				rc = 1;
2172a7938b0bSKashyap, Desai 				kfree(phys_disk);
2173a7938b0bSKashyap, Desai 				goto out;
2174a7938b0bSKashyap, Desai 			}
2175a7938b0bSKashyap, Desai 		}
2176a7938b0bSKashyap, Desai 		kfree(phys_disk);
2177a7938b0bSKashyap, Desai 	}
2178a7938b0bSKashyap, Desai 
2179a7938b0bSKashyap, Desai 
2180b506ade9SEric Moore 	/*
2181b506ade9SEric Moore 	 * Check inactive list for matching phys disks
2182b506ade9SEric Moore 	 */
2183b506ade9SEric Moore 	if (list_empty(&ioc->raid_data.inactive_list))
2184b506ade9SEric Moore 		goto out;
2185b506ade9SEric Moore 
2186ed5f606fSMatthias Kaehlcke 	mutex_lock(&ioc->raid_data.inactive_list_mutex);
2187b506ade9SEric Moore 	list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2188b506ade9SEric Moore 	    list) {
2189b506ade9SEric Moore 		if ((component_info->d.PhysDiskID == id) &&
2190b506ade9SEric Moore 		    (component_info->d.PhysDiskBus == channel))
2191b506ade9SEric Moore 			rc = 1;
2192b506ade9SEric Moore 	}
2193ed5f606fSMatthias Kaehlcke 	mutex_unlock(&ioc->raid_data.inactive_list_mutex);
2194b506ade9SEric Moore 
2195793955f5SEric Moore  out:
2196793955f5SEric Moore 	return rc;
2197f44e5461SMoore, Eric }
2198f44e5461SMoore, Eric EXPORT_SYMBOL(mptscsih_is_phys_disk);
2199f44e5461SMoore, Eric 
2200793955f5SEric Moore u8
mptscsih_raid_id_to_num(MPT_ADAPTER * ioc,u8 channel,u8 id)2201793955f5SEric Moore mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2202c92f222eSJames Bottomley {
2203b506ade9SEric Moore 	struct inactive_raid_component_info *component_info;
2204a7938b0bSKashyap, Desai 	int i, j;
2205a7938b0bSKashyap, Desai 	RaidPhysDiskPage1_t *phys_disk;
2206793955f5SEric Moore 	int rc = -ENXIO;
2207a7938b0bSKashyap, Desai 	int num_paths;
2208c92f222eSJames Bottomley 
2209793955f5SEric Moore 	if (!ioc->raid_data.pIocPg3)
2210793955f5SEric Moore 		goto out;
2211793955f5SEric Moore 	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2212793955f5SEric Moore 		if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2213793955f5SEric Moore 		    (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2214793955f5SEric Moore 			rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2215793955f5SEric Moore 			goto out;
2216793955f5SEric Moore 		}
2217c92f222eSJames Bottomley 	}
2218c92f222eSJames Bottomley 
2219a7938b0bSKashyap, Desai 	if (ioc->bus_type != SAS)
2220a7938b0bSKashyap, Desai 		goto out;
2221a7938b0bSKashyap, Desai 
2222a7938b0bSKashyap, Desai 	/*
2223a7938b0bSKashyap, Desai 	 * Check if dual path
2224a7938b0bSKashyap, Desai 	 */
2225a7938b0bSKashyap, Desai 	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2226a7938b0bSKashyap, Desai 		num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2227a7938b0bSKashyap, Desai 		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2228a7938b0bSKashyap, Desai 		if (num_paths < 2)
2229a7938b0bSKashyap, Desai 			continue;
2230a7938b0bSKashyap, Desai 		phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2231a7938b0bSKashyap, Desai 		   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2232a7938b0bSKashyap, Desai 		if (!phys_disk)
2233a7938b0bSKashyap, Desai 			continue;
2234a7938b0bSKashyap, Desai 		if ((mpt_raid_phys_disk_pg1(ioc,
2235a7938b0bSKashyap, Desai 		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2236a7938b0bSKashyap, Desai 		    phys_disk))) {
2237a7938b0bSKashyap, Desai 			kfree(phys_disk);
2238a7938b0bSKashyap, Desai 			continue;
2239a7938b0bSKashyap, Desai 		}
2240a7938b0bSKashyap, Desai 		for (j = 0; j < num_paths; j++) {
2241a7938b0bSKashyap, Desai 			if ((phys_disk->Path[j].Flags &
2242a7938b0bSKashyap, Desai 			    MPI_RAID_PHYSDISK1_FLAG_INVALID))
2243a7938b0bSKashyap, Desai 				continue;
2244a7938b0bSKashyap, Desai 			if ((phys_disk->Path[j].Flags &
2245a7938b0bSKashyap, Desai 			    MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2246a7938b0bSKashyap, Desai 				continue;
2247a7938b0bSKashyap, Desai 			if ((id == phys_disk->Path[j].PhysDiskID) &&
2248a7938b0bSKashyap, Desai 			    (channel == phys_disk->Path[j].PhysDiskBus)) {
2249a7938b0bSKashyap, Desai 				rc = phys_disk->PhysDiskNum;
2250a7938b0bSKashyap, Desai 				kfree(phys_disk);
2251a7938b0bSKashyap, Desai 				goto out;
2252a7938b0bSKashyap, Desai 			}
2253a7938b0bSKashyap, Desai 		}
2254a7938b0bSKashyap, Desai 		kfree(phys_disk);
2255a7938b0bSKashyap, Desai 	}
2256a7938b0bSKashyap, Desai 
2257b506ade9SEric Moore 	/*
2258b506ade9SEric Moore 	 * Check inactive list for matching phys disks
2259b506ade9SEric Moore 	 */
2260b506ade9SEric Moore 	if (list_empty(&ioc->raid_data.inactive_list))
2261b506ade9SEric Moore 		goto out;
2262b506ade9SEric Moore 
2263ed5f606fSMatthias Kaehlcke 	mutex_lock(&ioc->raid_data.inactive_list_mutex);
2264b506ade9SEric Moore 	list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2265b506ade9SEric Moore 	    list) {
2266b506ade9SEric Moore 		if ((component_info->d.PhysDiskID == id) &&
2267b506ade9SEric Moore 		    (component_info->d.PhysDiskBus == channel))
2268b506ade9SEric Moore 			rc = component_info->d.PhysDiskNum;
2269b506ade9SEric Moore 	}
2270ed5f606fSMatthias Kaehlcke 	mutex_unlock(&ioc->raid_data.inactive_list_mutex);
2271b506ade9SEric Moore 
2272793955f5SEric Moore  out:
2273793955f5SEric Moore 	return rc;
2274c92f222eSJames Bottomley }
2275c92f222eSJames Bottomley EXPORT_SYMBOL(mptscsih_raid_id_to_num);
2276c92f222eSJames Bottomley 
2277c7c82987SMoore, Eric Dean /*
2278c7c82987SMoore, Eric Dean  *	OS entry point to allow for host driver to free allocated memory
2279c7c82987SMoore, Eric Dean  *	Called if no device present or device being unloaded
2280c7c82987SMoore, Eric Dean  */
2281c7c82987SMoore, Eric Dean void
mptscsih_slave_destroy(struct scsi_device * sdev)2282c7c82987SMoore, Eric Dean mptscsih_slave_destroy(struct scsi_device *sdev)
2283c7c82987SMoore, Eric Dean {
2284c7c82987SMoore, Eric Dean 	struct Scsi_Host	*host = sdev->host;
2285e7eae9f6SEric Moore 	MPT_SCSI_HOST		*hd = shost_priv(host);
2286c7c82987SMoore, Eric Dean 	VirtTarget		*vtarget;
2287c7c82987SMoore, Eric Dean 	VirtDevice		*vdevice;
2288c7c82987SMoore, Eric Dean 	struct scsi_target 	*starget;
22891da177e4SLinus Torvalds 
2290c7c82987SMoore, Eric Dean 	starget = scsi_target(sdev);
2291c7c82987SMoore, Eric Dean 	vtarget = starget->hostdata;
2292c7c82987SMoore, Eric Dean 	vdevice = sdev->hostdata;
229308f5c5c2SKashyap, Desai 	if (!vdevice)
229408f5c5c2SKashyap, Desai 		return;
22951da177e4SLinus Torvalds 
2296c7c82987SMoore, Eric Dean 	mptscsih_search_running_cmds(hd, vdevice);
2297c7c82987SMoore, Eric Dean 	vtarget->num_luns--;
2298c7c82987SMoore, Eric Dean 	mptscsih_synchronize_cache(hd, vdevice);
2299c7c82987SMoore, Eric Dean 	kfree(vdevice);
2300c7c82987SMoore, Eric Dean 	sdev->hostdata = NULL;
23011da177e4SLinus Torvalds }
23021da177e4SLinus Torvalds 
23036e3815baSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
23046e3815baSMoore, Eric Dean /*
23056e3815baSMoore, Eric Dean  *	mptscsih_change_queue_depth - This function will set a devices queue depth
23066e3815baSMoore, Eric Dean  *	@sdev: per scsi_device pointer
23076e3815baSMoore, Eric Dean  *	@qdepth: requested queue depth
23086e3815baSMoore, Eric Dean  *
23096e3815baSMoore, Eric Dean  *	Adding support for new 'change_queue_depth' api.
23106e3815baSMoore, Eric Dean */
23116e3815baSMoore, Eric Dean int
mptscsih_change_queue_depth(struct scsi_device * sdev,int qdepth)2312db5ed4dfSChristoph Hellwig mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
23131da177e4SLinus Torvalds {
2314e7eae9f6SEric Moore 	MPT_SCSI_HOST		*hd = shost_priv(sdev->host);
2315c7c82987SMoore, Eric Dean 	VirtTarget 		*vtarget;
2316c7c82987SMoore, Eric Dean 	struct scsi_target 	*starget;
23171da177e4SLinus Torvalds 	int			max_depth;
2318e80b002bSEric Moore 	MPT_ADAPTER		*ioc = hd->ioc;
23191da177e4SLinus Torvalds 
2320c7c82987SMoore, Eric Dean 	starget = scsi_target(sdev);
2321c7c82987SMoore, Eric Dean 	vtarget = starget->hostdata;
23226e3815baSMoore, Eric Dean 
2323e80b002bSEric Moore 	if (ioc->bus_type == SPI) {
2324c7c82987SMoore, Eric Dean 		if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
23251da177e4SLinus Torvalds 			max_depth = 1;
2326c92f222eSJames Bottomley 		else if (sdev->type == TYPE_DISK &&
2327c92f222eSJames Bottomley 			 vtarget->minSyncFactor <= MPT_ULTRA160)
23281da177e4SLinus Torvalds 			max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
23291da177e4SLinus Torvalds 		else
23301da177e4SLinus Torvalds 			max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
23311da177e4SLinus Torvalds 	} else
233279a3ec1aSKashyap, Desai 		 max_depth = ioc->sh->can_queue;
233379a3ec1aSKashyap, Desai 
233479a3ec1aSKashyap, Desai 	if (!sdev->tagged_supported)
233579a3ec1aSKashyap, Desai 		max_depth = 1;
23361da177e4SLinus Torvalds 
23371da177e4SLinus Torvalds 	if (qdepth > max_depth)
23381da177e4SLinus Torvalds 		qdepth = max_depth;
23391da177e4SLinus Torvalds 
2340db5ed4dfSChristoph Hellwig 	return scsi_change_queue_depth(sdev, qdepth);
23411da177e4SLinus Torvalds }
23421da177e4SLinus Torvalds 
23431da177e4SLinus Torvalds /*
23441da177e4SLinus Torvalds  *	OS entry point to adjust the queue_depths on a per-device basis.
23451da177e4SLinus Torvalds  *	Called once per device the bus scan. Use it to force the queue_depth
23461da177e4SLinus Torvalds  *	member to 1 if a device does not support Q tags.
23471da177e4SLinus Torvalds  *	Return non-zero if fails.
23481da177e4SLinus Torvalds  */
23490d0c7974SMoore, Eric Dean  int
mptscsih_slave_configure(struct scsi_device * sdev)2350c7c82987SMoore, Eric Dean mptscsih_slave_configure(struct scsi_device *sdev)
23511da177e4SLinus Torvalds {
2352c7c82987SMoore, Eric Dean 	struct Scsi_Host	*sh = sdev->host;
2353c7c82987SMoore, Eric Dean 	VirtTarget		*vtarget;
2354c7c82987SMoore, Eric Dean 	VirtDevice		*vdevice;
2355c7c82987SMoore, Eric Dean 	struct scsi_target 	*starget;
2356e7eae9f6SEric Moore 	MPT_SCSI_HOST		*hd = shost_priv(sh);
2357e80b002bSEric Moore 	MPT_ADAPTER		*ioc = hd->ioc;
23581da177e4SLinus Torvalds 
2359c7c82987SMoore, Eric Dean 	starget = scsi_target(sdev);
2360c7c82987SMoore, Eric Dean 	vtarget = starget->hostdata;
2361c7c82987SMoore, Eric Dean 	vdevice = sdev->hostdata;
23621da177e4SLinus Torvalds 
2363e80b002bSEric Moore 	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
23649cb78c16SHannes Reinecke 		"device @ %p, channel=%d, id=%d, lun=%llu\n",
2365e80b002bSEric Moore 		ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2366e80b002bSEric Moore 	if (ioc->bus_type == SPI)
2367e80b002bSEric Moore 		dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
23681da177e4SLinus Torvalds 		    "sdtr %d wdtr %d ppr %d inq length=%d\n",
2369e80b002bSEric Moore 		    ioc->name, sdev->sdtr, sdev->wdtr,
2370c7c82987SMoore, Eric Dean 		    sdev->ppr, sdev->inquiry_len));
23711da177e4SLinus Torvalds 
2372c7c82987SMoore, Eric Dean 	vdevice->configured_lun = 1;
23731da177e4SLinus Torvalds 
2374e80b002bSEric Moore 	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
23751da177e4SLinus Torvalds 		"Queue depth=%d, tflags=%x\n",
2376e80b002bSEric Moore 		ioc->name, sdev->queue_depth, vtarget->tflags));
23771da177e4SLinus Torvalds 
2378e80b002bSEric Moore 	if (ioc->bus_type == SPI)
2379e80b002bSEric Moore 		dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
23801da177e4SLinus Torvalds 		    "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2381e80b002bSEric Moore 		    ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2382c7c82987SMoore, Eric Dean 		    vtarget->minSyncFactor));
23831da177e4SLinus Torvalds 
2384db5ed4dfSChristoph Hellwig 	mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
2385e80b002bSEric Moore 	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2386609aa22fSChristoph Hellwig 		"tagged %d, simple %d\n",
2387609aa22fSChristoph Hellwig 		ioc->name,sdev->tagged_supported, sdev->simple_tags));
23881da177e4SLinus Torvalds 
23892a1b7e57SRyan Kuester 	blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
23902a1b7e57SRyan Kuester 
23911da177e4SLinus Torvalds 	return 0;
23921da177e4SLinus Torvalds }
23931da177e4SLinus Torvalds 
23941da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
23951da177e4SLinus Torvalds /*
23961da177e4SLinus Torvalds  *  Private routines...
23971da177e4SLinus Torvalds  */
23981da177e4SLinus Torvalds 
23991da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
24001da177e4SLinus Torvalds /* Utility function to copy sense data from the scsi_cmnd buffer
24011da177e4SLinus Torvalds  * to the FC and SCSI target structures.
24021da177e4SLinus Torvalds  *
24031da177e4SLinus Torvalds  */
24041da177e4SLinus Torvalds static void
mptscsih_copy_sense_data(struct scsi_cmnd * sc,MPT_SCSI_HOST * hd,MPT_FRAME_HDR * mf,SCSIIOReply_t * pScsiReply)24050d0c7974SMoore, Eric Dean  mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
24061da177e4SLinus Torvalds {
2407a69de507SEric Moore 	VirtDevice	*vdevice;
24081da177e4SLinus Torvalds 	SCSIIORequest_t	*pReq;
24091da177e4SLinus Torvalds 	u32		 sense_count = le32_to_cpu(pScsiReply->SenseCount);
2410e80b002bSEric Moore 	MPT_ADAPTER 	*ioc = hd->ioc;
24111da177e4SLinus Torvalds 
24121da177e4SLinus Torvalds 	/* Get target structure
24131da177e4SLinus Torvalds 	 */
24141da177e4SLinus Torvalds 	pReq = (SCSIIORequest_t *) mf;
2415a69de507SEric Moore 	vdevice = sc->device->hostdata;
24161da177e4SLinus Torvalds 
24171da177e4SLinus Torvalds 	if (sense_count) {
24181da177e4SLinus Torvalds 		u8 *sense_data;
24191da177e4SLinus Torvalds 		int req_index;
24201da177e4SLinus Torvalds 
24211da177e4SLinus Torvalds 		/* Copy the sense received into the scsi command block. */
24221da177e4SLinus Torvalds 		req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2423e80b002bSEric Moore 		sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2424afe89f11STomas Henzl 		memcpy(sc->sense_buffer, sense_data, MPT_SENSE_BUFFER_ALLOC);
24251da177e4SLinus Torvalds 
24261da177e4SLinus Torvalds 		/* Log SMART data (asc = 0x5D, non-IM case only) if required.
24271da177e4SLinus Torvalds 		 */
2428e80b002bSEric Moore 		if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
2429a69de507SEric Moore 			if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
24301da177e4SLinus Torvalds 				int idx;
24311da177e4SLinus Torvalds 
24325b5ef4f6SMoore, Eric 				idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
24331da177e4SLinus Torvalds 				ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
24341da177e4SLinus Torvalds 				ioc->events[idx].eventContext = ioc->eventContext;
24351da177e4SLinus Torvalds 
24363d9780b9SDave Jones 				ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
24373d9780b9SDave Jones 					(MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
24383d9780b9SDave Jones 					(sc->device->channel << 8) | sc->device->id;
24391da177e4SLinus Torvalds 
24403d9780b9SDave Jones 				ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
24411da177e4SLinus Torvalds 
24421da177e4SLinus Torvalds 				ioc->eventContext++;
2443e80b002bSEric Moore 				if (ioc->pcidev->vendor ==
2444786899b0SEric Moore 				    PCI_VENDOR_ID_IBM) {
2445e80b002bSEric Moore 					mptscsih_issue_sep_command(ioc,
2446a69de507SEric Moore 					    vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2447a69de507SEric Moore 					vdevice->vtarget->tflags |=
2448786899b0SEric Moore 					    MPT_TARGET_FLAGS_LED_ON;
2449786899b0SEric Moore 				}
24501da177e4SLinus Torvalds 			}
24511da177e4SLinus Torvalds 		}
24521da177e4SLinus Torvalds 	} else {
2453e80b002bSEric Moore 		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2454e80b002bSEric Moore 				ioc->name));
24551da177e4SLinus Torvalds 	}
24561da177e4SLinus Torvalds }
24571da177e4SLinus Torvalds 
2458db7051b2SKashyap, Desai /**
2459db7051b2SKashyap, Desai  * mptscsih_get_scsi_lookup - retrieves scmd entry
2460db7051b2SKashyap, Desai  * @ioc: Pointer to MPT_ADAPTER structure
2461db7051b2SKashyap, Desai  * @i: index into the array
2462db7051b2SKashyap, Desai  *
2463db7051b2SKashyap, Desai  * Returns the scsi_cmd pointer
2464db7051b2SKashyap, Desai  */
2465db7051b2SKashyap, Desai struct scsi_cmnd *
mptscsih_get_scsi_lookup(MPT_ADAPTER * ioc,int i)2466db7051b2SKashyap, Desai mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
2467db7051b2SKashyap, Desai {
2468db7051b2SKashyap, Desai 	unsigned long	flags;
2469db7051b2SKashyap, Desai 	struct scsi_cmnd *scmd;
2470db7051b2SKashyap, Desai 
2471db7051b2SKashyap, Desai 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2472db7051b2SKashyap, Desai 	scmd = ioc->ScsiLookup[i];
2473db7051b2SKashyap, Desai 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2474db7051b2SKashyap, Desai 
2475db7051b2SKashyap, Desai 	return scmd;
2476db7051b2SKashyap, Desai }
2477db7051b2SKashyap, Desai EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
2478e8206381SEric Moore 
2479e8206381SEric Moore /**
2480fc847ab4SJames Bottomley  * mptscsih_getclear_scsi_lookup -  retrieves and clears scmd entry from ScsiLookup[] array list
24812f187862SKashyap, Desai  * @ioc: Pointer to MPT_ADAPTER structure
24822f187862SKashyap, Desai  * @i: index into the array
24832f187862SKashyap, Desai  *
24847105a387SRandy Dunlap  * Returns the scsi_cmd pointer
24852f187862SKashyap, Desai  *
2486e8206381SEric Moore  **/
2487e8206381SEric Moore static struct scsi_cmnd *
mptscsih_getclear_scsi_lookup(MPT_ADAPTER * ioc,int i)2488e8206381SEric Moore mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2489e8206381SEric Moore {
2490e8206381SEric Moore 	unsigned long	flags;
2491e8206381SEric Moore 	struct scsi_cmnd *scmd;
2492e8206381SEric Moore 
2493e8206381SEric Moore 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2494e8206381SEric Moore 	scmd = ioc->ScsiLookup[i];
2495e8206381SEric Moore 	ioc->ScsiLookup[i] = NULL;
2496e8206381SEric Moore 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2497e8206381SEric Moore 
2498e8206381SEric Moore 	return scmd;
2499e8206381SEric Moore }
2500e8206381SEric Moore 
2501e8206381SEric Moore /**
25029b8f77a1SBen Hutchings  * mptscsih_set_scsi_lookup - write a scmd entry into the ScsiLookup[] array list
2503e8206381SEric Moore  *
2504e8206381SEric Moore  * @ioc: Pointer to MPT_ADAPTER structure
2505e8206381SEric Moore  * @i: index into the array
2506e8206381SEric Moore  * @scmd: scsi_cmnd pointer
2507e8206381SEric Moore  *
2508e8206381SEric Moore  **/
2509e8206381SEric Moore static void
mptscsih_set_scsi_lookup(MPT_ADAPTER * ioc,int i,struct scsi_cmnd * scmd)2510e8206381SEric Moore mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2511e8206381SEric Moore {
2512e8206381SEric Moore 	unsigned long	flags;
2513e8206381SEric Moore 
2514e8206381SEric Moore 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2515e8206381SEric Moore 	ioc->ScsiLookup[i] = scmd;
2516e8206381SEric Moore 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2517e8206381SEric Moore }
2518e8206381SEric Moore 
2519e8206381SEric Moore /**
252023f9b75eSRandy Dunlap  * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
2521e8206381SEric Moore  * @ioc: Pointer to MPT_ADAPTER structure
252223f9b75eSRandy Dunlap  * @sc: scsi_cmnd pointer
252323f9b75eSRandy Dunlap  */
2524e8206381SEric Moore static int
SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER * ioc,struct scsi_cmnd * sc)2525e8206381SEric Moore SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2526e8206381SEric Moore {
2527e8206381SEric Moore 	unsigned long	flags;
2528e8206381SEric Moore 	int i, index=-1;
2529e8206381SEric Moore 
2530e8206381SEric Moore 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2531e8206381SEric Moore 	for (i = 0; i < ioc->req_depth; i++) {
2532e8206381SEric Moore 		if (ioc->ScsiLookup[i] == sc) {
2533e8206381SEric Moore 			index = i;
2534e8206381SEric Moore 			goto out;
25351da177e4SLinus Torvalds 		}
25361da177e4SLinus Torvalds 	}
25371da177e4SLinus Torvalds 
2538e8206381SEric Moore  out:
2539e8206381SEric Moore 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2540e8206381SEric Moore 	return index;
25411da177e4SLinus Torvalds }
25421da177e4SLinus Torvalds 
25431da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
25440d0c7974SMoore, Eric Dean  int
mptscsih_ioc_reset(MPT_ADAPTER * ioc,int reset_phase)25451da177e4SLinus Torvalds mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
25461da177e4SLinus Torvalds {
25471da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
25481da177e4SLinus Torvalds 
2549e7eae9f6SEric Moore 	if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
25501da177e4SLinus Torvalds 		return 0;
255137c60f37SKashyap, Desai 
2552e7eae9f6SEric Moore 	hd = shost_priv(ioc->sh);
255337c60f37SKashyap, Desai 	switch (reset_phase) {
255437c60f37SKashyap, Desai 	case MPT_IOC_SETUP_RESET:
255537c60f37SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
255637c60f37SKashyap, Desai 		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
255737c60f37SKashyap, Desai 		break;
255837c60f37SKashyap, Desai 	case MPT_IOC_PRE_RESET:
255937c60f37SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
256037c60f37SKashyap, Desai 		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
256137c60f37SKashyap, Desai 		mptscsih_flush_running_cmds(hd);
256237c60f37SKashyap, Desai 		break;
256337c60f37SKashyap, Desai 	case MPT_IOC_POST_RESET:
256437c60f37SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
256537c60f37SKashyap, Desai 		    "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
256637c60f37SKashyap, Desai 		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
256737c60f37SKashyap, Desai 			ioc->internal_cmds.status |=
256837c60f37SKashyap, Desai 				MPT_MGMT_STATUS_DID_IOCRESET;
256937c60f37SKashyap, Desai 			complete(&ioc->internal_cmds.done);
25701da177e4SLinus Torvalds 		}
257137c60f37SKashyap, Desai 		break;
257237c60f37SKashyap, Desai 	default:
257337c60f37SKashyap, Desai 		break;
25741da177e4SLinus Torvalds 	}
25751da177e4SLinus Torvalds 	return 1;		/* currently means nothing really */
25761da177e4SLinus Torvalds }
25771da177e4SLinus Torvalds 
25781da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
25790d0c7974SMoore, Eric Dean  int
mptscsih_event_process(MPT_ADAPTER * ioc,EventNotificationReply_t * pEvReply)25801da177e4SLinus Torvalds mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
25811da177e4SLinus Torvalds {
25821da177e4SLinus Torvalds 	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
25831da177e4SLinus Torvalds 
258437c60f37SKashyap, Desai 	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
258537c60f37SKashyap, Desai 		"MPT event (=%02Xh) routed to SCSI host driver!\n",
25861da177e4SLinus Torvalds 		ioc->name, event));
25871da177e4SLinus Torvalds 
25882f187862SKashyap, Desai 	if ((event == MPI_EVENT_IOC_BUS_RESET ||
25892f187862SKashyap, Desai 	    event == MPI_EVENT_EXT_BUS_RESET) &&
25902f187862SKashyap, Desai 	    (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
25912f187862SKashyap, Desai 			ioc->soft_resets++;
25921da177e4SLinus Torvalds 
25931da177e4SLinus Torvalds 	return 1;		/* currently means nothing really */
25941da177e4SLinus Torvalds }
25951da177e4SLinus Torvalds 
25961da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
25971da177e4SLinus Torvalds /*
25981da177e4SLinus Torvalds  *  Bus Scan and Domain Validation functionality ...
25991da177e4SLinus Torvalds  */
26001da177e4SLinus Torvalds 
26011da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26021da177e4SLinus Torvalds /*
26031da177e4SLinus Torvalds  *	mptscsih_scandv_complete - Scan and DV callback routine registered
26041da177e4SLinus Torvalds  *	to Fustion MPT (base) driver.
26051da177e4SLinus Torvalds  *
26061da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
26071da177e4SLinus Torvalds  *	@mf: Pointer to original MPT request frame
26081da177e4SLinus Torvalds  *	@mr: Pointer to MPT reply frame (NULL if TurboReply)
26091da177e4SLinus Torvalds  *
26101da177e4SLinus Torvalds  *	This routine is called from mpt.c::mpt_interrupt() at the completion
26111da177e4SLinus Torvalds  *	of any SCSI IO request.
26121da177e4SLinus Torvalds  *	This routine is registered with the Fusion MPT (base) driver at driver
26131da177e4SLinus Torvalds  *	load/init time via the mpt_register() API call.
26141da177e4SLinus Torvalds  *
26151da177e4SLinus Torvalds  *	Returns 1 indicating alloc'd request frame ptr should be freed.
26161da177e4SLinus Torvalds  *
26171da177e4SLinus Torvalds  *	Remark: Sets a completion code and (possibly) saves sense data
26181da177e4SLinus Torvalds  *	in the IOC member localReply structure.
26191da177e4SLinus Torvalds  *	Used ONLY for DV and other internal commands.
26201da177e4SLinus Torvalds  */
26210d0c7974SMoore, Eric Dean  int
mptscsih_scandv_complete(MPT_ADAPTER * ioc,MPT_FRAME_HDR * req,MPT_FRAME_HDR * reply)262237c60f37SKashyap, Desai mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
262337c60f37SKashyap, Desai 				MPT_FRAME_HDR *reply)
26241da177e4SLinus Torvalds {
26251da177e4SLinus Torvalds 	SCSIIORequest_t *pReq;
26261da177e4SLinus Torvalds 	SCSIIOReply_t	*pReply;
262737c60f37SKashyap, Desai 	u8		 cmd;
262837c60f37SKashyap, Desai 	u16		 req_idx;
26291da177e4SLinus Torvalds 	u8	*sense_data;
26301da177e4SLinus Torvalds 	int		 sz;
26311da177e4SLinus Torvalds 
263237c60f37SKashyap, Desai 	ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
263337c60f37SKashyap, Desai 	ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
263437c60f37SKashyap, Desai 	if (!reply)
263537c60f37SKashyap, Desai 		goto out;
263637c60f37SKashyap, Desai 
263737c60f37SKashyap, Desai 	pReply = (SCSIIOReply_t *) reply;
263837c60f37SKashyap, Desai 	pReq = (SCSIIORequest_t *) req;
263937c60f37SKashyap, Desai 	ioc->internal_cmds.completion_code =
264037c60f37SKashyap, Desai 	    mptscsih_get_completion_code(ioc, req, reply);
264137c60f37SKashyap, Desai 	ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
264237c60f37SKashyap, Desai 	memcpy(ioc->internal_cmds.reply, reply,
264337c60f37SKashyap, Desai 	    min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
264437c60f37SKashyap, Desai 	cmd = reply->u.hdr.Function;
264537c60f37SKashyap, Desai 	if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
264637c60f37SKashyap, Desai 	    (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
264737c60f37SKashyap, Desai 	    (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
264837c60f37SKashyap, Desai 		req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2649e80b002bSEric Moore 		sense_data = ((u8 *)ioc->sense_buf_pool +
26501da177e4SLinus Torvalds 		    (req_idx * MPT_SENSE_BUFFER_ALLOC));
26511da177e4SLinus Torvalds 		sz = min_t(int, pReq->SenseBufferLength,
265237c60f37SKashyap, Desai 		    MPT_SENSE_BUFFER_ALLOC);
265337c60f37SKashyap, Desai 		memcpy(ioc->internal_cmds.sense, sense_data, sz);
26541da177e4SLinus Torvalds 	}
265537c60f37SKashyap, Desai  out:
265637c60f37SKashyap, Desai 	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
265737c60f37SKashyap, Desai 		return 0;
265837c60f37SKashyap, Desai 	ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
265937c60f37SKashyap, Desai 	complete(&ioc->internal_cmds.done);
26601da177e4SLinus Torvalds 	return 1;
26611da177e4SLinus Torvalds }
26621da177e4SLinus Torvalds 
26631da177e4SLinus Torvalds 
266437c60f37SKashyap, Desai /**
26659b8f77a1SBen Hutchings  *	mptscsih_get_completion_code - get completion code from MPT request
266637c60f37SKashyap, Desai  *	@ioc: Pointer to MPT_ADAPTER structure
26679cf46a35SRandy Dunlap  *	@req: Pointer to original MPT request frame
26689cf46a35SRandy Dunlap  *	@reply: Pointer to MPT reply frame (NULL if TurboReply)
266937c60f37SKashyap, Desai  *
267037c60f37SKashyap, Desai  **/
267137c60f37SKashyap, Desai static int
mptscsih_get_completion_code(MPT_ADAPTER * ioc,MPT_FRAME_HDR * req,MPT_FRAME_HDR * reply)267237c60f37SKashyap, Desai mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
267337c60f37SKashyap, Desai 				MPT_FRAME_HDR *reply)
267437c60f37SKashyap, Desai {
267537c60f37SKashyap, Desai 	SCSIIOReply_t	*pReply;
267637c60f37SKashyap, Desai 	MpiRaidActionReply_t *pr;
267737c60f37SKashyap, Desai 	u8		 scsi_status;
267837c60f37SKashyap, Desai 	u16		 status;
267937c60f37SKashyap, Desai 	int		 completion_code;
268037c60f37SKashyap, Desai 
268137c60f37SKashyap, Desai 	pReply = (SCSIIOReply_t *)reply;
268237c60f37SKashyap, Desai 	status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
268337c60f37SKashyap, Desai 	scsi_status = pReply->SCSIStatus;
268437c60f37SKashyap, Desai 
268537c60f37SKashyap, Desai 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
268637c60f37SKashyap, Desai 	    "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
268737c60f37SKashyap, Desai 	    "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
268837c60f37SKashyap, Desai 	    scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
268937c60f37SKashyap, Desai 
269037c60f37SKashyap, Desai 	switch (status) {
269137c60f37SKashyap, Desai 
269237c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
269337c60f37SKashyap, Desai 		completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
269437c60f37SKashyap, Desai 		break;
269537c60f37SKashyap, Desai 
269637c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
269737c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
269837c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
269937c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
270037c60f37SKashyap, Desai 		completion_code = MPT_SCANDV_DID_RESET;
270137c60f37SKashyap, Desai 		break;
270237c60f37SKashyap, Desai 
270337c60f37SKashyap, Desai 	case MPI_IOCSTATUS_BUSY:
270437c60f37SKashyap, Desai 	case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
270537c60f37SKashyap, Desai 		completion_code = MPT_SCANDV_BUSY;
270637c60f37SKashyap, Desai 		break;
270737c60f37SKashyap, Desai 
270837c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
270937c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
271037c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
271137c60f37SKashyap, Desai 		if (pReply->Function == MPI_FUNCTION_CONFIG) {
271237c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_GOOD;
271337c60f37SKashyap, Desai 		} else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
271437c60f37SKashyap, Desai 			pr = (MpiRaidActionReply_t *)reply;
271537c60f37SKashyap, Desai 			if (le16_to_cpu(pr->ActionStatus) ==
271637c60f37SKashyap, Desai 				MPI_RAID_ACTION_ASTATUS_SUCCESS)
271737c60f37SKashyap, Desai 				completion_code = MPT_SCANDV_GOOD;
271837c60f37SKashyap, Desai 			else
271937c60f37SKashyap, Desai 				completion_code = MPT_SCANDV_SOME_ERROR;
272037c60f37SKashyap, Desai 		} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
272137c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_SENSE;
272237c60f37SKashyap, Desai 		else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
272337c60f37SKashyap, Desai 			if (req->u.scsireq.CDB[0] == INQUIRY)
272437c60f37SKashyap, Desai 				completion_code = MPT_SCANDV_ISSUE_SENSE;
272537c60f37SKashyap, Desai 			else
272637c60f37SKashyap, Desai 				completion_code = MPT_SCANDV_DID_RESET;
272737c60f37SKashyap, Desai 		} else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
272837c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_DID_RESET;
272937c60f37SKashyap, Desai 		else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
273037c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_DID_RESET;
273137c60f37SKashyap, Desai 		else if (scsi_status == MPI_SCSI_STATUS_BUSY)
273237c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_BUSY;
273337c60f37SKashyap, Desai 		else
273437c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_GOOD;
273537c60f37SKashyap, Desai 		break;
273637c60f37SKashyap, Desai 
273737c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
273837c60f37SKashyap, Desai 		if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
273937c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_DID_RESET;
274037c60f37SKashyap, Desai 		else
274137c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_SOME_ERROR;
274237c60f37SKashyap, Desai 		break;
274337c60f37SKashyap, Desai 	default:
274437c60f37SKashyap, Desai 		completion_code = MPT_SCANDV_SOME_ERROR;
274537c60f37SKashyap, Desai 		break;
274637c60f37SKashyap, Desai 
274737c60f37SKashyap, Desai 	}	/* switch(status) */
274837c60f37SKashyap, Desai 
274937c60f37SKashyap, Desai 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
275037c60f37SKashyap, Desai 	    "  completionCode set to %08xh\n", ioc->name, completion_code));
275137c60f37SKashyap, Desai 	return completion_code;
275237c60f37SKashyap, Desai }
27531da177e4SLinus Torvalds 
27541da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
27551da177e4SLinus Torvalds /**
27561da177e4SLinus Torvalds  *	mptscsih_do_cmd - Do internal command.
27571da177e4SLinus Torvalds  *	@hd: MPT_SCSI_HOST pointer
27581da177e4SLinus Torvalds  *	@io: INTERNAL_CMD pointer.
27591da177e4SLinus Torvalds  *
27601da177e4SLinus Torvalds  *	Issue the specified internally generated command and do command
27611da177e4SLinus Torvalds  *	specific cleanup. For bus scan / DV only.
27621da177e4SLinus Torvalds  *	NOTES: If command is Inquiry and status is good,
27631da177e4SLinus Torvalds  *	initialize a target structure, save the data
27641da177e4SLinus Torvalds  *
27651da177e4SLinus Torvalds  *	Remark: Single threaded access only.
27661da177e4SLinus Torvalds  *
27671da177e4SLinus Torvalds  *	Return:
27681da177e4SLinus Torvalds  *		< 0 if an illegal command or no resources
27691da177e4SLinus Torvalds  *
27701da177e4SLinus Torvalds  *		   0 if good
27711da177e4SLinus Torvalds  *
27721da177e4SLinus Torvalds  *		 > 0 if command complete but some type of completion error.
27731da177e4SLinus Torvalds  */
27741da177e4SLinus Torvalds static int
mptscsih_do_cmd(MPT_SCSI_HOST * hd,INTERNAL_CMD * io)27751da177e4SLinus Torvalds mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
27761da177e4SLinus Torvalds {
27771da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
27781da177e4SLinus Torvalds 	SCSIIORequest_t	*pScsiReq;
27791da177e4SLinus Torvalds 	int		 my_idx, ii, dir;
278037c60f37SKashyap, Desai 	int		 timeout;
27811da177e4SLinus Torvalds 	char		 cmdLen;
27821da177e4SLinus Torvalds 	char		 CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
278337c60f37SKashyap, Desai 	u8		 cmd = io->cmd;
2784e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
278537c60f37SKashyap, Desai 	int		 ret = 0;
278637c60f37SKashyap, Desai 	unsigned long	 timeleft;
278737c60f37SKashyap, Desai 	unsigned long	 flags;
27881da177e4SLinus Torvalds 
27891ba9ab2eSKashyap, Desai 	/* don't send internal command during diag reset */
27901ba9ab2eSKashyap, Desai 	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
27911ba9ab2eSKashyap, Desai 	if (ioc->ioc_reset_in_progress) {
27921ba9ab2eSKashyap, Desai 		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
27931ba9ab2eSKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
27941ba9ab2eSKashyap, Desai 			"%s: busy with host reset\n", ioc->name, __func__));
27951ba9ab2eSKashyap, Desai 		return MPT_SCANDV_BUSY;
27961ba9ab2eSKashyap, Desai 	}
27971ba9ab2eSKashyap, Desai 	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
27981ba9ab2eSKashyap, Desai 
279937c60f37SKashyap, Desai 	mutex_lock(&ioc->internal_cmds.mutex);
28001da177e4SLinus Torvalds 
28011da177e4SLinus Torvalds 	/* Set command specific information
28021da177e4SLinus Torvalds 	 */
28031da177e4SLinus Torvalds 	switch (cmd) {
28041da177e4SLinus Torvalds 	case INQUIRY:
28051da177e4SLinus Torvalds 		cmdLen = 6;
28061da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
28071da177e4SLinus Torvalds 		CDB[0] = cmd;
28081da177e4SLinus Torvalds 		CDB[4] = io->size;
280937c60f37SKashyap, Desai 		timeout = 10;
28101da177e4SLinus Torvalds 		break;
28111da177e4SLinus Torvalds 
28121da177e4SLinus Torvalds 	case TEST_UNIT_READY:
28131da177e4SLinus Torvalds 		cmdLen = 6;
28141da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
281537c60f37SKashyap, Desai 		timeout = 10;
28161da177e4SLinus Torvalds 		break;
28171da177e4SLinus Torvalds 
28181da177e4SLinus Torvalds 	case START_STOP:
28191da177e4SLinus Torvalds 		cmdLen = 6;
28201da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
28211da177e4SLinus Torvalds 		CDB[0] = cmd;
28221da177e4SLinus Torvalds 		CDB[4] = 1;	/*Spin up the disk */
282337c60f37SKashyap, Desai 		timeout = 15;
28241da177e4SLinus Torvalds 		break;
28251da177e4SLinus Torvalds 
28261da177e4SLinus Torvalds 	case REQUEST_SENSE:
28271da177e4SLinus Torvalds 		cmdLen = 6;
28281da177e4SLinus Torvalds 		CDB[0] = cmd;
28291da177e4SLinus Torvalds 		CDB[4] = io->size;
28301da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
283137c60f37SKashyap, Desai 		timeout = 10;
28321da177e4SLinus Torvalds 		break;
28331da177e4SLinus Torvalds 
28341da177e4SLinus Torvalds 	case READ_BUFFER:
28351da177e4SLinus Torvalds 		cmdLen = 10;
28361da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
28371da177e4SLinus Torvalds 		CDB[0] = cmd;
28381da177e4SLinus Torvalds 		if (io->flags & MPT_ICFLAG_ECHO) {
28391da177e4SLinus Torvalds 			CDB[1] = 0x0A;
28401da177e4SLinus Torvalds 		} else {
28411da177e4SLinus Torvalds 			CDB[1] = 0x02;
28421da177e4SLinus Torvalds 		}
28431da177e4SLinus Torvalds 
28441da177e4SLinus Torvalds 		if (io->flags & MPT_ICFLAG_BUF_CAP) {
28451da177e4SLinus Torvalds 			CDB[1] |= 0x01;
28461da177e4SLinus Torvalds 		}
28471da177e4SLinus Torvalds 		CDB[6] = (io->size >> 16) & 0xFF;
28481da177e4SLinus Torvalds 		CDB[7] = (io->size >>  8) & 0xFF;
28491da177e4SLinus Torvalds 		CDB[8] = io->size & 0xFF;
285037c60f37SKashyap, Desai 		timeout = 10;
28511da177e4SLinus Torvalds 		break;
28521da177e4SLinus Torvalds 
28531da177e4SLinus Torvalds 	case WRITE_BUFFER:
28541da177e4SLinus Torvalds 		cmdLen = 10;
28551da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_WRITE;
28561da177e4SLinus Torvalds 		CDB[0] = cmd;
28571da177e4SLinus Torvalds 		if (io->flags & MPT_ICFLAG_ECHO) {
28581da177e4SLinus Torvalds 			CDB[1] = 0x0A;
28591da177e4SLinus Torvalds 		} else {
28601da177e4SLinus Torvalds 			CDB[1] = 0x02;
28611da177e4SLinus Torvalds 		}
28621da177e4SLinus Torvalds 		CDB[6] = (io->size >> 16) & 0xFF;
28631da177e4SLinus Torvalds 		CDB[7] = (io->size >>  8) & 0xFF;
28641da177e4SLinus Torvalds 		CDB[8] = io->size & 0xFF;
286537c60f37SKashyap, Desai 		timeout = 10;
28661da177e4SLinus Torvalds 		break;
28671da177e4SLinus Torvalds 
28681da177e4SLinus Torvalds 	case RESERVE:
28691da177e4SLinus Torvalds 		cmdLen = 6;
28701da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
28711da177e4SLinus Torvalds 		CDB[0] = cmd;
287237c60f37SKashyap, Desai 		timeout = 10;
28731da177e4SLinus Torvalds 		break;
28741da177e4SLinus Torvalds 
28751da177e4SLinus Torvalds 	case RELEASE:
28761da177e4SLinus Torvalds 		cmdLen = 6;
28771da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
28781da177e4SLinus Torvalds 		CDB[0] = cmd;
287937c60f37SKashyap, Desai 		timeout = 10;
28801da177e4SLinus Torvalds 		break;
28811da177e4SLinus Torvalds 
28821da177e4SLinus Torvalds 	case SYNCHRONIZE_CACHE:
28831da177e4SLinus Torvalds 		cmdLen = 10;
28841da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
28851da177e4SLinus Torvalds 		CDB[0] = cmd;
28861da177e4SLinus Torvalds //		CDB[1] = 0x02;	/* set immediate bit */
288737c60f37SKashyap, Desai 		timeout = 10;
28881da177e4SLinus Torvalds 		break;
28891da177e4SLinus Torvalds 
28901da177e4SLinus Torvalds 	default:
28911da177e4SLinus Torvalds 		/* Error Case */
289237c60f37SKashyap, Desai 		ret = -EFAULT;
289337c60f37SKashyap, Desai 		goto out;
28941da177e4SLinus Torvalds 	}
28951da177e4SLinus Torvalds 
28961da177e4SLinus Torvalds 	/* Get and Populate a free Frame
289737c60f37SKashyap, Desai 	 * MsgContext set in mpt_get_msg_frame call
28981da177e4SLinus Torvalds 	 */
2899e80b002bSEric Moore 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
290037c60f37SKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
290137c60f37SKashyap, Desai 		    ioc->name, __func__));
290237c60f37SKashyap, Desai 		ret = MPT_SCANDV_BUSY;
290337c60f37SKashyap, Desai 		goto out;
29041da177e4SLinus Torvalds 	}
29051da177e4SLinus Torvalds 
29061da177e4SLinus Torvalds 	pScsiReq = (SCSIIORequest_t *) mf;
29071da177e4SLinus Torvalds 
29081da177e4SLinus Torvalds 	/* Get the request index */
29091da177e4SLinus Torvalds 	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
29101da177e4SLinus Torvalds 	ADD_INDEX_LOG(my_idx); /* for debug */
29111da177e4SLinus Torvalds 
29121da177e4SLinus Torvalds 	if (io->flags & MPT_ICFLAG_PHYS_DISK) {
29131da177e4SLinus Torvalds 		pScsiReq->TargetID = io->physDiskNum;
29141da177e4SLinus Torvalds 		pScsiReq->Bus = 0;
29151da177e4SLinus Torvalds 		pScsiReq->ChainOffset = 0;
29161da177e4SLinus Torvalds 		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
29171da177e4SLinus Torvalds 	} else {
29181da177e4SLinus Torvalds 		pScsiReq->TargetID = io->id;
2919793955f5SEric Moore 		pScsiReq->Bus = io->channel;
29201da177e4SLinus Torvalds 		pScsiReq->ChainOffset = 0;
29211da177e4SLinus Torvalds 		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
29221da177e4SLinus Torvalds 	}
29231da177e4SLinus Torvalds 
29241da177e4SLinus Torvalds 	pScsiReq->CDBLength = cmdLen;
29251da177e4SLinus Torvalds 	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
29261da177e4SLinus Torvalds 
29271da177e4SLinus Torvalds 	pScsiReq->Reserved = 0;
29281da177e4SLinus Torvalds 
292914d0f0b0SKashyap, Desai 	pScsiReq->MsgFlags = mpt_msg_flags(ioc);
29301da177e4SLinus Torvalds 	/* MsgContext set in mpt_get_msg_fram call  */
29311da177e4SLinus Torvalds 
2932793955f5SEric Moore 	int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
29331da177e4SLinus Torvalds 
29341da177e4SLinus Torvalds 	if (io->flags & MPT_ICFLAG_TAGGED_CMD)
29351da177e4SLinus Torvalds 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
29361da177e4SLinus Torvalds 	else
29371da177e4SLinus Torvalds 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
29381da177e4SLinus Torvalds 
29391da177e4SLinus Torvalds 	if (cmd == REQUEST_SENSE) {
29401da177e4SLinus Torvalds 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
294137c60f37SKashyap, Desai 		devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
294237c60f37SKashyap, Desai 		    "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
29431da177e4SLinus Torvalds 	}
29441da177e4SLinus Torvalds 
29451da177e4SLinus Torvalds 	for (ii = 0; ii < 16; ii++)
29461da177e4SLinus Torvalds 		pScsiReq->CDB[ii] = CDB[ii];
29471da177e4SLinus Torvalds 
29481da177e4SLinus Torvalds 	pScsiReq->DataLength = cpu_to_le32(io->size);
2949e80b002bSEric Moore 	pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
29501da177e4SLinus Torvalds 					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
29511da177e4SLinus Torvalds 
295237c60f37SKashyap, Desai 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
29539cb78c16SHannes Reinecke 	    "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%llu\n",
295437c60f37SKashyap, Desai 	    ioc->name, __func__, cmd, io->channel, io->id, io->lun));
29551da177e4SLinus Torvalds 
295637c60f37SKashyap, Desai 	if (dir == MPI_SCSIIO_CONTROL_READ)
295714d0f0b0SKashyap, Desai 		ioc->add_sge((char *) &pScsiReq->SGL,
295837c60f37SKashyap, Desai 		    MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
295937c60f37SKashyap, Desai 	else
296014d0f0b0SKashyap, Desai 		ioc->add_sge((char *) &pScsiReq->SGL,
296137c60f37SKashyap, Desai 		    MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
29621da177e4SLinus Torvalds 
296337c60f37SKashyap, Desai 	INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
2964e80b002bSEric Moore 	mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
296537c60f37SKashyap, Desai 	timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
296637c60f37SKashyap, Desai 	    timeout*HZ);
296737c60f37SKashyap, Desai 	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
296837c60f37SKashyap, Desai 		ret = MPT_SCANDV_DID_RESET;
296937c60f37SKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
297037c60f37SKashyap, Desai 		    "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
297137c60f37SKashyap, Desai 		    cmd));
297237c60f37SKashyap, Desai 		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
297337c60f37SKashyap, Desai 			mpt_free_msg_frame(ioc, mf);
297437c60f37SKashyap, Desai 			goto out;
297537c60f37SKashyap, Desai 		}
297637c60f37SKashyap, Desai 		if (!timeleft) {
297797009a29SKei Tokunaga 			printk(MYIOC_s_WARN_FMT
297897009a29SKei Tokunaga 			       "Issuing Reset from %s!! doorbell=0x%08xh"
297997009a29SKei Tokunaga 			       " cmd=0x%02x\n",
298097009a29SKei Tokunaga 			       ioc->name, __func__, mpt_GetIocState(ioc, 0),
298197009a29SKei Tokunaga 			       cmd);
2982d0f698c4SKashyap, Desai 			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
298337c60f37SKashyap, Desai 			mpt_free_msg_frame(ioc, mf);
298437c60f37SKashyap, Desai 		}
298537c60f37SKashyap, Desai 		goto out;
29861da177e4SLinus Torvalds 	}
29871da177e4SLinus Torvalds 
298837c60f37SKashyap, Desai 	ret = ioc->internal_cmds.completion_code;
298937c60f37SKashyap, Desai 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
299037c60f37SKashyap, Desai 			ioc->name, __func__, ret));
299137c60f37SKashyap, Desai 
299237c60f37SKashyap, Desai  out:
299337c60f37SKashyap, Desai 	CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
299437c60f37SKashyap, Desai 	mutex_unlock(&ioc->internal_cmds.mutex);
299537c60f37SKashyap, Desai 	return ret;
29961da177e4SLinus Torvalds }
29971da177e4SLinus Torvalds 
29981da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
29991da177e4SLinus Torvalds /**
3000c7c82987SMoore, Eric Dean  *	mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3001c7c82987SMoore, Eric Dean  *	@hd: Pointer to a SCSI HOST structure
3002d9489fb6SRandy Dunlap  *	@vdevice: virtual target device
3003c7c82987SMoore, Eric Dean  *
3004c7c82987SMoore, Eric Dean  *	Uses the ISR, but with special processing.
3005c7c82987SMoore, Eric Dean  *	MUST be single-threaded.
3006c7c82987SMoore, Eric Dean  *
3007c7c82987SMoore, Eric Dean  */
3008c7c82987SMoore, Eric Dean static void
mptscsih_synchronize_cache(MPT_SCSI_HOST * hd,VirtDevice * vdevice)3009c7c82987SMoore, Eric Dean mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3010c7c82987SMoore, Eric Dean {
3011c7c82987SMoore, Eric Dean 	INTERNAL_CMD		 iocmd;
30121da177e4SLinus Torvalds 
3013cc78d30aSEric Moore 	/* Ignore hidden raid components, this is handled when the command
3014cc78d30aSEric Moore 	 * is sent to the volume
3015cc78d30aSEric Moore 	 */
3016cc78d30aSEric Moore 	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3017cc78d30aSEric Moore 		return;
3018cc78d30aSEric Moore 
3019cc78d30aSEric Moore 	if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3020cc78d30aSEric Moore 	    !vdevice->configured_lun)
3021cc78d30aSEric Moore 		return;
3022cc78d30aSEric Moore 
30231da177e4SLinus Torvalds 	/* Following parameters will not change
30241da177e4SLinus Torvalds 	 * in this routine.
30251da177e4SLinus Torvalds 	 */
30261da177e4SLinus Torvalds 	iocmd.cmd = SYNCHRONIZE_CACHE;
30271da177e4SLinus Torvalds 	iocmd.flags = 0;
30281da177e4SLinus Torvalds 	iocmd.physDiskNum = -1;
30291da177e4SLinus Torvalds 	iocmd.data = NULL;
30301da177e4SLinus Torvalds 	iocmd.data_dma = -1;
30311da177e4SLinus Torvalds 	iocmd.size = 0;
30321da177e4SLinus Torvalds 	iocmd.rsvd = iocmd.rsvd2 = 0;
3033793955f5SEric Moore 	iocmd.channel = vdevice->vtarget->channel;
3034793955f5SEric Moore 	iocmd.id = vdevice->vtarget->id;
3035793955f5SEric Moore 	iocmd.lun = vdevice->lun;
30361da177e4SLinus Torvalds 
3037c7c82987SMoore, Eric Dean 	mptscsih_do_cmd(hd, &iocmd);
30381da177e4SLinus Torvalds }
30391da177e4SLinus Torvalds 
3040edb9068dSPrakash, Sathya static ssize_t
mptscsih_version_fw_show(struct device * dev,struct device_attribute * attr,char * buf)3041ee959b00STony Jones mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3042ee959b00STony Jones 			 char *buf)
3043edb9068dSPrakash, Sathya {
3044ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3045e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3046edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3047edb9068dSPrakash, Sathya 
3048edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3049edb9068dSPrakash, Sathya 	    (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3050edb9068dSPrakash, Sathya 	    (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3051edb9068dSPrakash, Sathya 	    (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3052edb9068dSPrakash, Sathya 	    ioc->facts.FWVersion.Word & 0x000000FF);
3053edb9068dSPrakash, Sathya }
3054ee959b00STony Jones static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
3055edb9068dSPrakash, Sathya 
3056edb9068dSPrakash, Sathya static ssize_t
mptscsih_version_bios_show(struct device * dev,struct device_attribute * attr,char * buf)3057ee959b00STony Jones mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3058ee959b00STony Jones 			   char *buf)
3059edb9068dSPrakash, Sathya {
3060ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3061e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3062edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3063edb9068dSPrakash, Sathya 
3064edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3065edb9068dSPrakash, Sathya 	    (ioc->biosVersion & 0xFF000000) >> 24,
3066edb9068dSPrakash, Sathya 	    (ioc->biosVersion & 0x00FF0000) >> 16,
3067edb9068dSPrakash, Sathya 	    (ioc->biosVersion & 0x0000FF00) >> 8,
3068edb9068dSPrakash, Sathya 	    ioc->biosVersion & 0x000000FF);
3069edb9068dSPrakash, Sathya }
3070ee959b00STony Jones static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
3071edb9068dSPrakash, Sathya 
3072edb9068dSPrakash, Sathya static ssize_t
mptscsih_version_mpi_show(struct device * dev,struct device_attribute * attr,char * buf)3073ee959b00STony Jones mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3074ee959b00STony Jones 			  char *buf)
3075edb9068dSPrakash, Sathya {
3076ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3077e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3078edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3079edb9068dSPrakash, Sathya 
3080edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3081edb9068dSPrakash, Sathya }
3082ee959b00STony Jones static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
3083edb9068dSPrakash, Sathya 
3084edb9068dSPrakash, Sathya static ssize_t
mptscsih_version_product_show(struct device * dev,struct device_attribute * attr,char * buf)3085ee959b00STony Jones mptscsih_version_product_show(struct device *dev,
3086ee959b00STony Jones 			      struct device_attribute *attr,
3087ee959b00STony Jones char *buf)
3088edb9068dSPrakash, Sathya {
3089ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3090e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3091edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3092edb9068dSPrakash, Sathya 
3093edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3094edb9068dSPrakash, Sathya }
3095ee959b00STony Jones static DEVICE_ATTR(version_product, S_IRUGO,
3096edb9068dSPrakash, Sathya     mptscsih_version_product_show, NULL);
3097edb9068dSPrakash, Sathya 
3098edb9068dSPrakash, Sathya static ssize_t
mptscsih_version_nvdata_persistent_show(struct device * dev,struct device_attribute * attr,char * buf)3099ee959b00STony Jones mptscsih_version_nvdata_persistent_show(struct device *dev,
3100ee959b00STony Jones 					struct device_attribute *attr,
3101ee959b00STony Jones 					char *buf)
3102edb9068dSPrakash, Sathya {
3103ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3104e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3105edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3106edb9068dSPrakash, Sathya 
3107edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02xh\n",
3108edb9068dSPrakash, Sathya 	    ioc->nvdata_version_persistent);
3109edb9068dSPrakash, Sathya }
3110ee959b00STony Jones static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
3111edb9068dSPrakash, Sathya     mptscsih_version_nvdata_persistent_show, NULL);
3112edb9068dSPrakash, Sathya 
3113edb9068dSPrakash, Sathya static ssize_t
mptscsih_version_nvdata_default_show(struct device * dev,struct device_attribute * attr,char * buf)3114ee959b00STony Jones mptscsih_version_nvdata_default_show(struct device *dev,
3115ee959b00STony Jones 				     struct device_attribute *attr, char *buf)
3116edb9068dSPrakash, Sathya {
3117ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3118e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3119edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3120edb9068dSPrakash, Sathya 
3121edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3122edb9068dSPrakash, Sathya }
3123ee959b00STony Jones static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
3124edb9068dSPrakash, Sathya     mptscsih_version_nvdata_default_show, NULL);
3125edb9068dSPrakash, Sathya 
3126edb9068dSPrakash, Sathya static ssize_t
mptscsih_board_name_show(struct device * dev,struct device_attribute * attr,char * buf)3127ee959b00STony Jones mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3128ee959b00STony Jones 			 char *buf)
3129edb9068dSPrakash, Sathya {
3130ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3131e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3132edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3133edb9068dSPrakash, Sathya 
3134edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3135edb9068dSPrakash, Sathya }
3136ee959b00STony Jones static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
3137edb9068dSPrakash, Sathya 
3138edb9068dSPrakash, Sathya static ssize_t
mptscsih_board_assembly_show(struct device * dev,struct device_attribute * attr,char * buf)3139ee959b00STony Jones mptscsih_board_assembly_show(struct device *dev,
3140ee959b00STony Jones 			     struct device_attribute *attr, char *buf)
3141edb9068dSPrakash, Sathya {
3142ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3143e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3144edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3145edb9068dSPrakash, Sathya 
3146edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3147edb9068dSPrakash, Sathya }
3148ee959b00STony Jones static DEVICE_ATTR(board_assembly, S_IRUGO,
3149edb9068dSPrakash, Sathya     mptscsih_board_assembly_show, NULL);
3150edb9068dSPrakash, Sathya 
3151edb9068dSPrakash, Sathya static ssize_t
mptscsih_board_tracer_show(struct device * dev,struct device_attribute * attr,char * buf)3152ee959b00STony Jones mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3153ee959b00STony Jones 			   char *buf)
3154edb9068dSPrakash, Sathya {
3155ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3156e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3157edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3158edb9068dSPrakash, Sathya 
3159edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3160edb9068dSPrakash, Sathya }
3161ee959b00STony Jones static DEVICE_ATTR(board_tracer, S_IRUGO,
3162edb9068dSPrakash, Sathya     mptscsih_board_tracer_show, NULL);
3163edb9068dSPrakash, Sathya 
3164edb9068dSPrakash, Sathya static ssize_t
mptscsih_io_delay_show(struct device * dev,struct device_attribute * attr,char * buf)3165ee959b00STony Jones mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3166ee959b00STony Jones 		       char *buf)
3167edb9068dSPrakash, Sathya {
3168ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3169e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3170edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3171edb9068dSPrakash, Sathya 
3172edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3173edb9068dSPrakash, Sathya }
3174ee959b00STony Jones static DEVICE_ATTR(io_delay, S_IRUGO,
3175edb9068dSPrakash, Sathya     mptscsih_io_delay_show, NULL);
3176edb9068dSPrakash, Sathya 
3177edb9068dSPrakash, Sathya static ssize_t
mptscsih_device_delay_show(struct device * dev,struct device_attribute * attr,char * buf)3178ee959b00STony Jones mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3179ee959b00STony Jones 			   char *buf)
3180edb9068dSPrakash, Sathya {
3181ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3182e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3183edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3184edb9068dSPrakash, Sathya 
3185edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3186edb9068dSPrakash, Sathya }
3187ee959b00STony Jones static DEVICE_ATTR(device_delay, S_IRUGO,
3188edb9068dSPrakash, Sathya     mptscsih_device_delay_show, NULL);
3189edb9068dSPrakash, Sathya 
31906757d6b4SPrakash, Sathya static ssize_t
mptscsih_debug_level_show(struct device * dev,struct device_attribute * attr,char * buf)3191ee959b00STony Jones mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3192ee959b00STony Jones 			  char *buf)
31936757d6b4SPrakash, Sathya {
3194ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3195e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
31966757d6b4SPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
31976757d6b4SPrakash, Sathya 
31986757d6b4SPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
31996757d6b4SPrakash, Sathya }
32006757d6b4SPrakash, Sathya static ssize_t
mptscsih_debug_level_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)3201ee959b00STony Jones mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3202ee959b00STony Jones 			   const char *buf, size_t count)
32036757d6b4SPrakash, Sathya {
3204ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3205e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
32066757d6b4SPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
32076757d6b4SPrakash, Sathya 	int val = 0;
32086757d6b4SPrakash, Sathya 
32096757d6b4SPrakash, Sathya 	if (sscanf(buf, "%x", &val) != 1)
32106757d6b4SPrakash, Sathya 		return -EINVAL;
32116757d6b4SPrakash, Sathya 
32126757d6b4SPrakash, Sathya 	ioc->debug_level = val;
32136757d6b4SPrakash, Sathya 	printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
32146757d6b4SPrakash, Sathya 				ioc->name, ioc->debug_level);
32156757d6b4SPrakash, Sathya 	return strlen(buf);
32166757d6b4SPrakash, Sathya }
3217ee959b00STony Jones static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
32186757d6b4SPrakash, Sathya 	mptscsih_debug_level_show, mptscsih_debug_level_store);
32196757d6b4SPrakash, Sathya 
3220*2899836fSBart Van Assche static struct attribute *mptscsih_host_attrs[] = {
3221*2899836fSBart Van Assche 	&dev_attr_version_fw.attr,
3222*2899836fSBart Van Assche 	&dev_attr_version_bios.attr,
3223*2899836fSBart Van Assche 	&dev_attr_version_mpi.attr,
3224*2899836fSBart Van Assche 	&dev_attr_version_product.attr,
3225*2899836fSBart Van Assche 	&dev_attr_version_nvdata_persistent.attr,
3226*2899836fSBart Van Assche 	&dev_attr_version_nvdata_default.attr,
3227*2899836fSBart Van Assche 	&dev_attr_board_name.attr,
3228*2899836fSBart Van Assche 	&dev_attr_board_assembly.attr,
3229*2899836fSBart Van Assche 	&dev_attr_board_tracer.attr,
3230*2899836fSBart Van Assche 	&dev_attr_io_delay.attr,
3231*2899836fSBart Van Assche 	&dev_attr_device_delay.attr,
3232*2899836fSBart Van Assche 	&dev_attr_debug_level.attr,
3233edb9068dSPrakash, Sathya 	NULL,
3234edb9068dSPrakash, Sathya };
323537c60f37SKashyap, Desai 
3236*2899836fSBart Van Assche static const struct attribute_group mptscsih_host_attr_group = {
3237*2899836fSBart Van Assche 	.attrs = mptscsih_host_attrs
3238*2899836fSBart Van Assche };
3239*2899836fSBart Van Assche 
3240*2899836fSBart Van Assche const struct attribute_group *mptscsih_host_attr_groups[] = {
3241*2899836fSBart Van Assche 	&mptscsih_host_attr_group,
3242*2899836fSBart Van Assche 	NULL
3243*2899836fSBart Van Assche };
3244*2899836fSBart Van Assche EXPORT_SYMBOL(mptscsih_host_attr_groups);
3245edb9068dSPrakash, Sathya 
32460d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_remove);
32470d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_shutdown);
32480d0c7974SMoore, Eric Dean  #ifdef CONFIG_PM
32490d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_suspend);
32500d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_resume);
32510d0c7974SMoore, Eric Dean  #endif
3252cac19703SAl Viro EXPORT_SYMBOL(mptscsih_show_info);
32530d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_info);
32540d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_qcmd);
32550d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_slave_destroy);
32560d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_slave_configure);
32570d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_abort);
32580d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_dev_reset);
32590d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_bus_reset);
32600d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_host_reset);
32610d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_bios_param);
32620d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_io_done);
32630d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
32640d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_scandv_complete);
32650d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_event_process);
32660d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_ioc_reset);
32676e3815baSMoore, Eric Dean EXPORT_SYMBOL(mptscsih_change_queue_depth);
32681da177e4SLinus Torvalds 
32690d0c7974SMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3270