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 */
551da177e4SLinus Torvalds #include <linux/interrupt.h>	/* needed for in_interrupt() proto */
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,
981ba9ab2eSKashyap, Desai 		int 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 
121b80ca4f7SFUJITA Tomonori #define SNS_LEN(scp)	SCSI_SENSE_BUFFERSIZE
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1251da177e4SLinus Torvalds /*
1261da177e4SLinus Torvalds  *	mptscsih_getFreeChainBuffer - Function to get a free chain
1271da177e4SLinus Torvalds  *	from the MPT_SCSI_HOST FreeChainQ.
1281da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
1291da177e4SLinus Torvalds  *	@req_idx: Index of the SCSI IO request frame. (output)
1301da177e4SLinus Torvalds  *
1311da177e4SLinus Torvalds  *	return SUCCESS or FAILED
1321da177e4SLinus Torvalds  */
1331da177e4SLinus Torvalds static inline int
1341da177e4SLinus Torvalds mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds 	MPT_FRAME_HDR *chainBuf;
1371da177e4SLinus Torvalds 	unsigned long flags;
1381da177e4SLinus Torvalds 	int rc;
1391da177e4SLinus Torvalds 	int chain_idx;
1401da177e4SLinus Torvalds 
1416757d6b4SPrakash, Sathya 	dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
1421da177e4SLinus Torvalds 	    ioc->name));
1431da177e4SLinus Torvalds 	spin_lock_irqsave(&ioc->FreeQlock, flags);
1441da177e4SLinus Torvalds 	if (!list_empty(&ioc->FreeChainQ)) {
1451da177e4SLinus Torvalds 		int offset;
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 		chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
1481da177e4SLinus Torvalds 				u.frame.linkage.list);
1491da177e4SLinus Torvalds 		list_del(&chainBuf->u.frame.linkage.list);
1501da177e4SLinus Torvalds 		offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
1511da177e4SLinus Torvalds 		chain_idx = offset / ioc->req_sz;
1521da177e4SLinus Torvalds 		rc = SUCCESS;
15329dd3609SEric Moore 		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
15429dd3609SEric Moore 		    "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
155c6678e0cSChristoph Hellwig 		    ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
1561da177e4SLinus Torvalds 	} else {
1571da177e4SLinus Torvalds 		rc = FAILED;
1581da177e4SLinus Torvalds 		chain_idx = MPT_HOST_NO_CHAIN;
15929dd3609SEric Moore 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
1601da177e4SLinus Torvalds 		    ioc->name));
1611da177e4SLinus Torvalds 	}
1621da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 	*retIndex = chain_idx;
1651da177e4SLinus Torvalds 	return rc;
1661da177e4SLinus Torvalds } /* mptscsih_getFreeChainBuffer() */
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1691da177e4SLinus Torvalds /*
1701da177e4SLinus Torvalds  *	mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
1711da177e4SLinus Torvalds  *	SCSIIORequest_t Message Frame.
1721da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
1731da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure
1741da177e4SLinus Torvalds  *	@pReq: Pointer to SCSIIORequest_t structure
1751da177e4SLinus Torvalds  *
1761da177e4SLinus Torvalds  *	Returns ...
1771da177e4SLinus Torvalds  */
1781da177e4SLinus Torvalds static int
1791da177e4SLinus Torvalds mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
1801da177e4SLinus Torvalds 		SCSIIORequest_t *pReq, int req_idx)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds 	char 	*psge;
1831da177e4SLinus Torvalds 	char	*chainSge;
1841da177e4SLinus Torvalds 	struct scatterlist *sg;
1851da177e4SLinus Torvalds 	int	 frm_sz;
1861da177e4SLinus Torvalds 	int	 sges_left, sg_done;
1871da177e4SLinus Torvalds 	int	 chain_idx = MPT_HOST_NO_CHAIN;
1881da177e4SLinus Torvalds 	int	 sgeOffset;
1891da177e4SLinus Torvalds 	int	 numSgeSlots, numSgeThisFrame;
1901da177e4SLinus Torvalds 	u32	 sgflags, sgdir, thisxfer = 0;
1911da177e4SLinus Torvalds 	int	 chain_dma_off = 0;
1921da177e4SLinus Torvalds 	int	 newIndex;
1931da177e4SLinus Torvalds 	int	 ii;
1941da177e4SLinus Torvalds 	dma_addr_t v2;
1951da177e4SLinus Torvalds 	u32	RequestNB;
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds 	sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
1981da177e4SLinus Torvalds 	if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {
1991da177e4SLinus Torvalds 		sgdir = MPT_TRANSFER_HOST_TO_IOC;
2001da177e4SLinus Torvalds 	} else {
2011da177e4SLinus Torvalds 		sgdir = MPT_TRANSFER_IOC_TO_HOST;
2021da177e4SLinus Torvalds 	}
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	psge = (char *) &pReq->SGL;
2051da177e4SLinus Torvalds 	frm_sz = ioc->req_sz;
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	/* Map the data portion, if any.
2081da177e4SLinus Torvalds 	 * sges_left  = 0 if no data transfer.
2091da177e4SLinus Torvalds 	 */
2101928d73fSFUJITA Tomonori 	sges_left = scsi_dma_map(SCpnt);
2111928d73fSFUJITA Tomonori 	if (sges_left < 0)
2121da177e4SLinus Torvalds 		return FAILED;
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 	/* Handle the SG case.
2151da177e4SLinus Torvalds 	 */
2161928d73fSFUJITA Tomonori 	sg = scsi_sglist(SCpnt);
2171da177e4SLinus Torvalds 	sg_done  = 0;
2181da177e4SLinus Torvalds 	sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
2191da177e4SLinus Torvalds 	chainSge = NULL;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	/* Prior to entering this loop - the following must be set
2221da177e4SLinus Torvalds 	 * current MF:  sgeOffset (bytes)
2231da177e4SLinus Torvalds 	 *              chainSge (Null if original MF is not a chain buffer)
2241da177e4SLinus Torvalds 	 *              sg_done (num SGE done for this MF)
2251da177e4SLinus Torvalds 	 */
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds nextSGEset:
22814d0f0b0SKashyap, Desai 	numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
2291da177e4SLinus Torvalds 	numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
2301da177e4SLinus Torvalds 
23114d0f0b0SKashyap, Desai 	sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	/* Get first (num - 1) SG elements
2341da177e4SLinus Torvalds 	 * Skip any SG entries with a length of 0
2351da177e4SLinus Torvalds 	 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
2361da177e4SLinus Torvalds 	 */
2371da177e4SLinus Torvalds 	for (ii=0; ii < (numSgeThisFrame-1); ii++) {
2381da177e4SLinus Torvalds 		thisxfer = sg_dma_len(sg);
2391da177e4SLinus Torvalds 		if (thisxfer == 0) {
2402f187862SKashyap, Desai 			/* Get next SG element from the OS */
2412f187862SKashyap, Desai 			sg = sg_next(sg);
2421da177e4SLinus Torvalds 			sg_done++;
2431da177e4SLinus Torvalds 			continue;
2441da177e4SLinus Torvalds 		}
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 		v2 = sg_dma_address(sg);
24714d0f0b0SKashyap, Desai 		ioc->add_sge(psge, sgflags | thisxfer, v2);
2481da177e4SLinus Torvalds 
2492f187862SKashyap, Desai 		/* Get next SG element from the OS */
2502f187862SKashyap, Desai 		sg = sg_next(sg);
25114d0f0b0SKashyap, Desai 		psge += ioc->SGE_size;
25214d0f0b0SKashyap, Desai 		sgeOffset += ioc->SGE_size;
2531da177e4SLinus Torvalds 		sg_done++;
2541da177e4SLinus Torvalds 	}
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	if (numSgeThisFrame == sges_left) {
2571da177e4SLinus Torvalds 		/* Add last element, end of buffer and end of list flags.
2581da177e4SLinus Torvalds 		 */
2591da177e4SLinus Torvalds 		sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
2601da177e4SLinus Torvalds 				MPT_SGE_FLAGS_END_OF_BUFFER |
2611da177e4SLinus Torvalds 				MPT_SGE_FLAGS_END_OF_LIST;
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 		/* Add last SGE and set termination flags.
2641da177e4SLinus Torvalds 		 * Note: Last SGE may have a length of 0 - which should be ok.
2651da177e4SLinus Torvalds 		 */
2661da177e4SLinus Torvalds 		thisxfer = sg_dma_len(sg);
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 		v2 = sg_dma_address(sg);
26914d0f0b0SKashyap, Desai 		ioc->add_sge(psge, sgflags | thisxfer, v2);
27014d0f0b0SKashyap, Desai 		sgeOffset += ioc->SGE_size;
2711da177e4SLinus Torvalds 		sg_done++;
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 		if (chainSge) {
2741da177e4SLinus Torvalds 			/* The current buffer is a chain buffer,
2751da177e4SLinus Torvalds 			 * but there is not another one.
2761da177e4SLinus Torvalds 			 * Update the chain element
2771da177e4SLinus Torvalds 			 * Offset and Length fields.
2781da177e4SLinus Torvalds 			 */
27914d0f0b0SKashyap, Desai 			ioc->add_chain((char *)chainSge, 0, sgeOffset,
28014d0f0b0SKashyap, Desai 				ioc->ChainBufferDMA + chain_dma_off);
2811da177e4SLinus Torvalds 		} else {
2821da177e4SLinus Torvalds 			/* The current buffer is the original MF
2831da177e4SLinus Torvalds 			 * and there is no Chain buffer.
2841da177e4SLinus Torvalds 			 */
2851da177e4SLinus Torvalds 			pReq->ChainOffset = 0;
2861da177e4SLinus Torvalds 			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;
2876757d6b4SPrakash, Sathya 			dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2881da177e4SLinus Torvalds 			    "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
2891da177e4SLinus Torvalds 			ioc->RequestNB[req_idx] = RequestNB;
2901da177e4SLinus Torvalds 		}
2911da177e4SLinus Torvalds 	} else {
2921da177e4SLinus Torvalds 		/* At least one chain buffer is needed.
2931da177e4SLinus Torvalds 		 * Complete the first MF
2941da177e4SLinus Torvalds 		 *  - last SGE element, set the LastElement bit
2951da177e4SLinus Torvalds 		 *  - set ChainOffset (words) for orig MF
2961da177e4SLinus Torvalds 		 *             (OR finish previous MF chain buffer)
2971da177e4SLinus Torvalds 		 *  - update MFStructPtr ChainIndex
2981da177e4SLinus Torvalds 		 *  - Populate chain element
2991da177e4SLinus Torvalds 		 * Also
3001da177e4SLinus Torvalds 		 * Loop until done.
3011da177e4SLinus Torvalds 		 */
3021da177e4SLinus Torvalds 
3036757d6b4SPrakash, Sathya 		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
3041da177e4SLinus Torvalds 				ioc->name, sg_done));
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds 		/* Set LAST_ELEMENT flag for last non-chain element
3071da177e4SLinus Torvalds 		 * in the buffer. Since psge points at the NEXT
3081da177e4SLinus Torvalds 		 * SGE element, go back one SGE element, update the flags
3091da177e4SLinus Torvalds 		 * and reset the pointer. (Note: sgflags & thisxfer are already
3101da177e4SLinus Torvalds 		 * set properly).
3111da177e4SLinus Torvalds 		 */
3121da177e4SLinus Torvalds 		if (sg_done) {
31314d0f0b0SKashyap, Desai 			u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
3141da177e4SLinus Torvalds 			sgflags = le32_to_cpu(*ptmp);
3151da177e4SLinus Torvalds 			sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
3161da177e4SLinus Torvalds 			*ptmp = cpu_to_le32(sgflags);
3171da177e4SLinus Torvalds 		}
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 		if (chainSge) {
3201da177e4SLinus Torvalds 			/* The current buffer is a chain buffer.
3211da177e4SLinus Torvalds 			 * chainSge points to the previous Chain Element.
3221da177e4SLinus Torvalds 			 * Update its chain element Offset and Length (must
3231da177e4SLinus Torvalds 			 * include chain element size) fields.
3241da177e4SLinus Torvalds 			 * Old chain element is now complete.
3251da177e4SLinus Torvalds 			 */
3261da177e4SLinus Torvalds 			u8 nextChain = (u8) (sgeOffset >> 2);
32714d0f0b0SKashyap, Desai 			sgeOffset += ioc->SGE_size;
32814d0f0b0SKashyap, Desai 			ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
32914d0f0b0SKashyap, Desai 					 ioc->ChainBufferDMA + chain_dma_off);
3301da177e4SLinus Torvalds 		} else {
3311da177e4SLinus Torvalds 			/* The original MF buffer requires a chain buffer -
3321da177e4SLinus Torvalds 			 * set the offset.
3331da177e4SLinus Torvalds 			 * Last element in this MF is a chain element.
3341da177e4SLinus Torvalds 			 */
3351da177e4SLinus Torvalds 			pReq->ChainOffset = (u8) (sgeOffset >> 2);
3361da177e4SLinus Torvalds 			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;
3376757d6b4SPrakash, Sathya 			dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
3381da177e4SLinus Torvalds 			ioc->RequestNB[req_idx] = RequestNB;
3391da177e4SLinus Torvalds 		}
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 		sges_left -= sg_done;
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds 		/* NOTE: psge points to the beginning of the chain element
3451da177e4SLinus Torvalds 		 * in current buffer. Get a chain buffer.
3461da177e4SLinus Torvalds 		 */
347c6678e0cSChristoph Hellwig 		if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
3486757d6b4SPrakash, Sathya 			dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
349c6678e0cSChristoph Hellwig 			    "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
3501da177e4SLinus Torvalds  			    ioc->name, pReq->CDB[0], SCpnt));
3511da177e4SLinus Torvalds 			return FAILED;
352c6678e0cSChristoph Hellwig 		}
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 		/* Update the tracking arrays.
3551da177e4SLinus Torvalds 		 * If chainSge == NULL, update ReqToChain, else ChainToChain
3561da177e4SLinus Torvalds 		 */
3571da177e4SLinus Torvalds 		if (chainSge) {
3581da177e4SLinus Torvalds 			ioc->ChainToChain[chain_idx] = newIndex;
3591da177e4SLinus Torvalds 		} else {
3601da177e4SLinus Torvalds 			ioc->ReqToChain[req_idx] = newIndex;
3611da177e4SLinus Torvalds 		}
3621da177e4SLinus Torvalds 		chain_idx = newIndex;
3631da177e4SLinus Torvalds 		chain_dma_off = ioc->req_sz * chain_idx;
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 		/* Populate the chainSGE for the current buffer.
3661da177e4SLinus Torvalds 		 * - Set chain buffer pointer to psge and fill
3671da177e4SLinus Torvalds 		 *   out the Address and Flags fields.
3681da177e4SLinus Torvalds 		 */
3691da177e4SLinus Torvalds 		chainSge = (char *) psge;
37029dd3609SEric Moore 		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Current buff @ %p (index 0x%x)",
37129dd3609SEric Moore 		    ioc->name, psge, req_idx));
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 		/* Start the SGE for the next buffer
3741da177e4SLinus Torvalds 		 */
3751da177e4SLinus Torvalds 		psge = (char *) (ioc->ChainBuffer + chain_dma_off);
3761da177e4SLinus Torvalds 		sgeOffset = 0;
3771da177e4SLinus Torvalds 		sg_done = 0;
3781da177e4SLinus Torvalds 
37929dd3609SEric Moore 		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Chain buff @ %p (index 0x%x)\n",
38029dd3609SEric Moore 		    ioc->name, psge, chain_idx));
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 		/* Start the SGE for the next buffer
3831da177e4SLinus Torvalds 		 */
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 		goto nextSGEset;
3861da177e4SLinus Torvalds 	}
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	return SUCCESS;
3891da177e4SLinus Torvalds } /* mptscsih_AddSGE() */
3901da177e4SLinus Torvalds 
391786899b0SEric Moore static void
392786899b0SEric Moore mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
393786899b0SEric Moore     U32 SlotStatus)
394786899b0SEric Moore {
395786899b0SEric Moore 	MPT_FRAME_HDR *mf;
396786899b0SEric Moore 	SEPRequest_t 	 *SEPMsg;
397786899b0SEric Moore 
398cc78d30aSEric Moore 	if (ioc->bus_type != SAS)
399cc78d30aSEric Moore 		return;
400cc78d30aSEric Moore 
401cc78d30aSEric Moore 	/* Not supported for hidden raid components
402cc78d30aSEric Moore 	 */
403cc78d30aSEric Moore 	if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
404786899b0SEric Moore 		return;
405786899b0SEric Moore 
406786899b0SEric Moore 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
4076757d6b4SPrakash, Sathya 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
408cadbd4a5SHarvey Harrison 		    ioc->name,__func__));
409786899b0SEric Moore 		return;
410786899b0SEric Moore 	}
411786899b0SEric Moore 
412786899b0SEric Moore 	SEPMsg = (SEPRequest_t *)mf;
413786899b0SEric Moore 	SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
414793955f5SEric Moore 	SEPMsg->Bus = vtarget->channel;
415793955f5SEric Moore 	SEPMsg->TargetID = vtarget->id;
416786899b0SEric Moore 	SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
417786899b0SEric Moore 	SEPMsg->SlotStatus = SlotStatus;
4186757d6b4SPrakash, Sathya 	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
419793955f5SEric Moore 	    "Sending SEP cmd=%x channel=%d id=%d\n",
420793955f5SEric Moore 	    ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
421786899b0SEric Moore 	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
422786899b0SEric Moore }
423786899b0SEric Moore 
4246757d6b4SPrakash, Sathya #ifdef CONFIG_FUSION_LOGGING
425c6c727a1SEric Moore /**
4266757d6b4SPrakash, Sathya  *	mptscsih_info_scsiio - debug print info on reply frame
427c6c727a1SEric Moore  *	@ioc: Pointer to MPT_ADAPTER structure
428c6c727a1SEric Moore  *	@sc: original scsi cmnd pointer
4296757d6b4SPrakash, Sathya  *	@pScsiReply: Pointer to MPT reply frame
4306757d6b4SPrakash, Sathya  *
4316757d6b4SPrakash, Sathya  *	MPT_DEBUG_REPLY needs to be enabled to obtain this info
432c6c727a1SEric Moore  *
433c6c727a1SEric Moore  *	Refer to lsi/mpi.h.
434c6c727a1SEric Moore  **/
435c6c727a1SEric Moore static void
4366757d6b4SPrakash, Sathya mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
437c6c727a1SEric Moore {
438c6c727a1SEric Moore 	char	*desc = NULL;
4396757d6b4SPrakash, Sathya 	char	*desc1 = NULL;
4406757d6b4SPrakash, Sathya 	u16	ioc_status;
4416757d6b4SPrakash, Sathya 	u8	skey, asc, ascq;
4426757d6b4SPrakash, Sathya 
4436757d6b4SPrakash, Sathya 	ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
444c6c727a1SEric Moore 
445c6c727a1SEric Moore 	switch (ioc_status) {
446c6c727a1SEric Moore 
4476757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SUCCESS:
4486757d6b4SPrakash, Sathya 		desc = "success";
449c6c727a1SEric Moore 		break;
4506757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_INVALID_BUS:
4516757d6b4SPrakash, Sathya 		desc = "invalid bus";
452c6c727a1SEric Moore 		break;
4536757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
4546757d6b4SPrakash, Sathya 		desc = "invalid target_id";
455c6c727a1SEric Moore 		break;
4566757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
4576757d6b4SPrakash, Sathya 		desc = "device not there";
458c6c727a1SEric Moore 		break;
4596757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
4606757d6b4SPrakash, Sathya 		desc = "data overrun";
461c6c727a1SEric Moore 		break;
4626757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
4636757d6b4SPrakash, Sathya 		desc = "data underrun";
464c6c727a1SEric Moore 		break;
4656757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
4666757d6b4SPrakash, Sathya 		desc = "I/O data error";
467c6c727a1SEric Moore 		break;
4686757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
4696757d6b4SPrakash, Sathya 		desc = "protocol error";
470c6c727a1SEric Moore 		break;
4716757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
4726757d6b4SPrakash, Sathya 		desc = "task terminated";
473c6c727a1SEric Moore 		break;
4746757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
4756757d6b4SPrakash, Sathya 		desc = "residual mismatch";
476c6c727a1SEric Moore 		break;
4776757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
4786757d6b4SPrakash, Sathya 		desc = "task management failed";
4796757d6b4SPrakash, Sathya 		break;
4806757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
4816757d6b4SPrakash, Sathya 		desc = "IOC terminated";
4826757d6b4SPrakash, Sathya 		break;
4836757d6b4SPrakash, Sathya 	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
4846757d6b4SPrakash, Sathya 		desc = "ext terminated";
4856757d6b4SPrakash, Sathya 		break;
4866757d6b4SPrakash, Sathya 	default:
4876757d6b4SPrakash, Sathya 		desc = "";
488c6c727a1SEric Moore 		break;
489c6c727a1SEric Moore 	}
490c6c727a1SEric Moore 
4916757d6b4SPrakash, Sathya 	switch (pScsiReply->SCSIStatus)
4926757d6b4SPrakash, Sathya 	{
493c6c727a1SEric Moore 
4946757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_SUCCESS:
4956757d6b4SPrakash, Sathya 		desc1 = "success";
4966757d6b4SPrakash, Sathya 		break;
4976757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_CHECK_CONDITION:
4986757d6b4SPrakash, Sathya 		desc1 = "check condition";
4996757d6b4SPrakash, Sathya 		break;
5006757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_CONDITION_MET:
5016757d6b4SPrakash, Sathya 		desc1 = "condition met";
5026757d6b4SPrakash, Sathya 		break;
5036757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_BUSY:
5046757d6b4SPrakash, Sathya 		desc1 = "busy";
5056757d6b4SPrakash, Sathya 		break;
5066757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_INTERMEDIATE:
5076757d6b4SPrakash, Sathya 		desc1 = "intermediate";
5086757d6b4SPrakash, Sathya 		break;
5096757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
5106757d6b4SPrakash, Sathya 		desc1 = "intermediate condmet";
5116757d6b4SPrakash, Sathya 		break;
5126757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
5136757d6b4SPrakash, Sathya 		desc1 = "reservation conflict";
5146757d6b4SPrakash, Sathya 		break;
5156757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_COMMAND_TERMINATED:
5166757d6b4SPrakash, Sathya 		desc1 = "command terminated";
5176757d6b4SPrakash, Sathya 		break;
5186757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_TASK_SET_FULL:
5196757d6b4SPrakash, Sathya 		desc1 = "task set full";
5206757d6b4SPrakash, Sathya 		break;
5216757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_ACA_ACTIVE:
5226757d6b4SPrakash, Sathya 		desc1 = "aca active";
5236757d6b4SPrakash, Sathya 		break;
5246757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
5256757d6b4SPrakash, Sathya 		desc1 = "fcpext device logged out";
5266757d6b4SPrakash, Sathya 		break;
5276757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
5286757d6b4SPrakash, Sathya 		desc1 = "fcpext no link";
5296757d6b4SPrakash, Sathya 		break;
5306757d6b4SPrakash, Sathya 	case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
5316757d6b4SPrakash, Sathya 		desc1 = "fcpext unassigned";
5326757d6b4SPrakash, Sathya 		break;
5336757d6b4SPrakash, Sathya 	default:
5346757d6b4SPrakash, Sathya 		desc1 = "";
5356757d6b4SPrakash, Sathya 		break;
5366757d6b4SPrakash, Sathya 	}
537c6c727a1SEric Moore 
5386757d6b4SPrakash, Sathya 	scsi_print_command(sc);
5392f187862SKashyap, Desai 	printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n",
5402f187862SKashyap, Desai 	    ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
54129dd3609SEric Moore 	printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
54229dd3609SEric Moore 	    "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
54329dd3609SEric Moore 	    scsi_get_resid(sc));
54429dd3609SEric Moore 	printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
54529dd3609SEric Moore 	    "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
5466757d6b4SPrakash, Sathya 	    le32_to_cpu(pScsiReply->TransferCount), sc->result);
5472f187862SKashyap, Desai 
54829dd3609SEric Moore 	printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
5496757d6b4SPrakash, Sathya 	    "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
55029dd3609SEric Moore 	    ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
5516757d6b4SPrakash, Sathya 	    pScsiReply->SCSIState);
5526757d6b4SPrakash, Sathya 
5536757d6b4SPrakash, Sathya 	if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
5546757d6b4SPrakash, Sathya 		skey = sc->sense_buffer[2] & 0x0F;
5556757d6b4SPrakash, Sathya 		asc = sc->sense_buffer[12];
5566757d6b4SPrakash, Sathya 		ascq = sc->sense_buffer[13];
5576757d6b4SPrakash, Sathya 
55829dd3609SEric Moore 		printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
55929dd3609SEric Moore 		    "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
5606757d6b4SPrakash, Sathya 	}
5616757d6b4SPrakash, Sathya 
5626757d6b4SPrakash, Sathya 	/*
5636757d6b4SPrakash, Sathya 	 *  Look for + dump FCP ResponseInfo[]!
5646757d6b4SPrakash, Sathya 	 */
5656757d6b4SPrakash, Sathya 	if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
5666757d6b4SPrakash, Sathya 	    pScsiReply->ResponseInfo)
56729dd3609SEric Moore 		printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
56829dd3609SEric Moore 		    ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
569c6c727a1SEric Moore }
570c6c727a1SEric Moore #endif
571c6c727a1SEric Moore 
5721da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5731da177e4SLinus Torvalds /*
5741da177e4SLinus Torvalds  *	mptscsih_io_done - Main SCSI IO callback routine registered to
5751da177e4SLinus Torvalds  *	Fusion MPT (base) driver
5761da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
5771da177e4SLinus Torvalds  *	@mf: Pointer to original MPT request frame
5781da177e4SLinus Torvalds  *	@r: Pointer to MPT reply frame (NULL if TurboReply)
5791da177e4SLinus Torvalds  *
5801da177e4SLinus Torvalds  *	This routine is called from mpt.c::mpt_interrupt() at the completion
5811da177e4SLinus Torvalds  *	of any SCSI IO request.
5821da177e4SLinus Torvalds  *	This routine is registered with the Fusion MPT (base) driver at driver
5831da177e4SLinus Torvalds  *	load/init time via the mpt_register() API call.
5841da177e4SLinus Torvalds  *
5851da177e4SLinus Torvalds  *	Returns 1 indicating alloc'd request frame ptr should be freed.
5861da177e4SLinus Torvalds  */
5870d0c7974SMoore, Eric Dean  int
5881da177e4SLinus Torvalds mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
5891da177e4SLinus Torvalds {
5901da177e4SLinus Torvalds 	struct scsi_cmnd	*sc;
5911da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
5921da177e4SLinus Torvalds 	SCSIIORequest_t	*pScsiReq;
5931da177e4SLinus Torvalds 	SCSIIOReply_t	*pScsiReply;
5942254c86dSMoore, Eric 	u16		 req_idx, req_idx_MR;
595a69de507SEric Moore 	VirtDevice	 *vdevice;
596786899b0SEric Moore 	VirtTarget	 *vtarget;
5971da177e4SLinus Torvalds 
598e7eae9f6SEric Moore 	hd = shost_priv(ioc->sh);
5991da177e4SLinus Torvalds 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
6002254c86dSMoore, Eric 	req_idx_MR = (mr != NULL) ?
6012254c86dSMoore, Eric 	    le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
6022f187862SKashyap, Desai 
6032f187862SKashyap, Desai 	/* Special case, where already freed message frame is received from
6042f187862SKashyap, Desai 	 * Firmware. It happens with Resetting IOC.
6052f187862SKashyap, Desai 	 * Return immediately. Do not care
6062f187862SKashyap, Desai 	 */
6072254c86dSMoore, Eric 	if ((req_idx != req_idx_MR) ||
6082f187862SKashyap, Desai 	    (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))
6092254c86dSMoore, Eric 		return 0;
6102254c86dSMoore, Eric 
611e8206381SEric Moore 	sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
6121da177e4SLinus Torvalds 	if (sc == NULL) {
6131da177e4SLinus Torvalds 		MPIHeader_t *hdr = (MPIHeader_t *)mf;
6141da177e4SLinus Torvalds 
6151da177e4SLinus Torvalds 		/* Remark: writeSDP1 will use the ScsiDoneCtx
6161da177e4SLinus Torvalds 		 * If a SCSI I/O cmd, device disabled by OS and
6171da177e4SLinus Torvalds 		 * completion done. Cannot touch sc struct. Just free mem.
6181da177e4SLinus Torvalds 		 */
6191da177e4SLinus Torvalds 		if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
6201da177e4SLinus Torvalds 			printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
6211da177e4SLinus Torvalds 			ioc->name);
6221da177e4SLinus Torvalds 
6231da177e4SLinus Torvalds 		mptscsih_freeChainBuffers(ioc, req_idx);
6241da177e4SLinus Torvalds 		return 1;
6251da177e4SLinus Torvalds 	}
6261da177e4SLinus Torvalds 
6273dc0b03fSEric Moore 	if ((unsigned char *)mf != sc->host_scribble) {
6283dc0b03fSEric Moore 		mptscsih_freeChainBuffers(ioc, req_idx);
6293dc0b03fSEric Moore 		return 1;
6303dc0b03fSEric Moore 	}
6313dc0b03fSEric Moore 
632fea98403SKashyap, Desai 	if (ioc->bus_type == SAS) {
633fea98403SKashyap, Desai 		VirtDevice *vdevice = sc->device->hostdata;
634fea98403SKashyap, Desai 
635fea98403SKashyap, Desai 		if (!vdevice || !vdevice->vtarget ||
636fea98403SKashyap, Desai 		    vdevice->vtarget->deleted) {
637fea98403SKashyap, Desai 			sc->result = DID_NO_CONNECT << 16;
638fea98403SKashyap, Desai 			goto out;
639fea98403SKashyap, Desai 		}
640fea98403SKashyap, Desai 	}
641fea98403SKashyap, Desai 
6423dc0b03fSEric Moore 	sc->host_scribble = NULL;
6431da177e4SLinus Torvalds 	sc->result = DID_OK << 16;		/* Set default reply as OK */
6441da177e4SLinus Torvalds 	pScsiReq = (SCSIIORequest_t *) mf;
6451da177e4SLinus Torvalds 	pScsiReply = (SCSIIOReply_t *) mr;
6461da177e4SLinus Torvalds 
647c6678e0cSChristoph Hellwig 	if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
6486757d6b4SPrakash, Sathya 		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
649c6678e0cSChristoph Hellwig 			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
650c6678e0cSChristoph Hellwig 			ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
651c6678e0cSChristoph Hellwig 	}else{
6526757d6b4SPrakash, Sathya 		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
653c6678e0cSChristoph Hellwig 			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
654c6678e0cSChristoph Hellwig 			ioc->name, mf, mr, sc, req_idx));
655c6678e0cSChristoph Hellwig 	}
656c6678e0cSChristoph Hellwig 
6571da177e4SLinus Torvalds 	if (pScsiReply == NULL) {
6581da177e4SLinus Torvalds 		/* special context reply handling */
6591da177e4SLinus Torvalds 		;
6601da177e4SLinus Torvalds 	} else {
6611da177e4SLinus Torvalds 		u32	 xfer_cnt;
6621da177e4SLinus Torvalds 		u16	 status;
6631da177e4SLinus Torvalds 		u8	 scsi_state, scsi_status;
664c6c727a1SEric Moore 		u32	 log_info;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6671da177e4SLinus Torvalds 		scsi_state = pScsiReply->SCSIState;
6681da177e4SLinus Torvalds 		scsi_status = pScsiReply->SCSIStatus;
6691da177e4SLinus Torvalds 		xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
6701928d73fSFUJITA Tomonori 		scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
671c6c727a1SEric Moore 		log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
6721da177e4SLinus Torvalds 
673466544d8SMoore, Eric Dean 		/*
674466544d8SMoore, Eric Dean 		 *  if we get a data underrun indication, yet no data was
675466544d8SMoore, Eric Dean 		 *  transferred and the SCSI status indicates that the
676466544d8SMoore, Eric Dean 		 *  command was never started, change the data underrun
677466544d8SMoore, Eric Dean 		 *  to success
678466544d8SMoore, Eric Dean 		 */
679466544d8SMoore, Eric Dean 		if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
680466544d8SMoore, Eric Dean 		    (scsi_status == MPI_SCSI_STATUS_BUSY ||
681466544d8SMoore, Eric Dean 		     scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
682466544d8SMoore, Eric Dean 		     scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
683466544d8SMoore, Eric Dean 			status = MPI_IOCSTATUS_SUCCESS;
684466544d8SMoore, Eric Dean 		}
685466544d8SMoore, Eric Dean 
6861da177e4SLinus Torvalds 		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
6870d0c7974SMoore, Eric Dean  			mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds 		/*
6901da177e4SLinus Torvalds 		 *  Look for + dump FCP ResponseInfo[]!
6911da177e4SLinus Torvalds 		 */
692466544d8SMoore, Eric Dean 		if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
693466544d8SMoore, Eric Dean 		    pScsiReply->ResponseInfo) {
69429dd3609SEric Moore 			printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
69529dd3609SEric Moore 			"FCP_ResponseInfo=%08xh\n", ioc->name,
696c6c727a1SEric Moore 			sc->device->host->host_no, sc->device->channel,
697c6c727a1SEric Moore 			sc->device->id, sc->device->lun,
6981da177e4SLinus Torvalds 			le32_to_cpu(pScsiReply->ResponseInfo));
6991da177e4SLinus Torvalds 		}
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 		switch(status) {
7021da177e4SLinus Torvalds 		case MPI_IOCSTATUS_BUSY:			/* 0x0002 */
703d23321b4SKashyap, Desai 		case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:	/* 0x0006 */
7041da177e4SLinus Torvalds 			/* CHECKME!
7051da177e4SLinus Torvalds 			 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
7061da177e4SLinus Torvalds 			 * But not: DID_BUS_BUSY lest one risk
7071da177e4SLinus Torvalds 			 * killing interrupt handler:-(
7081da177e4SLinus Torvalds 			 */
7091da177e4SLinus Torvalds 			sc->result = SAM_STAT_BUSY;
7101da177e4SLinus Torvalds 			break;
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_INVALID_BUS:		/* 0x0041 */
7131da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:	/* 0x0042 */
7141da177e4SLinus Torvalds 			sc->result = DID_BAD_TARGET << 16;
7151da177e4SLinus Torvalds 			break;
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
7181da177e4SLinus Torvalds 			/* Spoof to SCSI Selection Timeout! */
71965207fedSMoore, Eric 			if (ioc->bus_type != FC)
7201da177e4SLinus Torvalds 				sc->result = DID_NO_CONNECT << 16;
72165207fedSMoore, Eric 			/* else fibre, just stall until rescan event */
72265207fedSMoore, Eric 			else
72365207fedSMoore, Eric 				sc->result = DID_REQUEUE << 16;
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds 			if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
7261da177e4SLinus Torvalds 				hd->sel_timeout[pScsiReq->TargetID]++;
727786899b0SEric Moore 
728a69de507SEric Moore 			vdevice = sc->device->hostdata;
729a69de507SEric Moore 			if (!vdevice)
730786899b0SEric Moore 				break;
731a69de507SEric Moore 			vtarget = vdevice->vtarget;
732786899b0SEric Moore 			if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
733786899b0SEric Moore 				mptscsih_issue_sep_command(ioc, vtarget,
734786899b0SEric Moore 				    MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
735786899b0SEric Moore 				vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
736786899b0SEric Moore 			}
7371da177e4SLinus Torvalds 			break;
7381da177e4SLinus Torvalds 
7391da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
740bf451522SEric Moore 			if ( ioc->bus_type == SAS ) {
741bf451522SEric Moore 				u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
742bf451522SEric Moore 				if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
743c6c727a1SEric Moore 					if ((log_info & SAS_LOGINFO_MASK)
744c6c727a1SEric Moore 					    == SAS_LOGINFO_NEXUS_LOSS) {
745bf451522SEric Moore 						sc->result = (DID_BUS_BUSY << 16);
746bf451522SEric Moore 						break;
747bf451522SEric Moore 					}
748bf451522SEric Moore 				}
74986dd4242SEric Moore 			} else if (ioc->bus_type == FC) {
75086dd4242SEric Moore 				/*
75186dd4242SEric Moore 				 * The FC IOC may kill a request for variety of
75286dd4242SEric Moore 				 * reasons, some of which may be recovered by a
75386dd4242SEric Moore 				 * retry, some which are unlikely to be
75486dd4242SEric Moore 				 * recovered. Return DID_ERROR instead of
75586dd4242SEric Moore 				 * DID_RESET to permit retry of the command,
75686dd4242SEric Moore 				 * just not an infinite number of them
75786dd4242SEric Moore 				 */
75886dd4242SEric Moore 				sc->result = DID_ERROR << 16;
75986dd4242SEric Moore 				break;
760bf451522SEric Moore 			}
761bf451522SEric Moore 
762bf451522SEric Moore 			/*
763bf451522SEric Moore 			 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
764bf451522SEric Moore 			 */
765bf451522SEric Moore 
766bf451522SEric Moore 		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
7671da177e4SLinus Torvalds 			/* Linux handles an unsolicited DID_RESET better
7681da177e4SLinus Torvalds 			 * than an unsolicited DID_ABORT.
7691da177e4SLinus Torvalds 			 */
7701da177e4SLinus Torvalds 			sc->result = DID_RESET << 16;
7711da177e4SLinus Torvalds 
7722f187862SKashyap, Desai 		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
7732f187862SKashyap, Desai 			if (ioc->bus_type == FC)
7742f187862SKashyap, Desai 				sc->result = DID_ERROR << 16;
7752f187862SKashyap, Desai 			else
7762f187862SKashyap, Desai 				sc->result = DID_RESET << 16;
7771da177e4SLinus Torvalds 			break;
7781da177e4SLinus Torvalds 
7791da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
7801928d73fSFUJITA Tomonori 			scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
781466544d8SMoore, Eric Dean 			if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
7821da177e4SLinus Torvalds 				sc->result=DID_SOFT_ERROR << 16;
783466544d8SMoore, Eric Dean 			else /* Sufficient data transfer occurred */
784466544d8SMoore, Eric Dean 				sc->result = (DID_OK << 16) | scsi_status;
78529dd3609SEric Moore 			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
786c6c727a1SEric Moore 			    "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
78729dd3609SEric Moore 			    ioc->name, sc->result, sc->device->channel, sc->device->id));
7881da177e4SLinus Torvalds 			break;
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
7911da177e4SLinus Torvalds 			/*
7921da177e4SLinus Torvalds 			 *  Do upfront check for valid SenseData and give it
7931da177e4SLinus Torvalds 			 *  precedence!
7941da177e4SLinus Torvalds 			 */
7951da177e4SLinus Torvalds 			sc->result = (DID_OK << 16) | scsi_status;
7969b53b392SKashyap, Desai 			if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
7979b53b392SKashyap, Desai 
7989b53b392SKashyap, Desai 				/*
7999b53b392SKashyap, Desai 				 * For an Errata on LSI53C1030
8009b53b392SKashyap, Desai 				 * When the length of request data
8019b53b392SKashyap, Desai 				 * and transfer data are different
8029b53b392SKashyap, Desai 				 * with result of command (READ or VERIFY),
8039b53b392SKashyap, Desai 				 * DID_SOFT_ERROR is set.
8041da177e4SLinus Torvalds 				 */
8059b53b392SKashyap, Desai 				if (ioc->bus_type == SPI) {
8069b53b392SKashyap, Desai 					if (pScsiReq->CDB[0] == READ_6  ||
8079b53b392SKashyap, Desai 					    pScsiReq->CDB[0] == READ_10 ||
8089b53b392SKashyap, Desai 					    pScsiReq->CDB[0] == READ_12 ||
8099b53b392SKashyap, Desai 					    pScsiReq->CDB[0] == READ_16 ||
8109b53b392SKashyap, Desai 					    pScsiReq->CDB[0] == VERIFY  ||
8119b53b392SKashyap, Desai 					    pScsiReq->CDB[0] == VERIFY_16) {
8129b53b392SKashyap, Desai 						if (scsi_bufflen(sc) !=
8139b53b392SKashyap, Desai 							xfer_cnt) {
8149b53b392SKashyap, Desai 							sc->result =
8159b53b392SKashyap, Desai 							DID_SOFT_ERROR << 16;
8169b53b392SKashyap, Desai 						    printk(KERN_WARNING "Errata"
8179b53b392SKashyap, Desai 						    "on LSI53C1030 occurred."
8189b53b392SKashyap, Desai 						    "sc->req_bufflen=0x%02x,"
8199b53b392SKashyap, Desai 						    "xfer_cnt=0x%02x\n",
8209b53b392SKashyap, Desai 						    scsi_bufflen(sc),
8219b53b392SKashyap, Desai 						    xfer_cnt);
8229b53b392SKashyap, Desai 						}
8239b53b392SKashyap, Desai 					}
8249b53b392SKashyap, Desai 				}
8259b53b392SKashyap, Desai 
8261da177e4SLinus Torvalds 				if (xfer_cnt < sc->underflow) {
827466544d8SMoore, Eric Dean 					if (scsi_status == SAM_STAT_BUSY)
828466544d8SMoore, Eric Dean 						sc->result = SAM_STAT_BUSY;
829466544d8SMoore, Eric Dean 					else
8301da177e4SLinus Torvalds 						sc->result = DID_SOFT_ERROR << 16;
8311da177e4SLinus Torvalds 				}
8321da177e4SLinus Torvalds 				if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
8331da177e4SLinus Torvalds 					/* What to do?
8341da177e4SLinus Torvalds 				 	*/
8351da177e4SLinus Torvalds 					sc->result = DID_SOFT_ERROR << 16;
8361da177e4SLinus Torvalds 				}
8371da177e4SLinus Torvalds 				else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
8381da177e4SLinus Torvalds 					/*  Not real sure here either...  */
8391da177e4SLinus Torvalds 					sc->result = DID_RESET << 16;
8401da177e4SLinus Torvalds 				}
8411da177e4SLinus Torvalds 			}
8421da177e4SLinus Torvalds 
8436757d6b4SPrakash, Sathya 
84429dd3609SEric Moore 			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
84529dd3609SEric Moore 			    "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
84629dd3609SEric Moore 			    ioc->name, sc->underflow));
84729dd3609SEric Moore 			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
84829dd3609SEric Moore 			    "  ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
8496757d6b4SPrakash, Sathya 
8501da177e4SLinus Torvalds 			/* Report Queue Full
8511da177e4SLinus Torvalds 			 */
8521da177e4SLinus Torvalds 			if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
8531da177e4SLinus Torvalds 				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
8541da177e4SLinus Torvalds 
8551da177e4SLinus Torvalds 			break;
8561da177e4SLinus Torvalds 
8577e55147fSMoore, Eric 		case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:		/* 0x0044 */
8581928d73fSFUJITA Tomonori 			scsi_set_resid(sc, 0);
8591da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
8601da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
8611da177e4SLinus Torvalds 			sc->result = (DID_OK << 16) | scsi_status;
8621da177e4SLinus Torvalds 			if (scsi_state == 0) {
8631da177e4SLinus Torvalds 				;
8649b53b392SKashyap, Desai 			} else if (scsi_state &
8659b53b392SKashyap, Desai 			    MPI_SCSI_STATE_AUTOSENSE_VALID) {
8669b53b392SKashyap, Desai 
8679b53b392SKashyap, Desai 				/*
8689b53b392SKashyap, Desai 				 * For potential trouble on LSI53C1030.
8699b53b392SKashyap, Desai 				 * (date:2007.xx.)
8709b53b392SKashyap, Desai 				 * It is checked whether the length of
8719b53b392SKashyap, Desai 				 * request data is equal to
8729b53b392SKashyap, Desai 				 * the length of transfer and residual.
8739b53b392SKashyap, Desai 				 * MEDIUM_ERROR is set by incorrect data.
8749b53b392SKashyap, Desai 				 */
8759b53b392SKashyap, Desai 				if ((ioc->bus_type == SPI) &&
8769b53b392SKashyap, Desai 					(sc->sense_buffer[2] & 0x20)) {
8779b53b392SKashyap, Desai 					u32	 difftransfer;
8789b53b392SKashyap, Desai 					difftransfer =
8799b53b392SKashyap, Desai 					sc->sense_buffer[3] << 24 |
8809b53b392SKashyap, Desai 					sc->sense_buffer[4] << 16 |
8819b53b392SKashyap, Desai 					sc->sense_buffer[5] << 8 |
8829b53b392SKashyap, Desai 					sc->sense_buffer[6];
8839b53b392SKashyap, Desai 					if (((sc->sense_buffer[3] & 0x80) ==
8849b53b392SKashyap, Desai 						0x80) && (scsi_bufflen(sc)
8859b53b392SKashyap, Desai 						!= xfer_cnt)) {
8869b53b392SKashyap, Desai 						sc->sense_buffer[2] =
8879b53b392SKashyap, Desai 						    MEDIUM_ERROR;
8889b53b392SKashyap, Desai 						sc->sense_buffer[12] = 0xff;
8899b53b392SKashyap, Desai 						sc->sense_buffer[13] = 0xff;
8909b53b392SKashyap, Desai 						printk(KERN_WARNING"Errata"
8919b53b392SKashyap, Desai 						"on LSI53C1030 occurred."
8929b53b392SKashyap, Desai 						"sc->req_bufflen=0x%02x,"
8939b53b392SKashyap, Desai 						"xfer_cnt=0x%02x\n" ,
8949b53b392SKashyap, Desai 						scsi_bufflen(sc),
8959b53b392SKashyap, Desai 						xfer_cnt);
8969b53b392SKashyap, Desai 					}
8979b53b392SKashyap, Desai 					if (((sc->sense_buffer[3] & 0x80)
8989b53b392SKashyap, Desai 						!= 0x80) &&
8999b53b392SKashyap, Desai 						(scsi_bufflen(sc) !=
9009b53b392SKashyap, Desai 						xfer_cnt + difftransfer)) {
9019b53b392SKashyap, Desai 						sc->sense_buffer[2] =
9029b53b392SKashyap, Desai 							MEDIUM_ERROR;
9039b53b392SKashyap, Desai 						sc->sense_buffer[12] = 0xff;
9049b53b392SKashyap, Desai 						sc->sense_buffer[13] = 0xff;
9059b53b392SKashyap, Desai 						printk(KERN_WARNING
9069b53b392SKashyap, Desai 						"Errata on LSI53C1030 occurred"
9079b53b392SKashyap, Desai 						"sc->req_bufflen=0x%02x,"
9089b53b392SKashyap, Desai 						" xfer_cnt=0x%02x,"
9099b53b392SKashyap, Desai 						"difftransfer=0x%02x\n",
9109b53b392SKashyap, Desai 						scsi_bufflen(sc),
9119b53b392SKashyap, Desai 						xfer_cnt,
9129b53b392SKashyap, Desai 						difftransfer);
9139b53b392SKashyap, Desai 					}
9149b53b392SKashyap, Desai 				}
9159b53b392SKashyap, Desai 
9161da177e4SLinus Torvalds 				/*
9171da177e4SLinus Torvalds 				 * If running against circa 200003dd 909 MPT f/w,
9181da177e4SLinus Torvalds 				 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
9191da177e4SLinus Torvalds 				 * (QUEUE_FULL) returned from device! --> get 0x0000?128
9201da177e4SLinus Torvalds 				 * and with SenseBytes set to 0.
9211da177e4SLinus Torvalds 				 */
9221da177e4SLinus Torvalds 				if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
9231da177e4SLinus Torvalds 					mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds 			}
9261da177e4SLinus Torvalds 			else if (scsi_state &
9271da177e4SLinus Torvalds 			         (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
9281da177e4SLinus Torvalds 			   ) {
9291da177e4SLinus Torvalds 				/*
9301da177e4SLinus Torvalds 				 * What to do?
9311da177e4SLinus Torvalds 				 */
9321da177e4SLinus Torvalds 				sc->result = DID_SOFT_ERROR << 16;
9331da177e4SLinus Torvalds 			}
9341da177e4SLinus Torvalds 			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
9351da177e4SLinus Torvalds 				/*  Not real sure here either...  */
9361da177e4SLinus Torvalds 				sc->result = DID_RESET << 16;
9371da177e4SLinus Torvalds 			}
9381da177e4SLinus Torvalds 			else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
9391da177e4SLinus Torvalds 				/* Device Inq. data indicates that it supports
9401da177e4SLinus Torvalds 				 * QTags, but rejects QTag messages.
9411da177e4SLinus Torvalds 				 * This command completed OK.
9421da177e4SLinus Torvalds 				 *
9431da177e4SLinus Torvalds 				 * Not real sure here either so do nothing...  */
9441da177e4SLinus Torvalds 			}
9451da177e4SLinus Torvalds 
9461da177e4SLinus Torvalds 			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
9471da177e4SLinus Torvalds 				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
9481da177e4SLinus Torvalds 
9491da177e4SLinus Torvalds 			/* Add handling of:
9501da177e4SLinus Torvalds 			 * Reservation Conflict, Busy,
9511da177e4SLinus Torvalds 			 * Command Terminated, CHECK
9521da177e4SLinus Torvalds 			 */
9531da177e4SLinus Torvalds 			break;
9541da177e4SLinus Torvalds 
9551da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
9561da177e4SLinus Torvalds 			sc->result = DID_SOFT_ERROR << 16;
9571da177e4SLinus Torvalds 			break;
9581da177e4SLinus Torvalds 
9591da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_FUNCTION:		/* 0x0001 */
9601da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_SGL:			/* 0x0003 */
9611da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INTERNAL_ERROR:		/* 0x0004 */
9621da177e4SLinus Torvalds 		case MPI_IOCSTATUS_RESERVED:			/* 0x0005 */
9631da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_FIELD:		/* 0x0007 */
9641da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_STATE:		/* 0x0008 */
9651da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
9661da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:	/* 0x004A */
9671da177e4SLinus Torvalds 		default:
9681da177e4SLinus Torvalds 			/*
9691da177e4SLinus Torvalds 			 * What to do?
9701da177e4SLinus Torvalds 			 */
9711da177e4SLinus Torvalds 			sc->result = DID_SOFT_ERROR << 16;
9721da177e4SLinus Torvalds 			break;
9731da177e4SLinus Torvalds 
9741da177e4SLinus Torvalds 		}	/* switch(status) */
9751da177e4SLinus Torvalds 
9766757d6b4SPrakash, Sathya #ifdef CONFIG_FUSION_LOGGING
9776757d6b4SPrakash, Sathya 		if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
9786757d6b4SPrakash, Sathya 			mptscsih_info_scsiio(ioc, sc, pScsiReply);
979c6c727a1SEric Moore #endif
980c6c727a1SEric Moore 
9811da177e4SLinus Torvalds 	} /* end of address reply case */
982fea98403SKashyap, Desai out:
9831da177e4SLinus Torvalds 	/* Unmap the DMA buffers, if any. */
9841928d73fSFUJITA Tomonori 	scsi_dma_unmap(sc);
9851da177e4SLinus Torvalds 
9861da177e4SLinus Torvalds 	sc->scsi_done(sc);		/* Issue the command callback */
9871da177e4SLinus Torvalds 
9881da177e4SLinus Torvalds 	/* Free Chain buffers */
9891da177e4SLinus Torvalds 	mptscsih_freeChainBuffers(ioc, req_idx);
9901da177e4SLinus Torvalds 	return 1;
9911da177e4SLinus Torvalds }
9921da177e4SLinus Torvalds 
9931da177e4SLinus Torvalds /*
9941da177e4SLinus Torvalds  *	mptscsih_flush_running_cmds - For each command found, search
9951da177e4SLinus Torvalds  *		Scsi_Host instance taskQ and reply to OS.
9961da177e4SLinus Torvalds  *		Called only if recovering from a FW reload.
9971da177e4SLinus Torvalds  *	@hd: Pointer to a SCSI HOST structure
9981da177e4SLinus Torvalds  *
9991da177e4SLinus Torvalds  *	Returns: None.
10001da177e4SLinus Torvalds  *
10011da177e4SLinus Torvalds  *	Must be called while new I/Os are being queued.
10021da177e4SLinus Torvalds  */
10031da177e4SLinus Torvalds static void
10041da177e4SLinus Torvalds mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
10051da177e4SLinus Torvalds {
10061da177e4SLinus Torvalds 	MPT_ADAPTER *ioc = hd->ioc;
1007e8206381SEric Moore 	struct scsi_cmnd *sc;
1008e8206381SEric Moore 	SCSIIORequest_t	*mf = NULL;
10091da177e4SLinus Torvalds 	int		 ii;
1010e8206381SEric Moore 	int		 channel, id;
10111da177e4SLinus Torvalds 
1012e8206381SEric Moore 	for (ii= 0; ii < ioc->req_depth; ii++) {
1013e8206381SEric Moore 		sc = mptscsih_getclear_scsi_lookup(ioc, ii);
1014e8206381SEric Moore 		if (!sc)
10153dc0b03fSEric Moore 			continue;
1016e8206381SEric Moore 		mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
1017e8206381SEric Moore 		if (!mf)
1018e8206381SEric Moore 			continue;
1019e8206381SEric Moore 		channel = mf->Bus;
1020e8206381SEric Moore 		id = mf->TargetID;
1021e8206381SEric Moore 		mptscsih_freeChainBuffers(ioc, ii);
1022e8206381SEric Moore 		mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
1023e8206381SEric Moore 		if ((unsigned char *)mf != sc->host_scribble)
1024e8206381SEric Moore 			continue;
1025e8206381SEric Moore 		scsi_dma_unmap(sc);
1026e8206381SEric Moore 		sc->result = DID_RESET << 16;
1027e8206381SEric Moore 		sc->host_scribble = NULL;
10282f187862SKashyap, Desai 		dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
10292f187862SKashyap, Desai 		    "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
10302f187862SKashyap, Desai 		    "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
1031e8206381SEric Moore 		sc->scsi_done(sc);
10321da177e4SLinus Torvalds 	}
10331da177e4SLinus Torvalds }
10341da177e4SLinus Torvalds 
10351da177e4SLinus Torvalds /*
10361da177e4SLinus Torvalds  *	mptscsih_search_running_cmds - Delete any commands associated
10371da177e4SLinus Torvalds  *		with the specified target and lun. Function called only
10381da177e4SLinus Torvalds  *		when a lun is disable by mid-layer.
10391da177e4SLinus Torvalds  *		Do NOT access the referenced scsi_cmnd structure or
10401da177e4SLinus Torvalds  *		members. Will cause either a paging or NULL ptr error.
104105e8ec17SMichael Reed  *		(BUT, BUT, BUT, the code does reference it! - mdr)
10421da177e4SLinus Torvalds  *      @hd: Pointer to a SCSI HOST structure
1043c7c82987SMoore, Eric Dean  *	@vdevice: per device private data
10441da177e4SLinus Torvalds  *
10451da177e4SLinus Torvalds  *	Returns: None.
10461da177e4SLinus Torvalds  *
10471da177e4SLinus Torvalds  *	Called from slave_destroy.
10481da177e4SLinus Torvalds  */
10491da177e4SLinus Torvalds static void
1050c7c82987SMoore, Eric Dean mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
10511da177e4SLinus Torvalds {
10521da177e4SLinus Torvalds 	SCSIIORequest_t	*mf = NULL;
10531da177e4SLinus Torvalds 	int		 ii;
1054466544d8SMoore, Eric Dean 	struct scsi_cmnd *sc;
1055793955f5SEric Moore 	struct scsi_lun  lun;
1056e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
1057e8206381SEric Moore 	unsigned long	flags;
10581da177e4SLinus Torvalds 
1059e8206381SEric Moore 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
1060e8206381SEric Moore 	for (ii = 0; ii < ioc->req_depth; ii++) {
1061e8206381SEric Moore 		if ((sc = ioc->ScsiLookup[ii]) != NULL) {
10621da177e4SLinus Torvalds 
1063e80b002bSEric Moore 			mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
10643dc0b03fSEric Moore 			if (mf == NULL)
10653dc0b03fSEric Moore 				continue;
1066cc78d30aSEric Moore 			/* If the device is a hidden raid component, then its
1067cc78d30aSEric Moore 			 * expected that the mf->function will be RAID_SCSI_IO
1068cc78d30aSEric Moore 			 */
1069cc78d30aSEric Moore 			if (vdevice->vtarget->tflags &
1070cc78d30aSEric Moore 			    MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1071cc78d30aSEric Moore 			    MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1072cc78d30aSEric Moore 				continue;
1073cc78d30aSEric Moore 
1074793955f5SEric Moore 			int_to_scsilun(vdevice->lun, &lun);
1075793955f5SEric Moore 			if ((mf->Bus != vdevice->vtarget->channel) ||
1076793955f5SEric Moore 			    (mf->TargetID != vdevice->vtarget->id) ||
1077793955f5SEric Moore 			    memcmp(lun.scsi_lun, mf->LUN, 8))
10781da177e4SLinus Torvalds 				continue;
10791da177e4SLinus Torvalds 
10803dc0b03fSEric Moore 			if ((unsigned char *)mf != sc->host_scribble)
10813dc0b03fSEric Moore 				continue;
1082e8206381SEric Moore 			ioc->ScsiLookup[ii] = NULL;
1083e8206381SEric Moore 			spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
1084e8206381SEric Moore 			mptscsih_freeChainBuffers(ioc, ii);
1085e8206381SEric Moore 			mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
10861928d73fSFUJITA Tomonori 			scsi_dma_unmap(sc);
1087466544d8SMoore, Eric Dean 			sc->host_scribble = NULL;
1088466544d8SMoore, Eric Dean 			sc->result = DID_NO_CONNECT << 16;
10892f187862SKashyap, Desai 			dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
10902f187862SKashyap, Desai 			   MYIOC_s_FMT "completing cmds: fw_channel %d, "
10912f187862SKashyap, Desai 			   "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
10922f187862SKashyap, Desai 			   vdevice->vtarget->channel, vdevice->vtarget->id,
10932f187862SKashyap, Desai 			   sc, mf, ii));
1094466544d8SMoore, Eric Dean 			sc->scsi_done(sc);
1095e8206381SEric Moore 			spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
10961da177e4SLinus Torvalds 		}
10971da177e4SLinus Torvalds 	}
1098e8206381SEric Moore 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
10991da177e4SLinus Torvalds 	return;
11001da177e4SLinus Torvalds }
11011da177e4SLinus Torvalds 
11021da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11031da177e4SLinus Torvalds 
11041da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11051da177e4SLinus Torvalds /*
11061da177e4SLinus Torvalds  *	mptscsih_report_queue_full - Report QUEUE_FULL status returned
11071da177e4SLinus Torvalds  *	from a SCSI target device.
11081da177e4SLinus Torvalds  *	@sc: Pointer to scsi_cmnd structure
11091da177e4SLinus Torvalds  *	@pScsiReply: Pointer to SCSIIOReply_t
11101da177e4SLinus Torvalds  *	@pScsiReq: Pointer to original SCSI request
11111da177e4SLinus Torvalds  *
11121da177e4SLinus Torvalds  *	This routine periodically reports QUEUE_FULL status returned from a
11131da177e4SLinus Torvalds  *	SCSI target device.  It reports this to the console via kernel
11141da177e4SLinus Torvalds  *	printk() API call, not more than once every 10 seconds.
11151da177e4SLinus Torvalds  */
11161da177e4SLinus Torvalds static void
11171da177e4SLinus Torvalds mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
11181da177e4SLinus Torvalds {
11191da177e4SLinus Torvalds 	long time = jiffies;
11201da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
1121e80b002bSEric Moore 	MPT_ADAPTER	*ioc;
11221da177e4SLinus Torvalds 
11230d0c7974SMoore, Eric Dean  	if (sc->device == NULL)
11240d0c7974SMoore, Eric Dean  		return;
11250d0c7974SMoore, Eric Dean  	if (sc->device->host == NULL)
11260d0c7974SMoore, Eric Dean  		return;
1127e7eae9f6SEric Moore 	if ((hd = shost_priv(sc->device->host)) == NULL)
11280d0c7974SMoore, Eric Dean  		return;
1129e80b002bSEric Moore 	ioc = hd->ioc;
11300d0c7974SMoore, Eric Dean  	if (time - hd->last_queue_full > 10 * HZ) {
1131e80b002bSEric Moore 		dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1132e80b002bSEric Moore 				ioc->name, 0, sc->device->id, sc->device->lun));
11330d0c7974SMoore, Eric Dean  		hd->last_queue_full = time;
11341da177e4SLinus Torvalds 	}
11351da177e4SLinus Torvalds }
11361da177e4SLinus Torvalds 
11371da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11381da177e4SLinus Torvalds /*
11391da177e4SLinus Torvalds  *	mptscsih_remove - Removed scsi devices
11401da177e4SLinus Torvalds  *	@pdev: Pointer to pci_dev structure
11411da177e4SLinus Torvalds  *
11421da177e4SLinus Torvalds  *
11431da177e4SLinus Torvalds  */
11440d0c7974SMoore, Eric Dean  void
11451da177e4SLinus Torvalds mptscsih_remove(struct pci_dev *pdev)
11461da177e4SLinus Torvalds {
11471da177e4SLinus Torvalds 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
11481da177e4SLinus Torvalds 	struct Scsi_Host 	*host = ioc->sh;
11491da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
11500d0c7974SMoore, Eric Dean  	int sz1;
11511da177e4SLinus Torvalds 
1152466544d8SMoore, Eric Dean 	if(!host) {
1153466544d8SMoore, Eric Dean 		mpt_detach(pdev);
11541da177e4SLinus Torvalds 		return;
1155466544d8SMoore, Eric Dean 	}
11561da177e4SLinus Torvalds 
11571da177e4SLinus Torvalds 	scsi_remove_host(host);
11581da177e4SLinus Torvalds 
1159e7eae9f6SEric Moore 	if((hd = shost_priv(host)) == NULL)
11600d0c7974SMoore, Eric Dean  		return;
11610d0c7974SMoore, Eric Dean  
1162d18c3db5SGreg Kroah-Hartman 	mptscsih_shutdown(pdev);
11631da177e4SLinus Torvalds 
11641da177e4SLinus Torvalds 	sz1=0;
11651da177e4SLinus Torvalds 
1166e8206381SEric Moore 	if (ioc->ScsiLookup != NULL) {
1167e80b002bSEric Moore 		sz1 = ioc->req_depth * sizeof(void *);
1168e8206381SEric Moore 		kfree(ioc->ScsiLookup);
1169e8206381SEric Moore 		ioc->ScsiLookup = NULL;
11701da177e4SLinus Torvalds 	}
11711da177e4SLinus Torvalds 
1172e80b002bSEric Moore 	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
11731da177e4SLinus Torvalds 	    "Free'd ScsiLookup (%d) memory\n",
1174e80b002bSEric Moore 	    ioc->name, sz1));
11751da177e4SLinus Torvalds 
11760d0c7974SMoore, Eric Dean  	kfree(hd->info_kbuf);
11770d0c7974SMoore, Eric Dean  
11781da177e4SLinus Torvalds 	/* NULL the Scsi_Host pointer
11791da177e4SLinus Torvalds 	 */
1180e80b002bSEric Moore 	ioc->sh = NULL;
11811da177e4SLinus Torvalds 
11821da177e4SLinus Torvalds 	scsi_host_put(host);
11830d0c7974SMoore, Eric Dean  
11840d0c7974SMoore, Eric Dean  	mpt_detach(pdev);
11851da177e4SLinus Torvalds 
11861da177e4SLinus Torvalds }
11871da177e4SLinus Torvalds 
11881da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11891da177e4SLinus Torvalds /*
11901da177e4SLinus Torvalds  *	mptscsih_shutdown - reboot notifier
11911da177e4SLinus Torvalds  *
11921da177e4SLinus Torvalds  */
11930d0c7974SMoore, Eric Dean  void
1194d18c3db5SGreg Kroah-Hartman mptscsih_shutdown(struct pci_dev *pdev)
11951da177e4SLinus Torvalds {
11961da177e4SLinus Torvalds }
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds #ifdef CONFIG_PM
11991da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12001da177e4SLinus Torvalds /*
12010d0c7974SMoore, Eric Dean   *	mptscsih_suspend - Fusion MPT scsi driver suspend routine.
12021da177e4SLinus Torvalds  *
12031da177e4SLinus Torvalds  *
12041da177e4SLinus Torvalds  */
12050d0c7974SMoore, Eric Dean  int
12068d189f72SPavel Machek mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
12071da177e4SLinus Torvalds {
12084d4109d0SPrakash, Sathya 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
12094d4109d0SPrakash, Sathya 
12104d4109d0SPrakash, Sathya 	scsi_block_requests(ioc->sh);
12114d4109d0SPrakash, Sathya 	flush_scheduled_work();
1212d18c3db5SGreg Kroah-Hartman 	mptscsih_shutdown(pdev);
12130d0c7974SMoore, Eric Dean  	return mpt_suspend(pdev,state);
12141da177e4SLinus Torvalds }
12151da177e4SLinus Torvalds 
12161da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12171da177e4SLinus Torvalds /*
12181da177e4SLinus Torvalds  *	mptscsih_resume - Fusion MPT scsi driver resume routine.
12191da177e4SLinus Torvalds  *
12201da177e4SLinus Torvalds  *
12211da177e4SLinus Torvalds  */
12220d0c7974SMoore, Eric Dean  int
12231da177e4SLinus Torvalds mptscsih_resume(struct pci_dev *pdev)
12241da177e4SLinus Torvalds {
12254d4109d0SPrakash, Sathya 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
12264d4109d0SPrakash, Sathya 	int rc;
12274d4109d0SPrakash, Sathya 
12284d4109d0SPrakash, Sathya 	rc = mpt_resume(pdev);
12294d4109d0SPrakash, Sathya 	scsi_unblock_requests(ioc->sh);
12304d4109d0SPrakash, Sathya 	return rc;
12311da177e4SLinus Torvalds }
12321da177e4SLinus Torvalds 
12331da177e4SLinus Torvalds #endif
12341da177e4SLinus Torvalds 
12351da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12361da177e4SLinus Torvalds /**
12371da177e4SLinus Torvalds  *	mptscsih_info - Return information about MPT adapter
12381da177e4SLinus Torvalds  *	@SChost: Pointer to Scsi_Host structure
12391da177e4SLinus Torvalds  *
12401da177e4SLinus Torvalds  *	(linux scsi_host_template.info routine)
12411da177e4SLinus Torvalds  *
12421da177e4SLinus Torvalds  *	Returns pointer to buffer where information was written.
12431da177e4SLinus Torvalds  */
12440d0c7974SMoore, Eric Dean  const char *
12451da177e4SLinus Torvalds mptscsih_info(struct Scsi_Host *SChost)
12461da177e4SLinus Torvalds {
12471da177e4SLinus Torvalds 	MPT_SCSI_HOST *h;
12481da177e4SLinus Torvalds 	int size = 0;
12491da177e4SLinus Torvalds 
1250e7eae9f6SEric Moore 	h = shost_priv(SChost);
12510d0c7974SMoore, Eric Dean  
12521da177e4SLinus Torvalds 	if (h) {
12530d0c7974SMoore, Eric Dean  		if (h->info_kbuf == NULL)
12540d0c7974SMoore, Eric Dean  			if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
12550d0c7974SMoore, Eric Dean  				return h->info_kbuf;
12560d0c7974SMoore, Eric Dean  		h->info_kbuf[0] = '\0';
12570d0c7974SMoore, Eric Dean  
12580d0c7974SMoore, Eric Dean  		mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
12590d0c7974SMoore, Eric Dean  		h->info_kbuf[size-1] = '\0';
12601da177e4SLinus Torvalds 	}
12611da177e4SLinus Torvalds 
12620d0c7974SMoore, Eric Dean  	return h->info_kbuf;
12631da177e4SLinus Torvalds }
12641da177e4SLinus Torvalds 
12651da177e4SLinus Torvalds struct info_str {
12661da177e4SLinus Torvalds 	char *buffer;
12671da177e4SLinus Torvalds 	int   length;
12681da177e4SLinus Torvalds 	int   offset;
12691da177e4SLinus Torvalds 	int   pos;
12701da177e4SLinus Torvalds };
12711da177e4SLinus Torvalds 
12720d0c7974SMoore, Eric Dean  static void
12730d0c7974SMoore, Eric Dean  mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
12741da177e4SLinus Torvalds {
12751da177e4SLinus Torvalds 	if (info->pos + len > info->length)
12761da177e4SLinus Torvalds 		len = info->length - info->pos;
12771da177e4SLinus Torvalds 
12781da177e4SLinus Torvalds 	if (info->pos + len < info->offset) {
12791da177e4SLinus Torvalds 		info->pos += len;
12801da177e4SLinus Torvalds 		return;
12811da177e4SLinus Torvalds 	}
12821da177e4SLinus Torvalds 
12831da177e4SLinus Torvalds 	if (info->pos < info->offset) {
12841da177e4SLinus Torvalds 	        data += (info->offset - info->pos);
12851da177e4SLinus Torvalds 	        len  -= (info->offset - info->pos);
12861da177e4SLinus Torvalds 	}
12871da177e4SLinus Torvalds 
12881da177e4SLinus Torvalds 	if (len > 0) {
12891da177e4SLinus Torvalds                 memcpy(info->buffer + info->pos, data, len);
12901da177e4SLinus Torvalds                 info->pos += len;
12911da177e4SLinus Torvalds 	}
12921da177e4SLinus Torvalds }
12931da177e4SLinus Torvalds 
12940d0c7974SMoore, Eric Dean  static int
12950d0c7974SMoore, Eric Dean  mptscsih_copy_info(struct info_str *info, char *fmt, ...)
12961da177e4SLinus Torvalds {
12971da177e4SLinus Torvalds 	va_list args;
12981da177e4SLinus Torvalds 	char buf[81];
12991da177e4SLinus Torvalds 	int len;
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds 	va_start(args, fmt);
13021da177e4SLinus Torvalds 	len = vsprintf(buf, fmt, args);
13031da177e4SLinus Torvalds 	va_end(args);
13041da177e4SLinus Torvalds 
13050d0c7974SMoore, Eric Dean  	mptscsih_copy_mem_info(info, buf, len);
13061da177e4SLinus Torvalds 	return len;
13071da177e4SLinus Torvalds }
13081da177e4SLinus Torvalds 
13090d0c7974SMoore, Eric Dean  static int
13100d0c7974SMoore, Eric Dean  mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
13111da177e4SLinus Torvalds {
13121da177e4SLinus Torvalds 	struct info_str info;
13131da177e4SLinus Torvalds 
13141da177e4SLinus Torvalds 	info.buffer	= pbuf;
13151da177e4SLinus Torvalds 	info.length	= len;
13161da177e4SLinus Torvalds 	info.offset	= offset;
13171da177e4SLinus Torvalds 	info.pos	= 0;
13181da177e4SLinus Torvalds 
13190d0c7974SMoore, Eric Dean  	mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
13200d0c7974SMoore, Eric Dean  	mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
13210d0c7974SMoore, Eric Dean  	mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
13220d0c7974SMoore, Eric Dean  	mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
13231da177e4SLinus Torvalds 
13241da177e4SLinus Torvalds 	return ((info.pos > info.offset) ? info.pos - info.offset : 0);
13251da177e4SLinus Torvalds }
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13281da177e4SLinus Torvalds /**
13291da177e4SLinus Torvalds  *	mptscsih_proc_info - Return information about MPT adapter
1330d9489fb6SRandy Dunlap  * 	@host:   scsi host struct
1331d9489fb6SRandy Dunlap  * 	@buffer: if write, user data; if read, buffer for user
1332d9489fb6SRandy Dunlap  *	@start: returns the buffer address
1333d9489fb6SRandy Dunlap  * 	@offset: if write, 0; if read, the current offset into the buffer from
1334d9489fb6SRandy Dunlap  * 		 the previous read.
1335d9489fb6SRandy Dunlap  * 	@length: if write, return length;
1336d9489fb6SRandy Dunlap  *	@func:   write = 1; read = 0
13371da177e4SLinus Torvalds  *
13381da177e4SLinus Torvalds  *	(linux scsi_host_template.info routine)
13391da177e4SLinus Torvalds  */
13400d0c7974SMoore, Eric Dean  int
13411da177e4SLinus Torvalds mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
13421da177e4SLinus Torvalds 			int length, int func)
13431da177e4SLinus Torvalds {
1344e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
13451da177e4SLinus Torvalds 	MPT_ADAPTER	*ioc = hd->ioc;
13461da177e4SLinus Torvalds 	int size = 0;
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds 	if (func) {
13491da177e4SLinus Torvalds 		/*
13501da177e4SLinus Torvalds 		 * write is not supported
13511da177e4SLinus Torvalds 		 */
13521da177e4SLinus Torvalds 	} else {
13531da177e4SLinus Torvalds 		if (start)
13541da177e4SLinus Torvalds 			*start = buffer;
13551da177e4SLinus Torvalds 
13561da177e4SLinus Torvalds 		size = mptscsih_host_info(ioc, buffer, offset, length);
13571da177e4SLinus Torvalds 	}
13581da177e4SLinus Torvalds 
13591da177e4SLinus Torvalds 	return size;
13601da177e4SLinus Torvalds }
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13631da177e4SLinus Torvalds #define ADD_INDEX_LOG(req_ent)	do { } while(0)
13641da177e4SLinus Torvalds 
13651da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13661da177e4SLinus Torvalds /**
13671da177e4SLinus Torvalds  *	mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
13681da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure
13691da177e4SLinus Torvalds  *	@done: Pointer SCSI mid-layer IO completion function
13701da177e4SLinus Torvalds  *
13711da177e4SLinus Torvalds  *	(linux scsi_host_template.queuecommand routine)
13721da177e4SLinus Torvalds  *	This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
13731da177e4SLinus Torvalds  *	from a linux scsi_cmnd request and send it to the IOC.
13741da177e4SLinus Torvalds  *
13751da177e4SLinus Torvalds  *	Returns 0. (rtn value discarded by linux scsi mid-layer)
13761da177e4SLinus Torvalds  */
13770d0c7974SMoore, Eric Dean  int
13781da177e4SLinus Torvalds mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
13791da177e4SLinus Torvalds {
13801da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
13811da177e4SLinus Torvalds 	MPT_FRAME_HDR		*mf;
13821da177e4SLinus Torvalds 	SCSIIORequest_t		*pScsiReq;
1383a69de507SEric Moore 	VirtDevice		*vdevice = SCpnt->device->hostdata;
13841da177e4SLinus Torvalds 	u32	 datalen;
13851da177e4SLinus Torvalds 	u32	 scsictl;
13861da177e4SLinus Torvalds 	u32	 scsidir;
13871da177e4SLinus Torvalds 	u32	 cmd_len;
13881da177e4SLinus Torvalds 	int	 my_idx;
13891da177e4SLinus Torvalds 	int	 ii;
13906757d6b4SPrakash, Sathya 	MPT_ADAPTER *ioc;
13911da177e4SLinus Torvalds 
1392e7eae9f6SEric Moore 	hd = shost_priv(SCpnt->device->host);
13936757d6b4SPrakash, Sathya 	ioc = hd->ioc;
13941da177e4SLinus Torvalds 	SCpnt->scsi_done = done;
13951da177e4SLinus Torvalds 
13966757d6b4SPrakash, Sathya 	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
13976757d6b4SPrakash, Sathya 		ioc->name, SCpnt, done));
13981da177e4SLinus Torvalds 
1399e7deff33SKashyap, Desai 	if (ioc->taskmgmt_quiesce_io) {
14006757d6b4SPrakash, Sathya 		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
14016757d6b4SPrakash, Sathya 			ioc->name, SCpnt));
14021da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
14031da177e4SLinus Torvalds 	}
14041da177e4SLinus Torvalds 
14051da177e4SLinus Torvalds 	/*
14061da177e4SLinus Torvalds 	 *  Put together a MPT SCSI request...
14071da177e4SLinus Torvalds 	 */
1408e80b002bSEric Moore 	if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
14096757d6b4SPrakash, Sathya 		dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
14106757d6b4SPrakash, Sathya 				ioc->name));
14111da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
14121da177e4SLinus Torvalds 	}
14131da177e4SLinus Torvalds 
14141da177e4SLinus Torvalds 	pScsiReq = (SCSIIORequest_t *) mf;
14151da177e4SLinus Torvalds 
14161da177e4SLinus Torvalds 	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
14171da177e4SLinus Torvalds 
14181da177e4SLinus Torvalds 	ADD_INDEX_LOG(my_idx);
14191da177e4SLinus Torvalds 
14200d0c7974SMoore, Eric Dean  	/*    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
14211da177e4SLinus Torvalds 	 *    Seems we may receive a buffer (datalen>0) even when there
14221da177e4SLinus Torvalds 	 *    will be no data transfer!  GRRRRR...
14231da177e4SLinus Torvalds 	 */
14241da177e4SLinus Torvalds 	if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
14251928d73fSFUJITA Tomonori 		datalen = scsi_bufflen(SCpnt);
14261da177e4SLinus Torvalds 		scsidir = MPI_SCSIIO_CONTROL_READ;	/* DATA IN  (host<--ioc<--dev) */
14271da177e4SLinus Torvalds 	} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
14281928d73fSFUJITA Tomonori 		datalen = scsi_bufflen(SCpnt);
14291da177e4SLinus Torvalds 		scsidir = MPI_SCSIIO_CONTROL_WRITE;	/* DATA OUT (host-->ioc-->dev) */
14301da177e4SLinus Torvalds 	} else {
14311da177e4SLinus Torvalds 		datalen = 0;
14321da177e4SLinus Torvalds 		scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
14331da177e4SLinus Torvalds 	}
14341da177e4SLinus Torvalds 
14351da177e4SLinus Torvalds 	/* Default to untagged. Once a target structure has been allocated,
14361da177e4SLinus Torvalds 	 * use the Inquiry data to determine if device supports tagged.
14371da177e4SLinus Torvalds 	 */
1438a69de507SEric Moore 	if (vdevice
1439a69de507SEric Moore 	    && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
14401da177e4SLinus Torvalds 	    && (SCpnt->device->tagged_supported)) {
14411da177e4SLinus Torvalds 		scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
144265f89c23SKashyap, Desai 		if (SCpnt->request && SCpnt->request->ioprio) {
144365f89c23SKashyap, Desai 			if (((SCpnt->request->ioprio & 0x7) == 1) ||
144465f89c23SKashyap, Desai 				!(SCpnt->request->ioprio & 0x7))
144565f89c23SKashyap, Desai 				scsictl |= MPI_SCSIIO_CONTROL_HEADOFQ;
14461da177e4SLinus Torvalds 		}
144765f89c23SKashyap, Desai 	} else
144865f89c23SKashyap, Desai 		scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
144965f89c23SKashyap, Desai 
14501da177e4SLinus Torvalds 
14511da177e4SLinus Torvalds 	/* Use the above information to set up the message frame
14521da177e4SLinus Torvalds 	 */
1453a69de507SEric Moore 	pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1454a69de507SEric Moore 	pScsiReq->Bus = vdevice->vtarget->channel;
14551da177e4SLinus Torvalds 	pScsiReq->ChainOffset = 0;
1456a69de507SEric Moore 	if (vdevice->vtarget->tflags &  MPT_TARGET_FLAGS_RAID_COMPONENT)
1457c92f222eSJames Bottomley 		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1458c92f222eSJames Bottomley 	else
14591da177e4SLinus Torvalds 		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
14601da177e4SLinus Torvalds 	pScsiReq->CDBLength = SCpnt->cmd_len;
14611da177e4SLinus Torvalds 	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
14621da177e4SLinus Torvalds 	pScsiReq->Reserved = 0;
146314d0f0b0SKashyap, Desai 	pScsiReq->MsgFlags = mpt_msg_flags(ioc);
1464793955f5SEric Moore 	int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
14651da177e4SLinus Torvalds 	pScsiReq->Control = cpu_to_le32(scsictl);
14661da177e4SLinus Torvalds 
14671da177e4SLinus Torvalds 	/*
14681da177e4SLinus Torvalds 	 *  Write SCSI CDB into the message
14691da177e4SLinus Torvalds 	 */
14701da177e4SLinus Torvalds 	cmd_len = SCpnt->cmd_len;
14711da177e4SLinus Torvalds 	for (ii=0; ii < cmd_len; ii++)
14721da177e4SLinus Torvalds 		pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
14731da177e4SLinus Torvalds 
14741da177e4SLinus Torvalds 	for (ii=cmd_len; ii < 16; ii++)
14751da177e4SLinus Torvalds 		pScsiReq->CDB[ii] = 0;
14761da177e4SLinus Torvalds 
14771da177e4SLinus Torvalds 	/* DataLength */
14781da177e4SLinus Torvalds 	pScsiReq->DataLength = cpu_to_le32(datalen);
14791da177e4SLinus Torvalds 
14801da177e4SLinus Torvalds 	/* SenseBuffer low address */
1481e80b002bSEric Moore 	pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
14821da177e4SLinus Torvalds 					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
14831da177e4SLinus Torvalds 
14841da177e4SLinus Torvalds 	/* Now add the SG list
14851da177e4SLinus Torvalds 	 * Always have a SGE even if null length.
14861da177e4SLinus Torvalds 	 */
14871da177e4SLinus Torvalds 	if (datalen == 0) {
14881da177e4SLinus Torvalds 		/* Add a NULL SGE */
148914d0f0b0SKashyap, Desai 		ioc->add_sge((char *)&pScsiReq->SGL,
149014d0f0b0SKashyap, Desai 			MPT_SGE_FLAGS_SSIMPLE_READ | 0,
14911da177e4SLinus Torvalds 			(dma_addr_t) -1);
14921da177e4SLinus Torvalds 	} else {
14931da177e4SLinus Torvalds 		/* Add a 32 or 64 bit SGE */
1494e80b002bSEric Moore 		if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
14951da177e4SLinus Torvalds 			goto fail;
14961da177e4SLinus Torvalds 	}
14971da177e4SLinus Torvalds 
14983dc0b03fSEric Moore 	SCpnt->host_scribble = (unsigned char *)mf;
1499e8206381SEric Moore 	mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
15001da177e4SLinus Torvalds 
1501e80b002bSEric Moore 	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
15026757d6b4SPrakash, Sathya 	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
15036757d6b4SPrakash, Sathya 			ioc->name, SCpnt, mf, my_idx));
150429dd3609SEric Moore 	DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
15051da177e4SLinus Torvalds 	return 0;
15061da177e4SLinus Torvalds 
15071da177e4SLinus Torvalds  fail:
1508e80b002bSEric Moore 	mptscsih_freeChainBuffers(ioc, my_idx);
1509e80b002bSEric Moore 	mpt_free_msg_frame(ioc, mf);
15101da177e4SLinus Torvalds 	return SCSI_MLQUEUE_HOST_BUSY;
15111da177e4SLinus Torvalds }
15121da177e4SLinus Torvalds 
15131da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
15141da177e4SLinus Torvalds /*
15151da177e4SLinus Torvalds  *	mptscsih_freeChainBuffers - Function to free chain buffers associated
15161da177e4SLinus Torvalds  *	with a SCSI IO request
15171da177e4SLinus Torvalds  *	@hd: Pointer to the MPT_SCSI_HOST instance
15181da177e4SLinus Torvalds  *	@req_idx: Index of the SCSI IO request frame.
15191da177e4SLinus Torvalds  *
15201da177e4SLinus Torvalds  *	Called if SG chain buffer allocation fails and mptscsih callbacks.
15211da177e4SLinus Torvalds  *	No return.
15221da177e4SLinus Torvalds  */
15231da177e4SLinus Torvalds static void
15241da177e4SLinus Torvalds mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
15251da177e4SLinus Torvalds {
15261da177e4SLinus Torvalds 	MPT_FRAME_HDR *chain;
15271da177e4SLinus Torvalds 	unsigned long flags;
15281da177e4SLinus Torvalds 	int chain_idx;
15291da177e4SLinus Torvalds 	int next;
15301da177e4SLinus Torvalds 
15311da177e4SLinus Torvalds 	/* Get the first chain index and reset
15321da177e4SLinus Torvalds 	 * tracker state.
15331da177e4SLinus Torvalds 	 */
15341da177e4SLinus Torvalds 	chain_idx = ioc->ReqToChain[req_idx];
15351da177e4SLinus Torvalds 	ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
15361da177e4SLinus Torvalds 
15371da177e4SLinus Torvalds 	while (chain_idx != MPT_HOST_NO_CHAIN) {
15381da177e4SLinus Torvalds 
15391da177e4SLinus Torvalds 		/* Save the next chain buffer index */
15401da177e4SLinus Torvalds 		next = ioc->ChainToChain[chain_idx];
15411da177e4SLinus Torvalds 
15421da177e4SLinus Torvalds 		/* Free this chain buffer and reset
15431da177e4SLinus Torvalds 		 * tracker
15441da177e4SLinus Torvalds 		 */
15451da177e4SLinus Torvalds 		ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
15461da177e4SLinus Torvalds 
15471da177e4SLinus Torvalds 		chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
15481da177e4SLinus Torvalds 					+ (chain_idx * ioc->req_sz));
15491da177e4SLinus Torvalds 
15501da177e4SLinus Torvalds 		spin_lock_irqsave(&ioc->FreeQlock, flags);
15511da177e4SLinus Torvalds 		list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
15521da177e4SLinus Torvalds 		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
15531da177e4SLinus Torvalds 
15546757d6b4SPrakash, Sathya 		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
15551da177e4SLinus Torvalds 				ioc->name, chain_idx));
15561da177e4SLinus Torvalds 
15571da177e4SLinus Torvalds 		/* handle next */
15581da177e4SLinus Torvalds 		chain_idx = next;
15591da177e4SLinus Torvalds 	}
15601da177e4SLinus Torvalds 	return;
15611da177e4SLinus Torvalds }
15621da177e4SLinus Torvalds 
15631da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
15641da177e4SLinus Torvalds /*
15651da177e4SLinus Torvalds  *	Reset Handling
15661da177e4SLinus Torvalds  */
15671da177e4SLinus Torvalds 
15681da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1569cd2c6191SEric Moore /**
15701da177e4SLinus Torvalds  *	mptscsih_IssueTaskMgmt - Generic send Task Management function.
15711da177e4SLinus Torvalds  *	@hd: Pointer to MPT_SCSI_HOST structure
15721da177e4SLinus Torvalds  *	@type: Task Management type
15731544d677SRandy Dunlap  *	@channel: channel number for task management
1574793955f5SEric Moore  *	@id: Logical Target ID for reset (if appropriate)
15751da177e4SLinus Torvalds  *	@lun: Logical Unit for reset (if appropriate)
15761da177e4SLinus Torvalds  *	@ctx2abort: Context for the task to be aborted (if appropriate)
15771544d677SRandy Dunlap  *	@timeout: timeout for task management control
15781da177e4SLinus Torvalds  *
15791da177e4SLinus Torvalds  *	Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
15801da177e4SLinus Torvalds  *	or a non-interrupt thread.  In the former, must not call schedule().
15811da177e4SLinus Torvalds  *
15821da177e4SLinus Torvalds  *	Not all fields are meaningfull for all task types.
15831da177e4SLinus Torvalds  *
1584cd2c6191SEric Moore  *	Returns 0 for SUCCESS, or FAILED.
1585cd2c6191SEric Moore  *
1586cd2c6191SEric Moore  **/
15871ba9ab2eSKashyap, Desai int
15881ba9ab2eSKashyap, Desai mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
15891ba9ab2eSKashyap, Desai 	int ctx2abort, ulong timeout)
15901da177e4SLinus Torvalds {
15911da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
15921da177e4SLinus Torvalds 	SCSITaskMgmt_t	*pScsiTm;
15931da177e4SLinus Torvalds 	int		 ii;
15941da177e4SLinus Torvalds 	int		 retval;
1595e80b002bSEric Moore 	MPT_ADAPTER 	*ioc = hd->ioc;
15961ba9ab2eSKashyap, Desai 	unsigned long	 timeleft;
15971ba9ab2eSKashyap, Desai 	u8		 issue_hard_reset;
15981ba9ab2eSKashyap, Desai 	u32		 ioc_raw_state;
15991ba9ab2eSKashyap, Desai 	unsigned long	 time_count;
16001ba9ab2eSKashyap, Desai 
16011ba9ab2eSKashyap, Desai 	issue_hard_reset = 0;
16021ba9ab2eSKashyap, Desai 	ioc_raw_state = mpt_GetIocState(ioc, 0);
16031ba9ab2eSKashyap, Desai 
16041ba9ab2eSKashyap, Desai 	if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
16051ba9ab2eSKashyap, Desai 		printk(MYIOC_s_WARN_FMT
16061ba9ab2eSKashyap, Desai 			"TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
16071ba9ab2eSKashyap, Desai 			ioc->name, type, ioc_raw_state);
16081ba9ab2eSKashyap, Desai 		printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
16091ba9ab2eSKashyap, Desai 		    ioc->name, __func__);
16101ba9ab2eSKashyap, Desai 		if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
16111ba9ab2eSKashyap, Desai 			printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
16121ba9ab2eSKashyap, Desai 			    "FAILED!!\n", ioc->name);
16131ba9ab2eSKashyap, Desai 		return 0;
16141ba9ab2eSKashyap, Desai 	}
16151ba9ab2eSKashyap, Desai 
16161ba9ab2eSKashyap, Desai 	if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
16171ba9ab2eSKashyap, Desai 		printk(MYIOC_s_WARN_FMT
16181ba9ab2eSKashyap, Desai 			"TaskMgmt type=%x: ioc_state: "
16191ba9ab2eSKashyap, Desai 			"DOORBELL_ACTIVE (0x%x)!\n",
16201ba9ab2eSKashyap, Desai 			ioc->name, type, ioc_raw_state);
16211ba9ab2eSKashyap, Desai 		return FAILED;
16221ba9ab2eSKashyap, Desai 	}
16231ba9ab2eSKashyap, Desai 
16241ba9ab2eSKashyap, Desai 	mutex_lock(&ioc->taskmgmt_cmds.mutex);
16251ba9ab2eSKashyap, Desai 	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
16261ba9ab2eSKashyap, Desai 		mf = NULL;
16271ba9ab2eSKashyap, Desai 		retval = FAILED;
16281ba9ab2eSKashyap, Desai 		goto out;
16291ba9ab2eSKashyap, Desai 	}
16301da177e4SLinus Torvalds 
16311da177e4SLinus Torvalds 	/* Return Fail to calling function if no message frames available.
16321da177e4SLinus Torvalds 	 */
1633e80b002bSEric Moore 	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
16341ba9ab2eSKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
16351ba9ab2eSKashyap, Desai 			"TaskMgmt no msg frames!!\n", ioc->name));
16361ba9ab2eSKashyap, Desai 		retval = FAILED;
16371ba9ab2eSKashyap, Desai 		mpt_clear_taskmgmt_in_progress_flag(ioc);
16381ba9ab2eSKashyap, Desai 		goto out;
16391da177e4SLinus Torvalds 	}
16401ba9ab2eSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1641e80b002bSEric Moore 			ioc->name, mf));
16421da177e4SLinus Torvalds 
16431da177e4SLinus Torvalds 	/* Format the Request
16441da177e4SLinus Torvalds 	 */
16451da177e4SLinus Torvalds 	pScsiTm = (SCSITaskMgmt_t *) mf;
1646793955f5SEric Moore 	pScsiTm->TargetID = id;
16471da177e4SLinus Torvalds 	pScsiTm->Bus = channel;
16481da177e4SLinus Torvalds 	pScsiTm->ChainOffset = 0;
16491da177e4SLinus Torvalds 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
16501da177e4SLinus Torvalds 
16511da177e4SLinus Torvalds 	pScsiTm->Reserved = 0;
16521da177e4SLinus Torvalds 	pScsiTm->TaskType = type;
16531da177e4SLinus Torvalds 	pScsiTm->Reserved1 = 0;
16541da177e4SLinus Torvalds 	pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
16551da177e4SLinus Torvalds                     ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
16561da177e4SLinus Torvalds 
1657793955f5SEric Moore 	int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
16581da177e4SLinus Torvalds 
16591da177e4SLinus Torvalds 	for (ii=0; ii < 7; ii++)
16601da177e4SLinus Torvalds 		pScsiTm->Reserved2[ii] = 0;
16611da177e4SLinus Torvalds 
16621da177e4SLinus Torvalds 	pScsiTm->TaskMsgContext = ctx2abort;
16631da177e4SLinus Torvalds 
16641ba9ab2eSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
16651ba9ab2eSKashyap, Desai 		"task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
16661ba9ab2eSKashyap, Desai 		type, timeout));
16671da177e4SLinus Torvalds 
16686757d6b4SPrakash, Sathya 	DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
16691da177e4SLinus Torvalds 
16701ba9ab2eSKashyap, Desai 	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
16711ba9ab2eSKashyap, Desai 	time_count = jiffies;
1672e80b002bSEric Moore 	if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1673e80b002bSEric Moore 	    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1674e80b002bSEric Moore 		mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
16757a195f46SPrakash, Sathya 	else {
1676e80b002bSEric Moore 		retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
16777a195f46SPrakash, Sathya 			sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
16787a195f46SPrakash, Sathya 		if (retval) {
16791ba9ab2eSKashyap, Desai 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
16801ba9ab2eSKashyap, Desai 				"TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
16811ba9ab2eSKashyap, Desai 				ioc->name, mf, retval));
1682e80b002bSEric Moore 			mpt_free_msg_frame(ioc, mf);
16831ba9ab2eSKashyap, Desai 			mpt_clear_taskmgmt_in_progress_flag(ioc);
16841ba9ab2eSKashyap, Desai 			goto out;
16851da177e4SLinus Torvalds 		}
16861ba9ab2eSKashyap, Desai 	}
16871ba9ab2eSKashyap, Desai 
16881ba9ab2eSKashyap, Desai 	timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
16891ba9ab2eSKashyap, Desai 		timeout*HZ);
16901ba9ab2eSKashyap, Desai 	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
16911ba9ab2eSKashyap, Desai 		retval = FAILED;
16921ba9ab2eSKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
16931ba9ab2eSKashyap, Desai 		    "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
16941ba9ab2eSKashyap, Desai 		mpt_clear_taskmgmt_in_progress_flag(ioc);
16951ba9ab2eSKashyap, Desai 		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
16961ba9ab2eSKashyap, Desai 			goto out;
16971ba9ab2eSKashyap, Desai 		issue_hard_reset = 1;
16981ba9ab2eSKashyap, Desai 		goto out;
16991ba9ab2eSKashyap, Desai 	}
17001ba9ab2eSKashyap, Desai 
17011ba9ab2eSKashyap, Desai 	retval = mptscsih_taskmgmt_reply(ioc, type,
17021ba9ab2eSKashyap, Desai 	    (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
17031ba9ab2eSKashyap, Desai 
17041ba9ab2eSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
17051ba9ab2eSKashyap, Desai 	    "TaskMgmt completed (%d seconds)\n",
17061ba9ab2eSKashyap, Desai 	    ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
17071ba9ab2eSKashyap, Desai 
17081ba9ab2eSKashyap, Desai  out:
17091ba9ab2eSKashyap, Desai 
17101ba9ab2eSKashyap, Desai 	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
17111ba9ab2eSKashyap, Desai 	if (issue_hard_reset) {
17121ba9ab2eSKashyap, Desai 		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
17131ba9ab2eSKashyap, Desai 			ioc->name, __func__);
17141ba9ab2eSKashyap, Desai 		retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
17151ba9ab2eSKashyap, Desai 		mpt_free_msg_frame(ioc, mf);
17161ba9ab2eSKashyap, Desai 	}
17171ba9ab2eSKashyap, Desai 
17181ba9ab2eSKashyap, Desai 	retval = (retval == 0) ? 0 : FAILED;
17191ba9ab2eSKashyap, Desai 	mutex_unlock(&ioc->taskmgmt_cmds.mutex);
17201ba9ab2eSKashyap, Desai 	return retval;
17211ba9ab2eSKashyap, Desai }
17221ba9ab2eSKashyap, Desai EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
17231da177e4SLinus Torvalds 
1724d66c7a0fSChristoph Hellwig static int
1725d66c7a0fSChristoph Hellwig mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1726d66c7a0fSChristoph Hellwig {
1727d66c7a0fSChristoph Hellwig 	switch (ioc->bus_type) {
1728d66c7a0fSChristoph Hellwig 	case FC:
1729d66c7a0fSChristoph Hellwig 		return 40;
1730d66c7a0fSChristoph Hellwig 	case SAS:
1731d66c7a0fSChristoph Hellwig 	case SPI:
1732d66c7a0fSChristoph Hellwig 	default:
173322ab019bSBernd Schubert 		return 10;
1734d66c7a0fSChristoph Hellwig 	}
1735d66c7a0fSChristoph Hellwig }
1736d66c7a0fSChristoph Hellwig 
17371da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
17381da177e4SLinus Torvalds /**
17391da177e4SLinus Torvalds  *	mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
17401da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
17411da177e4SLinus Torvalds  *
17421da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_abort_handler routine)
17431da177e4SLinus Torvalds  *
17441da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
1745cd2c6191SEric Moore  **/
17460d0c7974SMoore, Eric Dean  int
17471da177e4SLinus Torvalds mptscsih_abort(struct scsi_cmnd * SCpnt)
17481da177e4SLinus Torvalds {
17491da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
17501da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
17511da177e4SLinus Torvalds 	u32		 ctx2abort;
17521da177e4SLinus Torvalds 	int		 scpnt_idx;
1753466544d8SMoore, Eric Dean 	int		 retval;
1754958d4a32SEric Moore 	VirtDevice	 *vdevice;
17553dc0b03fSEric Moore 	ulong	 	 sn = SCpnt->serial_number;
1756958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
17571da177e4SLinus Torvalds 
17581da177e4SLinus Torvalds 	/* If we can't locate our host adapter structure, return FAILED status.
17591da177e4SLinus Torvalds 	 */
1760e7eae9f6SEric Moore 	if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
17611da177e4SLinus Torvalds 		SCpnt->result = DID_RESET << 16;
17621da177e4SLinus Torvalds 		SCpnt->scsi_done(SCpnt);
176329dd3609SEric Moore 		printk(KERN_ERR MYNAM ": task abort: "
176429dd3609SEric Moore 		    "can't locate host! (sc=%p)\n", SCpnt);
17651da177e4SLinus Torvalds 		return FAILED;
17661da177e4SLinus Torvalds 	}
17671da177e4SLinus Torvalds 
1768958d4a32SEric Moore 	ioc = hd->ioc;
1769958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1770958d4a32SEric Moore 	       ioc->name, SCpnt);
1771958d4a32SEric Moore 	scsi_print_command(SCpnt);
1772958d4a32SEric Moore 
1773958d4a32SEric Moore 	vdevice = SCpnt->device->hostdata;
1774958d4a32SEric Moore 	if (!vdevice || !vdevice->vtarget) {
177529dd3609SEric Moore 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
177629dd3609SEric Moore 		    "task abort: device has been deleted (sc=%p)\n",
177729dd3609SEric Moore 		    ioc->name, SCpnt));
1778958d4a32SEric Moore 		SCpnt->result = DID_NO_CONNECT << 16;
1779958d4a32SEric Moore 		SCpnt->scsi_done(SCpnt);
1780958d4a32SEric Moore 		retval = 0;
1781958d4a32SEric Moore 		goto out;
1782958d4a32SEric Moore 	}
1783958d4a32SEric Moore 
1784cc78d30aSEric Moore 	/* Task aborts are not supported for hidden raid components.
1785cc78d30aSEric Moore 	 */
1786cc78d30aSEric Moore 	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
178729dd3609SEric Moore 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
178829dd3609SEric Moore 		    "task abort: hidden raid component (sc=%p)\n",
178929dd3609SEric Moore 		    ioc->name, SCpnt));
1790cc78d30aSEric Moore 		SCpnt->result = DID_RESET << 16;
1791cc78d30aSEric Moore 		retval = FAILED;
1792cc78d30aSEric Moore 		goto out;
1793cc78d30aSEric Moore 	}
1794cc78d30aSEric Moore 
17951da177e4SLinus Torvalds 	/* Find this command
17961da177e4SLinus Torvalds 	 */
1797e8206381SEric Moore 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
17981da177e4SLinus Torvalds 		/* Cmd not found in ScsiLookup.
17991da177e4SLinus Torvalds 		 * Do OS callback.
18001da177e4SLinus Torvalds 		 */
18011da177e4SLinus Torvalds 		SCpnt->result = DID_RESET << 16;
180229dd3609SEric Moore 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
1803958d4a32SEric Moore 		   "Command not in the active list! (sc=%p)\n", ioc->name,
1804958d4a32SEric Moore 		   SCpnt));
18059858ae38SKashyap, Desai 		retval = SUCCESS;
1806958d4a32SEric Moore 		goto out;
18071da177e4SLinus Torvalds 	}
18081da177e4SLinus Torvalds 
18092f187862SKashyap, Desai 	if (ioc->timeouts < -1)
18102f187862SKashyap, Desai 		ioc->timeouts++;
181165207fedSMoore, Eric 
18122f4c782cSKashyap, Desai 	if (mpt_fwfault_debug)
18132f4c782cSKashyap, Desai 		mpt_halt_firmware(ioc);
18142f4c782cSKashyap, Desai 
18151da177e4SLinus Torvalds 	/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
18161da177e4SLinus Torvalds 	 * (the IO to be ABORT'd)
18171da177e4SLinus Torvalds 	 *
18181da177e4SLinus Torvalds 	 * NOTE: Since we do not byteswap MsgContext, we do not
18191da177e4SLinus Torvalds 	 *	 swap it here either.  It is an opaque cookie to
18201da177e4SLinus Torvalds 	 *	 the controller, so it does not matter. -DaveM
18211da177e4SLinus Torvalds 	 */
1822e80b002bSEric Moore 	mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
18231da177e4SLinus Torvalds 	ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
18241ba9ab2eSKashyap, Desai 	retval = mptscsih_IssueTaskMgmt(hd,
18251ba9ab2eSKashyap, Desai 			 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
18261ba9ab2eSKashyap, Desai 			 vdevice->vtarget->channel,
18271ba9ab2eSKashyap, Desai 			 vdevice->vtarget->id, vdevice->lun,
1828958d4a32SEric Moore 			 ctx2abort, mptscsih_get_tm_timeout(ioc));
18291da177e4SLinus Torvalds 
1830e8206381SEric Moore 	if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
18312f187862SKashyap, Desai 	    SCpnt->serial_number == sn) {
18322f187862SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
18332f187862SKashyap, Desai 		    "task abort: command still in active list! (sc=%p)\n",
18342f187862SKashyap, Desai 		    ioc->name, SCpnt));
18353dc0b03fSEric Moore 		retval = FAILED;
18362f187862SKashyap, Desai 	} else {
18372f187862SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
18382f187862SKashyap, Desai 		    "task abort: command cleared from active list! (sc=%p)\n",
18392f187862SKashyap, Desai 		    ioc->name, SCpnt));
18402f187862SKashyap, Desai 		retval = SUCCESS;
18412f187862SKashyap, Desai 	}
18423dc0b03fSEric Moore 
1843958d4a32SEric Moore  out:
1844958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
18452f187862SKashyap, Desai 	    ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt);
18461da177e4SLinus Torvalds 
18472f187862SKashyap, Desai 	return retval;
18481da177e4SLinus Torvalds }
18491da177e4SLinus Torvalds 
18501da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
18511da177e4SLinus Torvalds /**
18521da177e4SLinus Torvalds  *	mptscsih_dev_reset - Perform a SCSI TARGET_RESET!  new_eh variant
18531da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
18541da177e4SLinus Torvalds  *
18551da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_dev_reset_handler routine)
18561da177e4SLinus Torvalds  *
18571da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
1858cd2c6191SEric Moore  **/
18590d0c7974SMoore, Eric Dean  int
18601da177e4SLinus Torvalds mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
18611da177e4SLinus Torvalds {
18621da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
1863466544d8SMoore, Eric Dean 	int		 retval;
1864958d4a32SEric Moore 	VirtDevice	 *vdevice;
1865958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
18661da177e4SLinus Torvalds 
18671da177e4SLinus Torvalds 	/* If we can't locate our host adapter structure, return FAILED status.
18681da177e4SLinus Torvalds 	 */
1869e7eae9f6SEric Moore 	if ((hd = shost_priv(SCpnt->device->host)) == NULL){
187029dd3609SEric Moore 		printk(KERN_ERR MYNAM ": target reset: "
187129dd3609SEric Moore 		   "Can't locate host! (sc=%p)\n", SCpnt);
18721da177e4SLinus Torvalds 		return FAILED;
18731da177e4SLinus Torvalds 	}
18741da177e4SLinus Torvalds 
1875958d4a32SEric Moore 	ioc = hd->ioc;
1876958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1877958d4a32SEric Moore 	       ioc->name, SCpnt);
1878466544d8SMoore, Eric Dean 	scsi_print_command(SCpnt);
18791da177e4SLinus Torvalds 
1880958d4a32SEric Moore 	vdevice = SCpnt->device->hostdata;
1881958d4a32SEric Moore 	if (!vdevice || !vdevice->vtarget) {
18822f187862SKashyap, Desai 		retval = SUCCESS;
1883958d4a32SEric Moore 		goto out;
1884958d4a32SEric Moore 	}
1885958d4a32SEric Moore 
1886cc78d30aSEric Moore 	/* Target reset to hidden raid component is not supported
1887cc78d30aSEric Moore 	 */
1888cc78d30aSEric Moore 	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1889cc78d30aSEric Moore 		retval = FAILED;
1890cc78d30aSEric Moore 		goto out;
1891cc78d30aSEric Moore 	}
1892cc78d30aSEric Moore 
18931ba9ab2eSKashyap, Desai 	retval = mptscsih_IssueTaskMgmt(hd,
18941ba9ab2eSKashyap, Desai 				MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
18951ba9ab2eSKashyap, Desai 				vdevice->vtarget->channel,
18961ba9ab2eSKashyap, Desai 				vdevice->vtarget->id, 0, 0,
1897958d4a32SEric Moore 				mptscsih_get_tm_timeout(ioc));
1898958d4a32SEric Moore 
1899958d4a32SEric Moore  out:
1900958d4a32SEric Moore 	printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1901958d4a32SEric Moore 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1902466544d8SMoore, Eric Dean 
1903466544d8SMoore, Eric Dean 	if (retval == 0)
1904466544d8SMoore, Eric Dean 		return SUCCESS;
1905cd2c6191SEric Moore 	else
1906466544d8SMoore, Eric Dean 		return FAILED;
19071da177e4SLinus Torvalds }
19081da177e4SLinus Torvalds 
1909cd2c6191SEric Moore 
19101da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
19111da177e4SLinus Torvalds /**
19121da177e4SLinus Torvalds  *	mptscsih_bus_reset - Perform a SCSI BUS_RESET!	new_eh variant
19131da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
19141da177e4SLinus Torvalds  *
19151da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_bus_reset_handler routine)
19161da177e4SLinus Torvalds  *
19171da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
1918cd2c6191SEric Moore  **/
19190d0c7974SMoore, Eric Dean  int
19201da177e4SLinus Torvalds mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
19211da177e4SLinus Torvalds {
19221da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
1923466544d8SMoore, Eric Dean 	int		 retval;
1924a69de507SEric Moore 	VirtDevice	 *vdevice;
1925958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
19261da177e4SLinus Torvalds 
19271da177e4SLinus Torvalds 	/* If we can't locate our host adapter structure, return FAILED status.
19281da177e4SLinus Torvalds 	 */
1929e7eae9f6SEric Moore 	if ((hd = shost_priv(SCpnt->device->host)) == NULL){
193029dd3609SEric Moore 		printk(KERN_ERR MYNAM ": bus reset: "
193129dd3609SEric Moore 		   "Can't locate host! (sc=%p)\n", SCpnt);
19321da177e4SLinus Torvalds 		return FAILED;
19331da177e4SLinus Torvalds 	}
19341da177e4SLinus Torvalds 
1935958d4a32SEric Moore 	ioc = hd->ioc;
1936958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1937958d4a32SEric Moore 	       ioc->name, SCpnt);
1938466544d8SMoore, Eric Dean 	scsi_print_command(SCpnt);
19391da177e4SLinus Torvalds 
19402f187862SKashyap, Desai 	if (ioc->timeouts < -1)
19412f187862SKashyap, Desai 		ioc->timeouts++;
19421da177e4SLinus Torvalds 
1943a69de507SEric Moore 	vdevice = SCpnt->device->hostdata;
19442f187862SKashyap, Desai 	if (!vdevice || !vdevice->vtarget)
19452f187862SKashyap, Desai 		return SUCCESS;
19461ba9ab2eSKashyap, Desai 	retval = mptscsih_IssueTaskMgmt(hd,
19471ba9ab2eSKashyap, Desai 					MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
19481ba9ab2eSKashyap, Desai 					vdevice->vtarget->channel, 0, 0, 0,
19491ba9ab2eSKashyap, Desai 					mptscsih_get_tm_timeout(ioc));
19501da177e4SLinus Torvalds 
1951958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1952958d4a32SEric Moore 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1953466544d8SMoore, Eric Dean 
1954466544d8SMoore, Eric Dean 	if (retval == 0)
1955466544d8SMoore, Eric Dean 		return SUCCESS;
1956cd2c6191SEric Moore 	else
1957466544d8SMoore, Eric Dean 		return FAILED;
19581da177e4SLinus Torvalds }
19591da177e4SLinus Torvalds 
19601da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
19611da177e4SLinus Torvalds /**
1962d9489fb6SRandy Dunlap  *	mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
19631da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
19641da177e4SLinus Torvalds  *
19651da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_host_reset_handler routine)
19661da177e4SLinus Torvalds  *
19671da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
19681da177e4SLinus Torvalds  */
19690d0c7974SMoore, Eric Dean  int
19701da177e4SLinus Torvalds mptscsih_host_reset(struct scsi_cmnd *SCpnt)
19711da177e4SLinus Torvalds {
19721da177e4SLinus Torvalds 	MPT_SCSI_HOST *  hd;
19732f187862SKashyap, Desai 	int              status = SUCCESS;
1974958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
19752f187862SKashyap, Desai 	int		retval;
19761da177e4SLinus Torvalds 
19771da177e4SLinus Torvalds 	/*  If we can't locate the host to reset, then we failed. */
1978e7eae9f6SEric Moore 	if ((hd = shost_priv(SCpnt->device->host)) == NULL){
197929dd3609SEric Moore 		printk(KERN_ERR MYNAM ": host reset: "
198029dd3609SEric Moore 		    "Can't locate host! (sc=%p)\n", SCpnt);
19811da177e4SLinus Torvalds 		return FAILED;
19821da177e4SLinus Torvalds 	}
19831da177e4SLinus Torvalds 
1984a6da74cbSJames Bottomley 	/* make sure we have no outstanding commands at this stage */
1985a6da74cbSJames Bottomley 	mptscsih_flush_running_cmds(hd);
1986a6da74cbSJames Bottomley 
1987958d4a32SEric Moore 	ioc = hd->ioc;
1988958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1989958d4a32SEric Moore 	    ioc->name, SCpnt);
19901da177e4SLinus Torvalds 
19911da177e4SLinus Torvalds 	/*  If our attempts to reset the host failed, then return a failed
19921da177e4SLinus Torvalds 	 *  status.  The host will be taken off line by the SCSI mid-layer.
19931da177e4SLinus Torvalds 	 */
19942f187862SKashyap, Desai     retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
19952f187862SKashyap, Desai 	if (retval < 0)
19962f187862SKashyap, Desai 		status = FAILED;
19972f187862SKashyap, Desai 	else
19982f187862SKashyap, Desai 		status = SUCCESS;
19991da177e4SLinus Torvalds 
2000958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
2001958d4a32SEric Moore 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
20021da177e4SLinus Torvalds 
20032f187862SKashyap, Desai 	return status;
20041da177e4SLinus Torvalds }
20051da177e4SLinus Torvalds 
20061da177e4SLinus Torvalds static int
20071ba9ab2eSKashyap, Desai mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
20081ba9ab2eSKashyap, Desai 	SCSITaskMgmtReply_t *pScsiTmReply)
20091da177e4SLinus Torvalds {
20101ba9ab2eSKashyap, Desai 	u16			 iocstatus;
20111ba9ab2eSKashyap, Desai 	u32			 termination_count;
20121ba9ab2eSKashyap, Desai 	int			 retval;
20131da177e4SLinus Torvalds 
20141ba9ab2eSKashyap, Desai 	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
20151ba9ab2eSKashyap, Desai 		retval = FAILED;
20161ba9ab2eSKashyap, Desai 		goto out;
20171da177e4SLinus Torvalds 	}
20181da177e4SLinus Torvalds 
20191ba9ab2eSKashyap, Desai 	DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
20201da177e4SLinus Torvalds 
20211ba9ab2eSKashyap, Desai 	iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
20221ba9ab2eSKashyap, Desai 	termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
20231ba9ab2eSKashyap, Desai 
20241ba9ab2eSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
20251ba9ab2eSKashyap, Desai 	    "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
20261ba9ab2eSKashyap, Desai 	    "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
20271ba9ab2eSKashyap, Desai 	    "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
20281ba9ab2eSKashyap, Desai 	    pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
20291ba9ab2eSKashyap, Desai 	    le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
20301ba9ab2eSKashyap, Desai 	    termination_count));
20311ba9ab2eSKashyap, Desai 
20321ba9ab2eSKashyap, Desai 	if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
20331ba9ab2eSKashyap, Desai 	    pScsiTmReply->ResponseCode)
20341ba9ab2eSKashyap, Desai 		mptscsih_taskmgmt_response_code(ioc,
20351ba9ab2eSKashyap, Desai 		    pScsiTmReply->ResponseCode);
20361ba9ab2eSKashyap, Desai 
20371ba9ab2eSKashyap, Desai 	if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
20381ba9ab2eSKashyap, Desai 		retval = 0;
20391ba9ab2eSKashyap, Desai 		goto out;
20401da177e4SLinus Torvalds 	}
20411da177e4SLinus Torvalds 
20421ba9ab2eSKashyap, Desai 	retval = FAILED;
20431ba9ab2eSKashyap, Desai 	if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
20441ba9ab2eSKashyap, Desai 		if (termination_count == 1)
20451ba9ab2eSKashyap, Desai 			retval = 0;
20461ba9ab2eSKashyap, Desai 		goto out;
20471ba9ab2eSKashyap, Desai 	}
20481ba9ab2eSKashyap, Desai 
20491ba9ab2eSKashyap, Desai 	if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
20501ba9ab2eSKashyap, Desai 	   iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
20511ba9ab2eSKashyap, Desai 		retval = 0;
20521ba9ab2eSKashyap, Desai 
20531ba9ab2eSKashyap, Desai  out:
20541ba9ab2eSKashyap, Desai 	return retval;
20551da177e4SLinus Torvalds }
20561da177e4SLinus Torvalds 
20571da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2058e7deff33SKashyap, Desai void
20599f63bb73SMoore, Eric mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
20609f63bb73SMoore, Eric {
20619f63bb73SMoore, Eric 	char *desc;
20629f63bb73SMoore, Eric 
20639f63bb73SMoore, Eric 	switch (response_code) {
20649f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
20659f63bb73SMoore, Eric 		desc = "The task completed.";
20669f63bb73SMoore, Eric 		break;
20679f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
20689f63bb73SMoore, Eric 		desc = "The IOC received an invalid frame status.";
20699f63bb73SMoore, Eric 		break;
20709f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
20719f63bb73SMoore, Eric 		desc = "The task type is not supported.";
20729f63bb73SMoore, Eric 		break;
20739f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_FAILED:
20749f63bb73SMoore, Eric 		desc = "The requested task failed.";
20759f63bb73SMoore, Eric 		break;
20769f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
20779f63bb73SMoore, Eric 		desc = "The task completed successfully.";
20789f63bb73SMoore, Eric 		break;
20799f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
20809f63bb73SMoore, Eric 		desc = "The LUN request is invalid.";
20819f63bb73SMoore, Eric 		break;
20829f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
20839f63bb73SMoore, Eric 		desc = "The task is in the IOC queue and has not been sent to target.";
20849f63bb73SMoore, Eric 		break;
20859f63bb73SMoore, Eric 	default:
20869f63bb73SMoore, Eric 		desc = "unknown";
20879f63bb73SMoore, Eric 		break;
20889f63bb73SMoore, Eric 	}
20899f63bb73SMoore, Eric 	printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
20909f63bb73SMoore, Eric 		ioc->name, response_code, desc);
20919f63bb73SMoore, Eric }
2092e7deff33SKashyap, Desai EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
20939f63bb73SMoore, Eric 
20949f63bb73SMoore, Eric /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
20951da177e4SLinus Torvalds /**
20961da177e4SLinus Torvalds  *	mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
20971da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
20981da177e4SLinus Torvalds  *	@mf: Pointer to SCSI task mgmt request frame
20991da177e4SLinus Torvalds  *	@mr: Pointer to SCSI task mgmt reply frame
21001da177e4SLinus Torvalds  *
21011da177e4SLinus Torvalds  *	This routine is called from mptbase.c::mpt_interrupt() at the completion
21021da177e4SLinus Torvalds  *	of any SCSI task management request.
21031da177e4SLinus Torvalds  *	This routine is registered with the MPT (base) driver at driver
21041da177e4SLinus Torvalds  *	load/init time via the mpt_register() API call.
21051da177e4SLinus Torvalds  *
21061da177e4SLinus Torvalds  *	Returns 1 indicating alloc'd request frame ptr should be freed.
2107cd2c6191SEric Moore  **/
21080d0c7974SMoore, Eric Dean  int
21091ba9ab2eSKashyap, Desai mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
21101ba9ab2eSKashyap, Desai 	MPT_FRAME_HDR *mr)
21111da177e4SLinus Torvalds {
21121ba9ab2eSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
21131ba9ab2eSKashyap, Desai 		"TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
21141da177e4SLinus Torvalds 
21151ba9ab2eSKashyap, Desai 	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
21161da177e4SLinus Torvalds 
21171ba9ab2eSKashyap, Desai 	if (!mr)
2118cd2c6191SEric Moore 		goto out;
2119cd2c6191SEric Moore 
21201ba9ab2eSKashyap, Desai 	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
21211ba9ab2eSKashyap, Desai 	memcpy(ioc->taskmgmt_cmds.reply, mr,
21221ba9ab2eSKashyap, Desai 	    min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
2123cd2c6191SEric Moore  out:
21241ba9ab2eSKashyap, Desai 	if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
21251ba9ab2eSKashyap, Desai 		mpt_clear_taskmgmt_in_progress_flag(ioc);
21261ba9ab2eSKashyap, Desai 		ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
21271ba9ab2eSKashyap, Desai 		complete(&ioc->taskmgmt_cmds.done);
21281da177e4SLinus Torvalds 		return 1;
21291da177e4SLinus Torvalds 	}
21301ba9ab2eSKashyap, Desai 	return 0;
21311ba9ab2eSKashyap, Desai }
21321da177e4SLinus Torvalds 
21331da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
21341da177e4SLinus Torvalds /*
21351da177e4SLinus Torvalds  *	This is anyones guess quite frankly.
21361da177e4SLinus Torvalds  */
21370d0c7974SMoore, Eric Dean  int
21381da177e4SLinus Torvalds mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
21391da177e4SLinus Torvalds 		sector_t capacity, int geom[])
21401da177e4SLinus Torvalds {
21411da177e4SLinus Torvalds 	int		heads;
21421da177e4SLinus Torvalds 	int		sectors;
21431da177e4SLinus Torvalds 	sector_t	cylinders;
21441da177e4SLinus Torvalds 	ulong 		dummy;
21451da177e4SLinus Torvalds 
21461da177e4SLinus Torvalds 	heads = 64;
21471da177e4SLinus Torvalds 	sectors = 32;
21481da177e4SLinus Torvalds 
21491da177e4SLinus Torvalds 	dummy = heads * sectors;
21501da177e4SLinus Torvalds 	cylinders = capacity;
21511da177e4SLinus Torvalds 	sector_div(cylinders,dummy);
21521da177e4SLinus Torvalds 
21531da177e4SLinus Torvalds 	/*
21541da177e4SLinus Torvalds 	 * Handle extended translation size for logical drives
21551da177e4SLinus Torvalds 	 * > 1Gb
21561da177e4SLinus Torvalds 	 */
21571da177e4SLinus Torvalds 	if ((ulong)capacity >= 0x200000) {
21581da177e4SLinus Torvalds 		heads = 255;
21591da177e4SLinus Torvalds 		sectors = 63;
21601da177e4SLinus Torvalds 		dummy = heads * sectors;
21611da177e4SLinus Torvalds 		cylinders = capacity;
21621da177e4SLinus Torvalds 		sector_div(cylinders,dummy);
21631da177e4SLinus Torvalds 	}
21641da177e4SLinus Torvalds 
21651da177e4SLinus Torvalds 	/* return result */
21661da177e4SLinus Torvalds 	geom[0] = heads;
21671da177e4SLinus Torvalds 	geom[1] = sectors;
21681da177e4SLinus Torvalds 	geom[2] = cylinders;
21691da177e4SLinus Torvalds 
21701da177e4SLinus Torvalds 	return 0;
21711da177e4SLinus Torvalds }
21721da177e4SLinus Torvalds 
2173f44e5461SMoore, Eric /* Search IOC page 3 to determine if this is hidden physical disk
2174f44e5461SMoore, Eric  *
2175f44e5461SMoore, Eric  */
2176f44e5461SMoore, Eric int
2177793955f5SEric Moore mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
2178f44e5461SMoore, Eric {
2179b506ade9SEric Moore 	struct inactive_raid_component_info *component_info;
2180a7938b0bSKashyap, Desai 	int i, j;
2181a7938b0bSKashyap, Desai 	RaidPhysDiskPage1_t *phys_disk;
2182793955f5SEric Moore 	int rc = 0;
2183a7938b0bSKashyap, Desai 	int num_paths;
2184f44e5461SMoore, Eric 
2185793955f5SEric Moore 	if (!ioc->raid_data.pIocPg3)
2186793955f5SEric Moore 		goto out;
2187f44e5461SMoore, Eric 	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2188793955f5SEric Moore 		if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2189793955f5SEric Moore 		    (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2190793955f5SEric Moore 			rc = 1;
2191793955f5SEric Moore 			goto out;
2192f44e5461SMoore, Eric 		}
2193793955f5SEric Moore 	}
2194793955f5SEric Moore 
2195a7938b0bSKashyap, Desai 	if (ioc->bus_type != SAS)
2196a7938b0bSKashyap, Desai 		goto out;
2197a7938b0bSKashyap, Desai 
2198a7938b0bSKashyap, Desai 	/*
2199a7938b0bSKashyap, Desai 	 * Check if dual path
2200a7938b0bSKashyap, Desai 	 */
2201a7938b0bSKashyap, Desai 	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2202a7938b0bSKashyap, Desai 		num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2203a7938b0bSKashyap, Desai 		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2204a7938b0bSKashyap, Desai 		if (num_paths < 2)
2205a7938b0bSKashyap, Desai 			continue;
2206a7938b0bSKashyap, Desai 		phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2207a7938b0bSKashyap, Desai 		   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2208a7938b0bSKashyap, Desai 		if (!phys_disk)
2209a7938b0bSKashyap, Desai 			continue;
2210a7938b0bSKashyap, Desai 		if ((mpt_raid_phys_disk_pg1(ioc,
2211a7938b0bSKashyap, Desai 		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2212a7938b0bSKashyap, Desai 		    phys_disk))) {
2213a7938b0bSKashyap, Desai 			kfree(phys_disk);
2214a7938b0bSKashyap, Desai 			continue;
2215a7938b0bSKashyap, Desai 		}
2216a7938b0bSKashyap, Desai 		for (j = 0; j < num_paths; j++) {
2217a7938b0bSKashyap, Desai 			if ((phys_disk->Path[j].Flags &
2218a7938b0bSKashyap, Desai 			    MPI_RAID_PHYSDISK1_FLAG_INVALID))
2219a7938b0bSKashyap, Desai 				continue;
2220a7938b0bSKashyap, Desai 			if ((phys_disk->Path[j].Flags &
2221a7938b0bSKashyap, Desai 			    MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2222a7938b0bSKashyap, Desai 				continue;
2223a7938b0bSKashyap, Desai 			if ((id == phys_disk->Path[j].PhysDiskID) &&
2224a7938b0bSKashyap, Desai 			    (channel == phys_disk->Path[j].PhysDiskBus)) {
2225a7938b0bSKashyap, Desai 				rc = 1;
2226a7938b0bSKashyap, Desai 				kfree(phys_disk);
2227a7938b0bSKashyap, Desai 				goto out;
2228a7938b0bSKashyap, Desai 			}
2229a7938b0bSKashyap, Desai 		}
2230a7938b0bSKashyap, Desai 		kfree(phys_disk);
2231a7938b0bSKashyap, Desai 	}
2232a7938b0bSKashyap, Desai 
2233a7938b0bSKashyap, Desai 
2234b506ade9SEric Moore 	/*
2235b506ade9SEric Moore 	 * Check inactive list for matching phys disks
2236b506ade9SEric Moore 	 */
2237b506ade9SEric Moore 	if (list_empty(&ioc->raid_data.inactive_list))
2238b506ade9SEric Moore 		goto out;
2239b506ade9SEric Moore 
2240ed5f606fSMatthias Kaehlcke 	mutex_lock(&ioc->raid_data.inactive_list_mutex);
2241b506ade9SEric Moore 	list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2242b506ade9SEric Moore 	    list) {
2243b506ade9SEric Moore 		if ((component_info->d.PhysDiskID == id) &&
2244b506ade9SEric Moore 		    (component_info->d.PhysDiskBus == channel))
2245b506ade9SEric Moore 			rc = 1;
2246b506ade9SEric Moore 	}
2247ed5f606fSMatthias Kaehlcke 	mutex_unlock(&ioc->raid_data.inactive_list_mutex);
2248b506ade9SEric Moore 
2249793955f5SEric Moore  out:
2250793955f5SEric Moore 	return rc;
2251f44e5461SMoore, Eric }
2252f44e5461SMoore, Eric EXPORT_SYMBOL(mptscsih_is_phys_disk);
2253f44e5461SMoore, Eric 
2254793955f5SEric Moore u8
2255793955f5SEric Moore mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2256c92f222eSJames Bottomley {
2257b506ade9SEric Moore 	struct inactive_raid_component_info *component_info;
2258a7938b0bSKashyap, Desai 	int i, j;
2259a7938b0bSKashyap, Desai 	RaidPhysDiskPage1_t *phys_disk;
2260793955f5SEric Moore 	int rc = -ENXIO;
2261a7938b0bSKashyap, Desai 	int num_paths;
2262c92f222eSJames Bottomley 
2263793955f5SEric Moore 	if (!ioc->raid_data.pIocPg3)
2264793955f5SEric Moore 		goto out;
2265793955f5SEric Moore 	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2266793955f5SEric Moore 		if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2267793955f5SEric Moore 		    (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2268793955f5SEric Moore 			rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2269793955f5SEric Moore 			goto out;
2270793955f5SEric Moore 		}
2271c92f222eSJames Bottomley 	}
2272c92f222eSJames Bottomley 
2273a7938b0bSKashyap, Desai 	if (ioc->bus_type != SAS)
2274a7938b0bSKashyap, Desai 		goto out;
2275a7938b0bSKashyap, Desai 
2276a7938b0bSKashyap, Desai 	/*
2277a7938b0bSKashyap, Desai 	 * Check if dual path
2278a7938b0bSKashyap, Desai 	 */
2279a7938b0bSKashyap, Desai 	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2280a7938b0bSKashyap, Desai 		num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2281a7938b0bSKashyap, Desai 		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2282a7938b0bSKashyap, Desai 		if (num_paths < 2)
2283a7938b0bSKashyap, Desai 			continue;
2284a7938b0bSKashyap, Desai 		phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2285a7938b0bSKashyap, Desai 		   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2286a7938b0bSKashyap, Desai 		if (!phys_disk)
2287a7938b0bSKashyap, Desai 			continue;
2288a7938b0bSKashyap, Desai 		if ((mpt_raid_phys_disk_pg1(ioc,
2289a7938b0bSKashyap, Desai 		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2290a7938b0bSKashyap, Desai 		    phys_disk))) {
2291a7938b0bSKashyap, Desai 			kfree(phys_disk);
2292a7938b0bSKashyap, Desai 			continue;
2293a7938b0bSKashyap, Desai 		}
2294a7938b0bSKashyap, Desai 		for (j = 0; j < num_paths; j++) {
2295a7938b0bSKashyap, Desai 			if ((phys_disk->Path[j].Flags &
2296a7938b0bSKashyap, Desai 			    MPI_RAID_PHYSDISK1_FLAG_INVALID))
2297a7938b0bSKashyap, Desai 				continue;
2298a7938b0bSKashyap, Desai 			if ((phys_disk->Path[j].Flags &
2299a7938b0bSKashyap, Desai 			    MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2300a7938b0bSKashyap, Desai 				continue;
2301a7938b0bSKashyap, Desai 			if ((id == phys_disk->Path[j].PhysDiskID) &&
2302a7938b0bSKashyap, Desai 			    (channel == phys_disk->Path[j].PhysDiskBus)) {
2303a7938b0bSKashyap, Desai 				rc = phys_disk->PhysDiskNum;
2304a7938b0bSKashyap, Desai 				kfree(phys_disk);
2305a7938b0bSKashyap, Desai 				goto out;
2306a7938b0bSKashyap, Desai 			}
2307a7938b0bSKashyap, Desai 		}
2308a7938b0bSKashyap, Desai 		kfree(phys_disk);
2309a7938b0bSKashyap, Desai 	}
2310a7938b0bSKashyap, Desai 
2311b506ade9SEric Moore 	/*
2312b506ade9SEric Moore 	 * Check inactive list for matching phys disks
2313b506ade9SEric Moore 	 */
2314b506ade9SEric Moore 	if (list_empty(&ioc->raid_data.inactive_list))
2315b506ade9SEric Moore 		goto out;
2316b506ade9SEric Moore 
2317ed5f606fSMatthias Kaehlcke 	mutex_lock(&ioc->raid_data.inactive_list_mutex);
2318b506ade9SEric Moore 	list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2319b506ade9SEric Moore 	    list) {
2320b506ade9SEric Moore 		if ((component_info->d.PhysDiskID == id) &&
2321b506ade9SEric Moore 		    (component_info->d.PhysDiskBus == channel))
2322b506ade9SEric Moore 			rc = component_info->d.PhysDiskNum;
2323b506ade9SEric Moore 	}
2324ed5f606fSMatthias Kaehlcke 	mutex_unlock(&ioc->raid_data.inactive_list_mutex);
2325b506ade9SEric Moore 
2326793955f5SEric Moore  out:
2327793955f5SEric Moore 	return rc;
2328c92f222eSJames Bottomley }
2329c92f222eSJames Bottomley EXPORT_SYMBOL(mptscsih_raid_id_to_num);
2330c92f222eSJames Bottomley 
2331c7c82987SMoore, Eric Dean /*
2332c7c82987SMoore, Eric Dean  *	OS entry point to allow for host driver to free allocated memory
2333c7c82987SMoore, Eric Dean  *	Called if no device present or device being unloaded
2334c7c82987SMoore, Eric Dean  */
2335c7c82987SMoore, Eric Dean void
2336c7c82987SMoore, Eric Dean mptscsih_slave_destroy(struct scsi_device *sdev)
2337c7c82987SMoore, Eric Dean {
2338c7c82987SMoore, Eric Dean 	struct Scsi_Host	*host = sdev->host;
2339e7eae9f6SEric Moore 	MPT_SCSI_HOST		*hd = shost_priv(host);
2340c7c82987SMoore, Eric Dean 	VirtTarget		*vtarget;
2341c7c82987SMoore, Eric Dean 	VirtDevice		*vdevice;
2342c7c82987SMoore, Eric Dean 	struct scsi_target 	*starget;
23431da177e4SLinus Torvalds 
2344c7c82987SMoore, Eric Dean 	starget = scsi_target(sdev);
2345c7c82987SMoore, Eric Dean 	vtarget = starget->hostdata;
2346c7c82987SMoore, Eric Dean 	vdevice = sdev->hostdata;
23471da177e4SLinus Torvalds 
2348c7c82987SMoore, Eric Dean 	mptscsih_search_running_cmds(hd, vdevice);
2349c7c82987SMoore, Eric Dean 	vtarget->num_luns--;
2350c7c82987SMoore, Eric Dean 	mptscsih_synchronize_cache(hd, vdevice);
2351c7c82987SMoore, Eric Dean 	kfree(vdevice);
2352c7c82987SMoore, Eric Dean 	sdev->hostdata = NULL;
23531da177e4SLinus Torvalds }
23541da177e4SLinus Torvalds 
23556e3815baSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
23566e3815baSMoore, Eric Dean /*
23576e3815baSMoore, Eric Dean  *	mptscsih_change_queue_depth - This function will set a devices queue depth
23586e3815baSMoore, Eric Dean  *	@sdev: per scsi_device pointer
23596e3815baSMoore, Eric Dean  *	@qdepth: requested queue depth
2360e881a172SMike Christie  *	@reason: calling context
23616e3815baSMoore, Eric Dean  *
23626e3815baSMoore, Eric Dean  *	Adding support for new 'change_queue_depth' api.
23636e3815baSMoore, Eric Dean */
23646e3815baSMoore, Eric Dean int
2365e881a172SMike Christie mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
23661da177e4SLinus Torvalds {
2367e7eae9f6SEric Moore 	MPT_SCSI_HOST		*hd = shost_priv(sdev->host);
2368c7c82987SMoore, Eric Dean 	VirtTarget 		*vtarget;
2369c7c82987SMoore, Eric Dean 	struct scsi_target 	*starget;
23701da177e4SLinus Torvalds 	int			max_depth;
23711da177e4SLinus Torvalds 	int			tagged;
2372e80b002bSEric Moore 	MPT_ADAPTER		*ioc = hd->ioc;
23731da177e4SLinus Torvalds 
2374c7c82987SMoore, Eric Dean 	starget = scsi_target(sdev);
2375c7c82987SMoore, Eric Dean 	vtarget = starget->hostdata;
23766e3815baSMoore, Eric Dean 
2377e881a172SMike Christie 	if (reason != SCSI_QDEPTH_DEFAULT)
2378e881a172SMike Christie 		return -EOPNOTSUPP;
2379e881a172SMike Christie 
2380e80b002bSEric Moore 	if (ioc->bus_type == SPI) {
2381c7c82987SMoore, Eric Dean 		if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
23821da177e4SLinus Torvalds 			max_depth = 1;
2383c92f222eSJames Bottomley 		else if (sdev->type == TYPE_DISK &&
2384c92f222eSJames Bottomley 			 vtarget->minSyncFactor <= MPT_ULTRA160)
23851da177e4SLinus Torvalds 			max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
23861da177e4SLinus Torvalds 		else
23871da177e4SLinus Torvalds 			max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
23881da177e4SLinus Torvalds 	} else
238979a3ec1aSKashyap, Desai 		 max_depth = ioc->sh->can_queue;
239079a3ec1aSKashyap, Desai 
239179a3ec1aSKashyap, Desai 	if (!sdev->tagged_supported)
239279a3ec1aSKashyap, Desai 		max_depth = 1;
23931da177e4SLinus Torvalds 
23941da177e4SLinus Torvalds 	if (qdepth > max_depth)
23951da177e4SLinus Torvalds 		qdepth = max_depth;
23961da177e4SLinus Torvalds 	if (qdepth == 1)
23971da177e4SLinus Torvalds 		tagged = 0;
23981da177e4SLinus Torvalds 	else
23991da177e4SLinus Torvalds 		tagged = MSG_SIMPLE_TAG;
24001da177e4SLinus Torvalds 
24016e3815baSMoore, Eric Dean 	scsi_adjust_queue_depth(sdev, tagged, qdepth);
24026e3815baSMoore, Eric Dean 	return sdev->queue_depth;
24031da177e4SLinus Torvalds }
24041da177e4SLinus Torvalds 
24051da177e4SLinus Torvalds /*
24061da177e4SLinus Torvalds  *	OS entry point to adjust the queue_depths on a per-device basis.
24071da177e4SLinus Torvalds  *	Called once per device the bus scan. Use it to force the queue_depth
24081da177e4SLinus Torvalds  *	member to 1 if a device does not support Q tags.
24091da177e4SLinus Torvalds  *	Return non-zero if fails.
24101da177e4SLinus Torvalds  */
24110d0c7974SMoore, Eric Dean  int
2412c7c82987SMoore, Eric Dean mptscsih_slave_configure(struct scsi_device *sdev)
24131da177e4SLinus Torvalds {
2414c7c82987SMoore, Eric Dean 	struct Scsi_Host	*sh = sdev->host;
2415c7c82987SMoore, Eric Dean 	VirtTarget		*vtarget;
2416c7c82987SMoore, Eric Dean 	VirtDevice		*vdevice;
2417c7c82987SMoore, Eric Dean 	struct scsi_target 	*starget;
2418e7eae9f6SEric Moore 	MPT_SCSI_HOST		*hd = shost_priv(sh);
2419e80b002bSEric Moore 	MPT_ADAPTER		*ioc = hd->ioc;
24201da177e4SLinus Torvalds 
2421c7c82987SMoore, Eric Dean 	starget = scsi_target(sdev);
2422c7c82987SMoore, Eric Dean 	vtarget = starget->hostdata;
2423c7c82987SMoore, Eric Dean 	vdevice = sdev->hostdata;
24241da177e4SLinus Torvalds 
2425e80b002bSEric Moore 	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2426793955f5SEric Moore 		"device @ %p, channel=%d, id=%d, lun=%d\n",
2427e80b002bSEric Moore 		ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2428e80b002bSEric Moore 	if (ioc->bus_type == SPI)
2429e80b002bSEric Moore 		dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
24301da177e4SLinus Torvalds 		    "sdtr %d wdtr %d ppr %d inq length=%d\n",
2431e80b002bSEric Moore 		    ioc->name, sdev->sdtr, sdev->wdtr,
2432c7c82987SMoore, Eric Dean 		    sdev->ppr, sdev->inquiry_len));
24331da177e4SLinus Torvalds 
2434c7c82987SMoore, Eric Dean 	vdevice->configured_lun = 1;
24351da177e4SLinus Torvalds 
2436e80b002bSEric Moore 	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
24371da177e4SLinus Torvalds 		"Queue depth=%d, tflags=%x\n",
2438e80b002bSEric Moore 		ioc->name, sdev->queue_depth, vtarget->tflags));
24391da177e4SLinus Torvalds 
2440e80b002bSEric Moore 	if (ioc->bus_type == SPI)
2441e80b002bSEric Moore 		dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
24421da177e4SLinus Torvalds 		    "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2443e80b002bSEric Moore 		    ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2444c7c82987SMoore, Eric Dean 		    vtarget->minSyncFactor));
24451da177e4SLinus Torvalds 
2446e881a172SMike Christie 	mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH,
2447e881a172SMike Christie 				    SCSI_QDEPTH_DEFAULT);
2448e80b002bSEric Moore 	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
24491da177e4SLinus Torvalds 		"tagged %d, simple %d, ordered %d\n",
2450e80b002bSEric Moore 		ioc->name,sdev->tagged_supported, sdev->simple_tags,
2451c7c82987SMoore, Eric Dean 		sdev->ordered_tags));
24521da177e4SLinus Torvalds 
24531da177e4SLinus Torvalds 	return 0;
24541da177e4SLinus Torvalds }
24551da177e4SLinus Torvalds 
24561da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
24571da177e4SLinus Torvalds /*
24581da177e4SLinus Torvalds  *  Private routines...
24591da177e4SLinus Torvalds  */
24601da177e4SLinus Torvalds 
24611da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
24621da177e4SLinus Torvalds /* Utility function to copy sense data from the scsi_cmnd buffer
24631da177e4SLinus Torvalds  * to the FC and SCSI target structures.
24641da177e4SLinus Torvalds  *
24651da177e4SLinus Torvalds  */
24661da177e4SLinus Torvalds static void
24670d0c7974SMoore, Eric Dean  mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
24681da177e4SLinus Torvalds {
2469a69de507SEric Moore 	VirtDevice	*vdevice;
24701da177e4SLinus Torvalds 	SCSIIORequest_t	*pReq;
24711da177e4SLinus Torvalds 	u32		 sense_count = le32_to_cpu(pScsiReply->SenseCount);
2472e80b002bSEric Moore 	MPT_ADAPTER 	*ioc = hd->ioc;
24731da177e4SLinus Torvalds 
24741da177e4SLinus Torvalds 	/* Get target structure
24751da177e4SLinus Torvalds 	 */
24761da177e4SLinus Torvalds 	pReq = (SCSIIORequest_t *) mf;
2477a69de507SEric Moore 	vdevice = sc->device->hostdata;
24781da177e4SLinus Torvalds 
24791da177e4SLinus Torvalds 	if (sense_count) {
24801da177e4SLinus Torvalds 		u8 *sense_data;
24811da177e4SLinus Torvalds 		int req_index;
24821da177e4SLinus Torvalds 
24831da177e4SLinus Torvalds 		/* Copy the sense received into the scsi command block. */
24841da177e4SLinus Torvalds 		req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2485e80b002bSEric Moore 		sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
24861da177e4SLinus Torvalds 		memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
24871da177e4SLinus Torvalds 
24881da177e4SLinus Torvalds 		/* Log SMART data (asc = 0x5D, non-IM case only) if required.
24891da177e4SLinus Torvalds 		 */
2490e80b002bSEric Moore 		if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
2491a69de507SEric Moore 			if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
24921da177e4SLinus Torvalds 				int idx;
24931da177e4SLinus Torvalds 
24945b5ef4f6SMoore, Eric 				idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
24951da177e4SLinus Torvalds 				ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
24961da177e4SLinus Torvalds 				ioc->events[idx].eventContext = ioc->eventContext;
24971da177e4SLinus Torvalds 
24983d9780b9SDave Jones 				ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
24993d9780b9SDave Jones 					(MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
25003d9780b9SDave Jones 					(sc->device->channel << 8) | sc->device->id;
25011da177e4SLinus Torvalds 
25023d9780b9SDave Jones 				ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
25031da177e4SLinus Torvalds 
25041da177e4SLinus Torvalds 				ioc->eventContext++;
2505e80b002bSEric Moore 				if (ioc->pcidev->vendor ==
2506786899b0SEric Moore 				    PCI_VENDOR_ID_IBM) {
2507e80b002bSEric Moore 					mptscsih_issue_sep_command(ioc,
2508a69de507SEric Moore 					    vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2509a69de507SEric Moore 					vdevice->vtarget->tflags |=
2510786899b0SEric Moore 					    MPT_TARGET_FLAGS_LED_ON;
2511786899b0SEric Moore 				}
25121da177e4SLinus Torvalds 			}
25131da177e4SLinus Torvalds 		}
25141da177e4SLinus Torvalds 	} else {
2515e80b002bSEric Moore 		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2516e80b002bSEric Moore 				ioc->name));
25171da177e4SLinus Torvalds 	}
25181da177e4SLinus Torvalds }
25191da177e4SLinus Torvalds 
2520db7051b2SKashyap, Desai /**
2521db7051b2SKashyap, Desai  * mptscsih_get_scsi_lookup - retrieves scmd entry
2522db7051b2SKashyap, Desai  * @ioc: Pointer to MPT_ADAPTER structure
2523db7051b2SKashyap, Desai  * @i: index into the array
2524db7051b2SKashyap, Desai  *
2525db7051b2SKashyap, Desai  * Returns the scsi_cmd pointer
2526db7051b2SKashyap, Desai  */
2527db7051b2SKashyap, Desai struct scsi_cmnd *
2528db7051b2SKashyap, Desai mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
2529db7051b2SKashyap, Desai {
2530db7051b2SKashyap, Desai 	unsigned long	flags;
2531db7051b2SKashyap, Desai 	struct scsi_cmnd *scmd;
2532db7051b2SKashyap, Desai 
2533db7051b2SKashyap, Desai 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2534db7051b2SKashyap, Desai 	scmd = ioc->ScsiLookup[i];
2535db7051b2SKashyap, Desai 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2536db7051b2SKashyap, Desai 
2537db7051b2SKashyap, Desai 	return scmd;
2538db7051b2SKashyap, Desai }
2539db7051b2SKashyap, Desai EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
2540e8206381SEric Moore 
2541e8206381SEric Moore /**
2542fc847ab4SJames Bottomley  * mptscsih_getclear_scsi_lookup -  retrieves and clears scmd entry from ScsiLookup[] array list
25432f187862SKashyap, Desai  * @ioc: Pointer to MPT_ADAPTER structure
25442f187862SKashyap, Desai  * @i: index into the array
25452f187862SKashyap, Desai  *
25467105a387SRandy Dunlap  * Returns the scsi_cmd pointer
25472f187862SKashyap, Desai  *
2548e8206381SEric Moore  **/
2549e8206381SEric Moore static struct scsi_cmnd *
2550e8206381SEric Moore mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2551e8206381SEric Moore {
2552e8206381SEric Moore 	unsigned long	flags;
2553e8206381SEric Moore 	struct scsi_cmnd *scmd;
2554e8206381SEric Moore 
2555e8206381SEric Moore 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2556e8206381SEric Moore 	scmd = ioc->ScsiLookup[i];
2557e8206381SEric Moore 	ioc->ScsiLookup[i] = NULL;
2558e8206381SEric Moore 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2559e8206381SEric Moore 
2560e8206381SEric Moore 	return scmd;
2561e8206381SEric Moore }
2562e8206381SEric Moore 
2563e8206381SEric Moore /**
2564e8206381SEric Moore  * mptscsih_set_scsi_lookup
2565e8206381SEric Moore  *
2566e8206381SEric Moore  * writes a scmd entry into the ScsiLookup[] array list
2567e8206381SEric Moore  *
2568e8206381SEric Moore  * @ioc: Pointer to MPT_ADAPTER structure
2569e8206381SEric Moore  * @i: index into the array
2570e8206381SEric Moore  * @scmd: scsi_cmnd pointer
2571e8206381SEric Moore  *
2572e8206381SEric Moore  **/
2573e8206381SEric Moore static void
2574e8206381SEric Moore mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2575e8206381SEric Moore {
2576e8206381SEric Moore 	unsigned long	flags;
2577e8206381SEric Moore 
2578e8206381SEric Moore 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2579e8206381SEric Moore 	ioc->ScsiLookup[i] = scmd;
2580e8206381SEric Moore 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2581e8206381SEric Moore }
2582e8206381SEric Moore 
2583e8206381SEric Moore /**
258423f9b75eSRandy Dunlap  * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
2585e8206381SEric Moore  * @ioc: Pointer to MPT_ADAPTER structure
258623f9b75eSRandy Dunlap  * @sc: scsi_cmnd pointer
258723f9b75eSRandy Dunlap  */
2588e8206381SEric Moore static int
2589e8206381SEric Moore SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2590e8206381SEric Moore {
2591e8206381SEric Moore 	unsigned long	flags;
2592e8206381SEric Moore 	int i, index=-1;
2593e8206381SEric Moore 
2594e8206381SEric Moore 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2595e8206381SEric Moore 	for (i = 0; i < ioc->req_depth; i++) {
2596e8206381SEric Moore 		if (ioc->ScsiLookup[i] == sc) {
2597e8206381SEric Moore 			index = i;
2598e8206381SEric Moore 			goto out;
25991da177e4SLinus Torvalds 		}
26001da177e4SLinus Torvalds 	}
26011da177e4SLinus Torvalds 
2602e8206381SEric Moore  out:
2603e8206381SEric Moore 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2604e8206381SEric Moore 	return index;
26051da177e4SLinus Torvalds }
26061da177e4SLinus Torvalds 
26071da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26080d0c7974SMoore, Eric Dean  int
26091da177e4SLinus Torvalds mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
26101da177e4SLinus Torvalds {
26111da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
26121da177e4SLinus Torvalds 
2613e7eae9f6SEric Moore 	if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
26141da177e4SLinus Torvalds 		return 0;
261537c60f37SKashyap, Desai 
2616e7eae9f6SEric Moore 	hd = shost_priv(ioc->sh);
261737c60f37SKashyap, Desai 	switch (reset_phase) {
261837c60f37SKashyap, Desai 	case MPT_IOC_SETUP_RESET:
261937c60f37SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
262037c60f37SKashyap, Desai 		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
262137c60f37SKashyap, Desai 		break;
262237c60f37SKashyap, Desai 	case MPT_IOC_PRE_RESET:
262337c60f37SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
262437c60f37SKashyap, Desai 		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
262537c60f37SKashyap, Desai 		mptscsih_flush_running_cmds(hd);
262637c60f37SKashyap, Desai 		break;
262737c60f37SKashyap, Desai 	case MPT_IOC_POST_RESET:
262837c60f37SKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
262937c60f37SKashyap, Desai 		    "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
263037c60f37SKashyap, Desai 		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
263137c60f37SKashyap, Desai 			ioc->internal_cmds.status |=
263237c60f37SKashyap, Desai 				MPT_MGMT_STATUS_DID_IOCRESET;
263337c60f37SKashyap, Desai 			complete(&ioc->internal_cmds.done);
26341da177e4SLinus Torvalds 		}
263537c60f37SKashyap, Desai 		break;
263637c60f37SKashyap, Desai 	default:
263737c60f37SKashyap, Desai 		break;
26381da177e4SLinus Torvalds 	}
26391da177e4SLinus Torvalds 	return 1;		/* currently means nothing really */
26401da177e4SLinus Torvalds }
26411da177e4SLinus Torvalds 
26421da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26430d0c7974SMoore, Eric Dean  int
26441da177e4SLinus Torvalds mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
26451da177e4SLinus Torvalds {
26461da177e4SLinus Torvalds 	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
26471da177e4SLinus Torvalds 
264837c60f37SKashyap, Desai 	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
264937c60f37SKashyap, Desai 		"MPT event (=%02Xh) routed to SCSI host driver!\n",
26501da177e4SLinus Torvalds 		ioc->name, event));
26511da177e4SLinus Torvalds 
26522f187862SKashyap, Desai 	if ((event == MPI_EVENT_IOC_BUS_RESET ||
26532f187862SKashyap, Desai 	    event == MPI_EVENT_EXT_BUS_RESET) &&
26542f187862SKashyap, Desai 	    (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
26552f187862SKashyap, Desai 			ioc->soft_resets++;
26561da177e4SLinus Torvalds 
26571da177e4SLinus Torvalds 	return 1;		/* currently means nothing really */
26581da177e4SLinus Torvalds }
26591da177e4SLinus Torvalds 
26601da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26611da177e4SLinus Torvalds /*
26621da177e4SLinus Torvalds  *  Bus Scan and Domain Validation functionality ...
26631da177e4SLinus Torvalds  */
26641da177e4SLinus Torvalds 
26651da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26661da177e4SLinus Torvalds /*
26671da177e4SLinus Torvalds  *	mptscsih_scandv_complete - Scan and DV callback routine registered
26681da177e4SLinus Torvalds  *	to Fustion MPT (base) driver.
26691da177e4SLinus Torvalds  *
26701da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
26711da177e4SLinus Torvalds  *	@mf: Pointer to original MPT request frame
26721da177e4SLinus Torvalds  *	@mr: Pointer to MPT reply frame (NULL if TurboReply)
26731da177e4SLinus Torvalds  *
26741da177e4SLinus Torvalds  *	This routine is called from mpt.c::mpt_interrupt() at the completion
26751da177e4SLinus Torvalds  *	of any SCSI IO request.
26761da177e4SLinus Torvalds  *	This routine is registered with the Fusion MPT (base) driver at driver
26771da177e4SLinus Torvalds  *	load/init time via the mpt_register() API call.
26781da177e4SLinus Torvalds  *
26791da177e4SLinus Torvalds  *	Returns 1 indicating alloc'd request frame ptr should be freed.
26801da177e4SLinus Torvalds  *
26811da177e4SLinus Torvalds  *	Remark: Sets a completion code and (possibly) saves sense data
26821da177e4SLinus Torvalds  *	in the IOC member localReply structure.
26831da177e4SLinus Torvalds  *	Used ONLY for DV and other internal commands.
26841da177e4SLinus Torvalds  */
26850d0c7974SMoore, Eric Dean  int
268637c60f37SKashyap, Desai mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
268737c60f37SKashyap, Desai 				MPT_FRAME_HDR *reply)
26881da177e4SLinus Torvalds {
26891da177e4SLinus Torvalds 	SCSIIORequest_t *pReq;
26901da177e4SLinus Torvalds 	SCSIIOReply_t	*pReply;
269137c60f37SKashyap, Desai 	u8		 cmd;
269237c60f37SKashyap, Desai 	u16		 req_idx;
26931da177e4SLinus Torvalds 	u8	*sense_data;
26941da177e4SLinus Torvalds 	int		 sz;
26951da177e4SLinus Torvalds 
269637c60f37SKashyap, Desai 	ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
269737c60f37SKashyap, Desai 	ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
269837c60f37SKashyap, Desai 	if (!reply)
269937c60f37SKashyap, Desai 		goto out;
270037c60f37SKashyap, Desai 
270137c60f37SKashyap, Desai 	pReply = (SCSIIOReply_t *) reply;
270237c60f37SKashyap, Desai 	pReq = (SCSIIORequest_t *) req;
270337c60f37SKashyap, Desai 	ioc->internal_cmds.completion_code =
270437c60f37SKashyap, Desai 	    mptscsih_get_completion_code(ioc, req, reply);
270537c60f37SKashyap, Desai 	ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
270637c60f37SKashyap, Desai 	memcpy(ioc->internal_cmds.reply, reply,
270737c60f37SKashyap, Desai 	    min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
270837c60f37SKashyap, Desai 	cmd = reply->u.hdr.Function;
270937c60f37SKashyap, Desai 	if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
271037c60f37SKashyap, Desai 	    (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
271137c60f37SKashyap, Desai 	    (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
271237c60f37SKashyap, Desai 		req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2713e80b002bSEric Moore 		sense_data = ((u8 *)ioc->sense_buf_pool +
27141da177e4SLinus Torvalds 		    (req_idx * MPT_SENSE_BUFFER_ALLOC));
27151da177e4SLinus Torvalds 		sz = min_t(int, pReq->SenseBufferLength,
271637c60f37SKashyap, Desai 		    MPT_SENSE_BUFFER_ALLOC);
271737c60f37SKashyap, Desai 		memcpy(ioc->internal_cmds.sense, sense_data, sz);
27181da177e4SLinus Torvalds 	}
271937c60f37SKashyap, Desai  out:
272037c60f37SKashyap, Desai 	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
272137c60f37SKashyap, Desai 		return 0;
272237c60f37SKashyap, Desai 	ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
272337c60f37SKashyap, Desai 	complete(&ioc->internal_cmds.done);
27241da177e4SLinus Torvalds 	return 1;
27251da177e4SLinus Torvalds }
27261da177e4SLinus Torvalds 
27271da177e4SLinus Torvalds 
272837c60f37SKashyap, Desai /**
272937c60f37SKashyap, Desai  *	mptscsih_get_completion_code -
273037c60f37SKashyap, Desai  *	@ioc: Pointer to MPT_ADAPTER structure
27319cf46a35SRandy Dunlap  *	@req: Pointer to original MPT request frame
27329cf46a35SRandy Dunlap  *	@reply: Pointer to MPT reply frame (NULL if TurboReply)
273337c60f37SKashyap, Desai  *
273437c60f37SKashyap, Desai  **/
273537c60f37SKashyap, Desai static int
273637c60f37SKashyap, Desai mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
273737c60f37SKashyap, Desai 				MPT_FRAME_HDR *reply)
273837c60f37SKashyap, Desai {
273937c60f37SKashyap, Desai 	SCSIIOReply_t	*pReply;
274037c60f37SKashyap, Desai 	MpiRaidActionReply_t *pr;
274137c60f37SKashyap, Desai 	u8		 scsi_status;
274237c60f37SKashyap, Desai 	u16		 status;
274337c60f37SKashyap, Desai 	int		 completion_code;
274437c60f37SKashyap, Desai 
274537c60f37SKashyap, Desai 	pReply = (SCSIIOReply_t *)reply;
274637c60f37SKashyap, Desai 	status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
274737c60f37SKashyap, Desai 	scsi_status = pReply->SCSIStatus;
274837c60f37SKashyap, Desai 
274937c60f37SKashyap, Desai 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
275037c60f37SKashyap, Desai 	    "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
275137c60f37SKashyap, Desai 	    "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
275237c60f37SKashyap, Desai 	    scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
275337c60f37SKashyap, Desai 
275437c60f37SKashyap, Desai 	switch (status) {
275537c60f37SKashyap, Desai 
275637c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
275737c60f37SKashyap, Desai 		completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
275837c60f37SKashyap, Desai 		break;
275937c60f37SKashyap, Desai 
276037c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
276137c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
276237c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
276337c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
276437c60f37SKashyap, Desai 		completion_code = MPT_SCANDV_DID_RESET;
276537c60f37SKashyap, Desai 		break;
276637c60f37SKashyap, Desai 
276737c60f37SKashyap, Desai 	case MPI_IOCSTATUS_BUSY:
276837c60f37SKashyap, Desai 	case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
276937c60f37SKashyap, Desai 		completion_code = MPT_SCANDV_BUSY;
277037c60f37SKashyap, Desai 		break;
277137c60f37SKashyap, Desai 
277237c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
277337c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
277437c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
277537c60f37SKashyap, Desai 		if (pReply->Function == MPI_FUNCTION_CONFIG) {
277637c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_GOOD;
277737c60f37SKashyap, Desai 		} else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
277837c60f37SKashyap, Desai 			pr = (MpiRaidActionReply_t *)reply;
277937c60f37SKashyap, Desai 			if (le16_to_cpu(pr->ActionStatus) ==
278037c60f37SKashyap, Desai 				MPI_RAID_ACTION_ASTATUS_SUCCESS)
278137c60f37SKashyap, Desai 				completion_code = MPT_SCANDV_GOOD;
278237c60f37SKashyap, Desai 			else
278337c60f37SKashyap, Desai 				completion_code = MPT_SCANDV_SOME_ERROR;
278437c60f37SKashyap, Desai 		} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
278537c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_SENSE;
278637c60f37SKashyap, Desai 		else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
278737c60f37SKashyap, Desai 			if (req->u.scsireq.CDB[0] == INQUIRY)
278837c60f37SKashyap, Desai 				completion_code = MPT_SCANDV_ISSUE_SENSE;
278937c60f37SKashyap, Desai 			else
279037c60f37SKashyap, Desai 				completion_code = MPT_SCANDV_DID_RESET;
279137c60f37SKashyap, Desai 		} else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
279237c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_DID_RESET;
279337c60f37SKashyap, Desai 		else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
279437c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_DID_RESET;
279537c60f37SKashyap, Desai 		else if (scsi_status == MPI_SCSI_STATUS_BUSY)
279637c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_BUSY;
279737c60f37SKashyap, Desai 		else
279837c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_GOOD;
279937c60f37SKashyap, Desai 		break;
280037c60f37SKashyap, Desai 
280137c60f37SKashyap, Desai 	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
280237c60f37SKashyap, Desai 		if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
280337c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_DID_RESET;
280437c60f37SKashyap, Desai 		else
280537c60f37SKashyap, Desai 			completion_code = MPT_SCANDV_SOME_ERROR;
280637c60f37SKashyap, Desai 		break;
280737c60f37SKashyap, Desai 	default:
280837c60f37SKashyap, Desai 		completion_code = MPT_SCANDV_SOME_ERROR;
280937c60f37SKashyap, Desai 		break;
281037c60f37SKashyap, Desai 
281137c60f37SKashyap, Desai 	}	/* switch(status) */
281237c60f37SKashyap, Desai 
281337c60f37SKashyap, Desai 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
281437c60f37SKashyap, Desai 	    "  completionCode set to %08xh\n", ioc->name, completion_code));
281537c60f37SKashyap, Desai 	return completion_code;
281637c60f37SKashyap, Desai }
28171da177e4SLinus Torvalds 
28181da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
28191da177e4SLinus Torvalds /**
28201da177e4SLinus Torvalds  *	mptscsih_do_cmd - Do internal command.
28211da177e4SLinus Torvalds  *	@hd: MPT_SCSI_HOST pointer
28221da177e4SLinus Torvalds  *	@io: INTERNAL_CMD pointer.
28231da177e4SLinus Torvalds  *
28241da177e4SLinus Torvalds  *	Issue the specified internally generated command and do command
28251da177e4SLinus Torvalds  *	specific cleanup. For bus scan / DV only.
28261da177e4SLinus Torvalds  *	NOTES: If command is Inquiry and status is good,
28271da177e4SLinus Torvalds  *	initialize a target structure, save the data
28281da177e4SLinus Torvalds  *
28291da177e4SLinus Torvalds  *	Remark: Single threaded access only.
28301da177e4SLinus Torvalds  *
28311da177e4SLinus Torvalds  *	Return:
28321da177e4SLinus Torvalds  *		< 0 if an illegal command or no resources
28331da177e4SLinus Torvalds  *
28341da177e4SLinus Torvalds  *		   0 if good
28351da177e4SLinus Torvalds  *
28361da177e4SLinus Torvalds  *		 > 0 if command complete but some type of completion error.
28371da177e4SLinus Torvalds  */
28381da177e4SLinus Torvalds static int
28391da177e4SLinus Torvalds mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
28401da177e4SLinus Torvalds {
28411da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
28421da177e4SLinus Torvalds 	SCSIIORequest_t	*pScsiReq;
28431da177e4SLinus Torvalds 	int		 my_idx, ii, dir;
284437c60f37SKashyap, Desai 	int		 timeout;
28451da177e4SLinus Torvalds 	char		 cmdLen;
28461da177e4SLinus Torvalds 	char		 CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
284737c60f37SKashyap, Desai 	u8		 cmd = io->cmd;
2848e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
284937c60f37SKashyap, Desai 	int		 ret = 0;
285037c60f37SKashyap, Desai 	unsigned long	 timeleft;
285137c60f37SKashyap, Desai 	unsigned long	 flags;
28521da177e4SLinus Torvalds 
28531ba9ab2eSKashyap, Desai 	/* don't send internal command during diag reset */
28541ba9ab2eSKashyap, Desai 	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
28551ba9ab2eSKashyap, Desai 	if (ioc->ioc_reset_in_progress) {
28561ba9ab2eSKashyap, Desai 		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
28571ba9ab2eSKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
28581ba9ab2eSKashyap, Desai 			"%s: busy with host reset\n", ioc->name, __func__));
28591ba9ab2eSKashyap, Desai 		return MPT_SCANDV_BUSY;
28601ba9ab2eSKashyap, Desai 	}
28611ba9ab2eSKashyap, Desai 	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
28621ba9ab2eSKashyap, Desai 
286337c60f37SKashyap, Desai 	mutex_lock(&ioc->internal_cmds.mutex);
28641da177e4SLinus Torvalds 
28651da177e4SLinus Torvalds 	/* Set command specific information
28661da177e4SLinus Torvalds 	 */
28671da177e4SLinus Torvalds 	switch (cmd) {
28681da177e4SLinus Torvalds 	case INQUIRY:
28691da177e4SLinus Torvalds 		cmdLen = 6;
28701da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
28711da177e4SLinus Torvalds 		CDB[0] = cmd;
28721da177e4SLinus Torvalds 		CDB[4] = io->size;
287337c60f37SKashyap, Desai 		timeout = 10;
28741da177e4SLinus Torvalds 		break;
28751da177e4SLinus Torvalds 
28761da177e4SLinus Torvalds 	case TEST_UNIT_READY:
28771da177e4SLinus Torvalds 		cmdLen = 6;
28781da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
287937c60f37SKashyap, Desai 		timeout = 10;
28801da177e4SLinus Torvalds 		break;
28811da177e4SLinus Torvalds 
28821da177e4SLinus Torvalds 	case START_STOP:
28831da177e4SLinus Torvalds 		cmdLen = 6;
28841da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
28851da177e4SLinus Torvalds 		CDB[0] = cmd;
28861da177e4SLinus Torvalds 		CDB[4] = 1;	/*Spin up the disk */
288737c60f37SKashyap, Desai 		timeout = 15;
28881da177e4SLinus Torvalds 		break;
28891da177e4SLinus Torvalds 
28901da177e4SLinus Torvalds 	case REQUEST_SENSE:
28911da177e4SLinus Torvalds 		cmdLen = 6;
28921da177e4SLinus Torvalds 		CDB[0] = cmd;
28931da177e4SLinus Torvalds 		CDB[4] = io->size;
28941da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
289537c60f37SKashyap, Desai 		timeout = 10;
28961da177e4SLinus Torvalds 		break;
28971da177e4SLinus Torvalds 
28981da177e4SLinus Torvalds 	case READ_BUFFER:
28991da177e4SLinus Torvalds 		cmdLen = 10;
29001da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29011da177e4SLinus Torvalds 		CDB[0] = cmd;
29021da177e4SLinus Torvalds 		if (io->flags & MPT_ICFLAG_ECHO) {
29031da177e4SLinus Torvalds 			CDB[1] = 0x0A;
29041da177e4SLinus Torvalds 		} else {
29051da177e4SLinus Torvalds 			CDB[1] = 0x02;
29061da177e4SLinus Torvalds 		}
29071da177e4SLinus Torvalds 
29081da177e4SLinus Torvalds 		if (io->flags & MPT_ICFLAG_BUF_CAP) {
29091da177e4SLinus Torvalds 			CDB[1] |= 0x01;
29101da177e4SLinus Torvalds 		}
29111da177e4SLinus Torvalds 		CDB[6] = (io->size >> 16) & 0xFF;
29121da177e4SLinus Torvalds 		CDB[7] = (io->size >>  8) & 0xFF;
29131da177e4SLinus Torvalds 		CDB[8] = io->size & 0xFF;
291437c60f37SKashyap, Desai 		timeout = 10;
29151da177e4SLinus Torvalds 		break;
29161da177e4SLinus Torvalds 
29171da177e4SLinus Torvalds 	case WRITE_BUFFER:
29181da177e4SLinus Torvalds 		cmdLen = 10;
29191da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_WRITE;
29201da177e4SLinus Torvalds 		CDB[0] = cmd;
29211da177e4SLinus Torvalds 		if (io->flags & MPT_ICFLAG_ECHO) {
29221da177e4SLinus Torvalds 			CDB[1] = 0x0A;
29231da177e4SLinus Torvalds 		} else {
29241da177e4SLinus Torvalds 			CDB[1] = 0x02;
29251da177e4SLinus Torvalds 		}
29261da177e4SLinus Torvalds 		CDB[6] = (io->size >> 16) & 0xFF;
29271da177e4SLinus Torvalds 		CDB[7] = (io->size >>  8) & 0xFF;
29281da177e4SLinus Torvalds 		CDB[8] = io->size & 0xFF;
292937c60f37SKashyap, Desai 		timeout = 10;
29301da177e4SLinus Torvalds 		break;
29311da177e4SLinus Torvalds 
29321da177e4SLinus Torvalds 	case RESERVE:
29331da177e4SLinus Torvalds 		cmdLen = 6;
29341da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29351da177e4SLinus Torvalds 		CDB[0] = cmd;
293637c60f37SKashyap, Desai 		timeout = 10;
29371da177e4SLinus Torvalds 		break;
29381da177e4SLinus Torvalds 
29391da177e4SLinus Torvalds 	case RELEASE:
29401da177e4SLinus Torvalds 		cmdLen = 6;
29411da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29421da177e4SLinus Torvalds 		CDB[0] = cmd;
294337c60f37SKashyap, Desai 		timeout = 10;
29441da177e4SLinus Torvalds 		break;
29451da177e4SLinus Torvalds 
29461da177e4SLinus Torvalds 	case SYNCHRONIZE_CACHE:
29471da177e4SLinus Torvalds 		cmdLen = 10;
29481da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29491da177e4SLinus Torvalds 		CDB[0] = cmd;
29501da177e4SLinus Torvalds //		CDB[1] = 0x02;	/* set immediate bit */
295137c60f37SKashyap, Desai 		timeout = 10;
29521da177e4SLinus Torvalds 		break;
29531da177e4SLinus Torvalds 
29541da177e4SLinus Torvalds 	default:
29551da177e4SLinus Torvalds 		/* Error Case */
295637c60f37SKashyap, Desai 		ret = -EFAULT;
295737c60f37SKashyap, Desai 		goto out;
29581da177e4SLinus Torvalds 	}
29591da177e4SLinus Torvalds 
29601da177e4SLinus Torvalds 	/* Get and Populate a free Frame
296137c60f37SKashyap, Desai 	 * MsgContext set in mpt_get_msg_frame call
29621da177e4SLinus Torvalds 	 */
2963e80b002bSEric Moore 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
296437c60f37SKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
296537c60f37SKashyap, Desai 		    ioc->name, __func__));
296637c60f37SKashyap, Desai 		ret = MPT_SCANDV_BUSY;
296737c60f37SKashyap, Desai 		goto out;
29681da177e4SLinus Torvalds 	}
29691da177e4SLinus Torvalds 
29701da177e4SLinus Torvalds 	pScsiReq = (SCSIIORequest_t *) mf;
29711da177e4SLinus Torvalds 
29721da177e4SLinus Torvalds 	/* Get the request index */
29731da177e4SLinus Torvalds 	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
29741da177e4SLinus Torvalds 	ADD_INDEX_LOG(my_idx); /* for debug */
29751da177e4SLinus Torvalds 
29761da177e4SLinus Torvalds 	if (io->flags & MPT_ICFLAG_PHYS_DISK) {
29771da177e4SLinus Torvalds 		pScsiReq->TargetID = io->physDiskNum;
29781da177e4SLinus Torvalds 		pScsiReq->Bus = 0;
29791da177e4SLinus Torvalds 		pScsiReq->ChainOffset = 0;
29801da177e4SLinus Torvalds 		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
29811da177e4SLinus Torvalds 	} else {
29821da177e4SLinus Torvalds 		pScsiReq->TargetID = io->id;
2983793955f5SEric Moore 		pScsiReq->Bus = io->channel;
29841da177e4SLinus Torvalds 		pScsiReq->ChainOffset = 0;
29851da177e4SLinus Torvalds 		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
29861da177e4SLinus Torvalds 	}
29871da177e4SLinus Torvalds 
29881da177e4SLinus Torvalds 	pScsiReq->CDBLength = cmdLen;
29891da177e4SLinus Torvalds 	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
29901da177e4SLinus Torvalds 
29911da177e4SLinus Torvalds 	pScsiReq->Reserved = 0;
29921da177e4SLinus Torvalds 
299314d0f0b0SKashyap, Desai 	pScsiReq->MsgFlags = mpt_msg_flags(ioc);
29941da177e4SLinus Torvalds 	/* MsgContext set in mpt_get_msg_fram call  */
29951da177e4SLinus Torvalds 
2996793955f5SEric Moore 	int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
29971da177e4SLinus Torvalds 
29981da177e4SLinus Torvalds 	if (io->flags & MPT_ICFLAG_TAGGED_CMD)
29991da177e4SLinus Torvalds 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
30001da177e4SLinus Torvalds 	else
30011da177e4SLinus Torvalds 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
30021da177e4SLinus Torvalds 
30031da177e4SLinus Torvalds 	if (cmd == REQUEST_SENSE) {
30041da177e4SLinus Torvalds 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
300537c60f37SKashyap, Desai 		devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
300637c60f37SKashyap, Desai 		    "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
30071da177e4SLinus Torvalds 	}
30081da177e4SLinus Torvalds 
30091da177e4SLinus Torvalds 	for (ii = 0; ii < 16; ii++)
30101da177e4SLinus Torvalds 		pScsiReq->CDB[ii] = CDB[ii];
30111da177e4SLinus Torvalds 
30121da177e4SLinus Torvalds 	pScsiReq->DataLength = cpu_to_le32(io->size);
3013e80b002bSEric Moore 	pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
30141da177e4SLinus Torvalds 					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
30151da177e4SLinus Torvalds 
301637c60f37SKashyap, Desai 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
301737c60f37SKashyap, Desai 	    "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
301837c60f37SKashyap, Desai 	    ioc->name, __func__, cmd, io->channel, io->id, io->lun));
30191da177e4SLinus Torvalds 
302037c60f37SKashyap, Desai 	if (dir == MPI_SCSIIO_CONTROL_READ)
302114d0f0b0SKashyap, Desai 		ioc->add_sge((char *) &pScsiReq->SGL,
302237c60f37SKashyap, Desai 		    MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
302337c60f37SKashyap, Desai 	else
302414d0f0b0SKashyap, Desai 		ioc->add_sge((char *) &pScsiReq->SGL,
302537c60f37SKashyap, Desai 		    MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
30261da177e4SLinus Torvalds 
302737c60f37SKashyap, Desai 	INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
3028e80b002bSEric Moore 	mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
302937c60f37SKashyap, Desai 	timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
303037c60f37SKashyap, Desai 	    timeout*HZ);
303137c60f37SKashyap, Desai 	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
303237c60f37SKashyap, Desai 		ret = MPT_SCANDV_DID_RESET;
303337c60f37SKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
303437c60f37SKashyap, Desai 		    "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
303537c60f37SKashyap, Desai 		    cmd));
303637c60f37SKashyap, Desai 		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
303737c60f37SKashyap, Desai 			mpt_free_msg_frame(ioc, mf);
303837c60f37SKashyap, Desai 			goto out;
303937c60f37SKashyap, Desai 		}
304037c60f37SKashyap, Desai 		if (!timeleft) {
304137c60f37SKashyap, Desai 			printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
304237c60f37SKashyap, Desai 			    ioc->name, __func__);
304337c60f37SKashyap, Desai 			mpt_HardResetHandler(ioc, CAN_SLEEP);
304437c60f37SKashyap, Desai 			mpt_free_msg_frame(ioc, mf);
304537c60f37SKashyap, Desai 		}
304637c60f37SKashyap, Desai 		goto out;
30471da177e4SLinus Torvalds 	}
30481da177e4SLinus Torvalds 
304937c60f37SKashyap, Desai 	ret = ioc->internal_cmds.completion_code;
305037c60f37SKashyap, Desai 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
305137c60f37SKashyap, Desai 			ioc->name, __func__, ret));
305237c60f37SKashyap, Desai 
305337c60f37SKashyap, Desai  out:
305437c60f37SKashyap, Desai 	CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
305537c60f37SKashyap, Desai 	mutex_unlock(&ioc->internal_cmds.mutex);
305637c60f37SKashyap, Desai 	return ret;
30571da177e4SLinus Torvalds }
30581da177e4SLinus Torvalds 
30591da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
30601da177e4SLinus Torvalds /**
3061c7c82987SMoore, Eric Dean  *	mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3062c7c82987SMoore, Eric Dean  *	@hd: Pointer to a SCSI HOST structure
3063d9489fb6SRandy Dunlap  *	@vdevice: virtual target device
3064c7c82987SMoore, Eric Dean  *
3065c7c82987SMoore, Eric Dean  *	Uses the ISR, but with special processing.
3066c7c82987SMoore, Eric Dean  *	MUST be single-threaded.
3067c7c82987SMoore, Eric Dean  *
3068c7c82987SMoore, Eric Dean  */
3069c7c82987SMoore, Eric Dean static void
3070c7c82987SMoore, Eric Dean mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3071c7c82987SMoore, Eric Dean {
3072c7c82987SMoore, Eric Dean 	INTERNAL_CMD		 iocmd;
30731da177e4SLinus Torvalds 
3074cc78d30aSEric Moore 	/* Ignore hidden raid components, this is handled when the command
3075cc78d30aSEric Moore 	 * is sent to the volume
3076cc78d30aSEric Moore 	 */
3077cc78d30aSEric Moore 	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3078cc78d30aSEric Moore 		return;
3079cc78d30aSEric Moore 
3080cc78d30aSEric Moore 	if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3081cc78d30aSEric Moore 	    !vdevice->configured_lun)
3082cc78d30aSEric Moore 		return;
3083cc78d30aSEric Moore 
30841da177e4SLinus Torvalds 	/* Following parameters will not change
30851da177e4SLinus Torvalds 	 * in this routine.
30861da177e4SLinus Torvalds 	 */
30871da177e4SLinus Torvalds 	iocmd.cmd = SYNCHRONIZE_CACHE;
30881da177e4SLinus Torvalds 	iocmd.flags = 0;
30891da177e4SLinus Torvalds 	iocmd.physDiskNum = -1;
30901da177e4SLinus Torvalds 	iocmd.data = NULL;
30911da177e4SLinus Torvalds 	iocmd.data_dma = -1;
30921da177e4SLinus Torvalds 	iocmd.size = 0;
30931da177e4SLinus Torvalds 	iocmd.rsvd = iocmd.rsvd2 = 0;
3094793955f5SEric Moore 	iocmd.channel = vdevice->vtarget->channel;
3095793955f5SEric Moore 	iocmd.id = vdevice->vtarget->id;
3096793955f5SEric Moore 	iocmd.lun = vdevice->lun;
30971da177e4SLinus Torvalds 
3098c7c82987SMoore, Eric Dean 	mptscsih_do_cmd(hd, &iocmd);
30991da177e4SLinus Torvalds }
31001da177e4SLinus Torvalds 
3101edb9068dSPrakash, Sathya static ssize_t
3102ee959b00STony Jones mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3103ee959b00STony Jones 			 char *buf)
3104edb9068dSPrakash, Sathya {
3105ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3106e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3107edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3108edb9068dSPrakash, Sathya 
3109edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3110edb9068dSPrakash, Sathya 	    (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3111edb9068dSPrakash, Sathya 	    (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3112edb9068dSPrakash, Sathya 	    (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3113edb9068dSPrakash, Sathya 	    ioc->facts.FWVersion.Word & 0x000000FF);
3114edb9068dSPrakash, Sathya }
3115ee959b00STony Jones static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
3116edb9068dSPrakash, Sathya 
3117edb9068dSPrakash, Sathya static ssize_t
3118ee959b00STony Jones mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3119ee959b00STony Jones 			   char *buf)
3120edb9068dSPrakash, Sathya {
3121ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3122e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3123edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3124edb9068dSPrakash, Sathya 
3125edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3126edb9068dSPrakash, Sathya 	    (ioc->biosVersion & 0xFF000000) >> 24,
3127edb9068dSPrakash, Sathya 	    (ioc->biosVersion & 0x00FF0000) >> 16,
3128edb9068dSPrakash, Sathya 	    (ioc->biosVersion & 0x0000FF00) >> 8,
3129edb9068dSPrakash, Sathya 	    ioc->biosVersion & 0x000000FF);
3130edb9068dSPrakash, Sathya }
3131ee959b00STony Jones static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
3132edb9068dSPrakash, Sathya 
3133edb9068dSPrakash, Sathya static ssize_t
3134ee959b00STony Jones mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3135ee959b00STony Jones 			  char *buf)
3136edb9068dSPrakash, Sathya {
3137ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3138e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3139edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3140edb9068dSPrakash, Sathya 
3141edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3142edb9068dSPrakash, Sathya }
3143ee959b00STony Jones static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
3144edb9068dSPrakash, Sathya 
3145edb9068dSPrakash, Sathya static ssize_t
3146ee959b00STony Jones mptscsih_version_product_show(struct device *dev,
3147ee959b00STony Jones 			      struct device_attribute *attr,
3148ee959b00STony Jones char *buf)
3149edb9068dSPrakash, Sathya {
3150ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3151e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3152edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3153edb9068dSPrakash, Sathya 
3154edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3155edb9068dSPrakash, Sathya }
3156ee959b00STony Jones static DEVICE_ATTR(version_product, S_IRUGO,
3157edb9068dSPrakash, Sathya     mptscsih_version_product_show, NULL);
3158edb9068dSPrakash, Sathya 
3159edb9068dSPrakash, Sathya static ssize_t
3160ee959b00STony Jones mptscsih_version_nvdata_persistent_show(struct device *dev,
3161ee959b00STony Jones 					struct device_attribute *attr,
3162ee959b00STony Jones 					char *buf)
3163edb9068dSPrakash, Sathya {
3164ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3165e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3166edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3167edb9068dSPrakash, Sathya 
3168edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02xh\n",
3169edb9068dSPrakash, Sathya 	    ioc->nvdata_version_persistent);
3170edb9068dSPrakash, Sathya }
3171ee959b00STony Jones static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
3172edb9068dSPrakash, Sathya     mptscsih_version_nvdata_persistent_show, NULL);
3173edb9068dSPrakash, Sathya 
3174edb9068dSPrakash, Sathya static ssize_t
3175ee959b00STony Jones mptscsih_version_nvdata_default_show(struct device *dev,
3176ee959b00STony Jones 				     struct device_attribute *attr, char *buf)
3177edb9068dSPrakash, Sathya {
3178ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3179e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3180edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3181edb9068dSPrakash, Sathya 
3182edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3183edb9068dSPrakash, Sathya }
3184ee959b00STony Jones static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
3185edb9068dSPrakash, Sathya     mptscsih_version_nvdata_default_show, NULL);
3186edb9068dSPrakash, Sathya 
3187edb9068dSPrakash, Sathya static ssize_t
3188ee959b00STony Jones mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3189ee959b00STony Jones 			 char *buf)
3190edb9068dSPrakash, Sathya {
3191ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3192e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3193edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3194edb9068dSPrakash, Sathya 
3195edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3196edb9068dSPrakash, Sathya }
3197ee959b00STony Jones static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
3198edb9068dSPrakash, Sathya 
3199edb9068dSPrakash, Sathya static ssize_t
3200ee959b00STony Jones mptscsih_board_assembly_show(struct device *dev,
3201ee959b00STony Jones 			     struct device_attribute *attr, char *buf)
3202edb9068dSPrakash, Sathya {
3203ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3204e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3205edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3206edb9068dSPrakash, Sathya 
3207edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3208edb9068dSPrakash, Sathya }
3209ee959b00STony Jones static DEVICE_ATTR(board_assembly, S_IRUGO,
3210edb9068dSPrakash, Sathya     mptscsih_board_assembly_show, NULL);
3211edb9068dSPrakash, Sathya 
3212edb9068dSPrakash, Sathya static ssize_t
3213ee959b00STony Jones mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3214ee959b00STony Jones 			   char *buf)
3215edb9068dSPrakash, Sathya {
3216ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3217e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3218edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3219edb9068dSPrakash, Sathya 
3220edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3221edb9068dSPrakash, Sathya }
3222ee959b00STony Jones static DEVICE_ATTR(board_tracer, S_IRUGO,
3223edb9068dSPrakash, Sathya     mptscsih_board_tracer_show, NULL);
3224edb9068dSPrakash, Sathya 
3225edb9068dSPrakash, Sathya static ssize_t
3226ee959b00STony Jones mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3227ee959b00STony Jones 		       char *buf)
3228edb9068dSPrakash, Sathya {
3229ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3230e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3231edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3232edb9068dSPrakash, Sathya 
3233edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3234edb9068dSPrakash, Sathya }
3235ee959b00STony Jones static DEVICE_ATTR(io_delay, S_IRUGO,
3236edb9068dSPrakash, Sathya     mptscsih_io_delay_show, NULL);
3237edb9068dSPrakash, Sathya 
3238edb9068dSPrakash, Sathya static ssize_t
3239ee959b00STony Jones mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3240ee959b00STony Jones 			   char *buf)
3241edb9068dSPrakash, Sathya {
3242ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3243e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
3244edb9068dSPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
3245edb9068dSPrakash, Sathya 
3246edb9068dSPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3247edb9068dSPrakash, Sathya }
3248ee959b00STony Jones static DEVICE_ATTR(device_delay, S_IRUGO,
3249edb9068dSPrakash, Sathya     mptscsih_device_delay_show, NULL);
3250edb9068dSPrakash, Sathya 
32516757d6b4SPrakash, Sathya static ssize_t
3252ee959b00STony Jones mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3253ee959b00STony Jones 			  char *buf)
32546757d6b4SPrakash, Sathya {
3255ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3256e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
32576757d6b4SPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
32586757d6b4SPrakash, Sathya 
32596757d6b4SPrakash, Sathya 	return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
32606757d6b4SPrakash, Sathya }
32616757d6b4SPrakash, Sathya static ssize_t
3262ee959b00STony Jones mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3263ee959b00STony Jones 			   const char *buf, size_t count)
32646757d6b4SPrakash, Sathya {
3265ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
3266e7eae9f6SEric Moore 	MPT_SCSI_HOST	*hd = shost_priv(host);
32676757d6b4SPrakash, Sathya 	MPT_ADAPTER *ioc = hd->ioc;
32686757d6b4SPrakash, Sathya 	int val = 0;
32696757d6b4SPrakash, Sathya 
32706757d6b4SPrakash, Sathya 	if (sscanf(buf, "%x", &val) != 1)
32716757d6b4SPrakash, Sathya 		return -EINVAL;
32726757d6b4SPrakash, Sathya 
32736757d6b4SPrakash, Sathya 	ioc->debug_level = val;
32746757d6b4SPrakash, Sathya 	printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
32756757d6b4SPrakash, Sathya 				ioc->name, ioc->debug_level);
32766757d6b4SPrakash, Sathya 	return strlen(buf);
32776757d6b4SPrakash, Sathya }
3278ee959b00STony Jones static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
32796757d6b4SPrakash, Sathya 	mptscsih_debug_level_show, mptscsih_debug_level_store);
32806757d6b4SPrakash, Sathya 
3281ee959b00STony Jones struct device_attribute *mptscsih_host_attrs[] = {
3282ee959b00STony Jones 	&dev_attr_version_fw,
3283ee959b00STony Jones 	&dev_attr_version_bios,
3284ee959b00STony Jones 	&dev_attr_version_mpi,
3285ee959b00STony Jones 	&dev_attr_version_product,
3286ee959b00STony Jones 	&dev_attr_version_nvdata_persistent,
3287ee959b00STony Jones 	&dev_attr_version_nvdata_default,
3288ee959b00STony Jones 	&dev_attr_board_name,
3289ee959b00STony Jones 	&dev_attr_board_assembly,
3290ee959b00STony Jones 	&dev_attr_board_tracer,
3291ee959b00STony Jones 	&dev_attr_io_delay,
3292ee959b00STony Jones 	&dev_attr_device_delay,
3293ee959b00STony Jones 	&dev_attr_debug_level,
3294edb9068dSPrakash, Sathya 	NULL,
3295edb9068dSPrakash, Sathya };
329637c60f37SKashyap, Desai 
3297edb9068dSPrakash, Sathya EXPORT_SYMBOL(mptscsih_host_attrs);
3298edb9068dSPrakash, Sathya 
32990d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_remove);
33000d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_shutdown);
33010d0c7974SMoore, Eric Dean  #ifdef CONFIG_PM
33020d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_suspend);
33030d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_resume);
33040d0c7974SMoore, Eric Dean  #endif
33050d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_proc_info);
33060d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_info);
33070d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_qcmd);
33080d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_slave_destroy);
33090d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_slave_configure);
33100d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_abort);
33110d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_dev_reset);
33120d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_bus_reset);
33130d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_host_reset);
33140d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_bios_param);
33150d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_io_done);
33160d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
33170d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_scandv_complete);
33180d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_event_process);
33190d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_ioc_reset);
33206e3815baSMoore, Eric Dean EXPORT_SYMBOL(mptscsih_change_queue_depth);
33211da177e4SLinus Torvalds 
33220d0c7974SMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3323