11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/drivers/message/fusion/mptscsih.c
30d0c7974SMoore, Eric Dean   *      For use with LSI Logic PCI chip/adapter(s)
41da177e4SLinus Torvalds  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
51da177e4SLinus Torvalds  *
69f4203b3SEric Moore  *  Copyright (c) 1999-2007 LSI Logic 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>
491da177e4SLinus Torvalds #include <linux/init.h>
501da177e4SLinus Torvalds #include <linux/errno.h>
511da177e4SLinus Torvalds #include <linux/kdev_t.h>
521da177e4SLinus Torvalds #include <linux/blkdev.h>
531da177e4SLinus Torvalds #include <linux/delay.h>	/* for mdelay */
541da177e4SLinus Torvalds #include <linux/interrupt.h>	/* needed for in_interrupt() proto */
551da177e4SLinus Torvalds #include <linux/reboot.h>	/* notifier code */
561da177e4SLinus Torvalds #include <linux/workqueue.h>
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds #include <scsi/scsi.h>
591da177e4SLinus Torvalds #include <scsi/scsi_cmnd.h>
601da177e4SLinus Torvalds #include <scsi/scsi_device.h>
611da177e4SLinus Torvalds #include <scsi/scsi_host.h>
621da177e4SLinus Torvalds #include <scsi/scsi_tcq.h>
63e0fc15beSMoore, Eric Dean #include <scsi/scsi_dbg.h>
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds #include "mptbase.h"
661da177e4SLinus Torvalds #include "mptscsih.h"
67bf451522SEric Moore #include "lsi/mpi_log_sas.h"
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
701da177e4SLinus Torvalds #define my_NAME		"Fusion MPT SCSI Host driver"
711da177e4SLinus Torvalds #define my_VERSION	MPT_LINUX_VERSION_COMMON
721da177e4SLinus Torvalds #define MYNAM		"mptscsih"
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds MODULE_AUTHOR(MODULEAUTHOR);
751da177e4SLinus Torvalds MODULE_DESCRIPTION(my_NAME);
761da177e4SLinus Torvalds MODULE_LICENSE("GPL");
779f4203b3SEric Moore MODULE_VERSION(my_VERSION);
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
801da177e4SLinus Torvalds /*
811da177e4SLinus Torvalds  *  Other private/forward protos...
821da177e4SLinus Torvalds  */
830d0c7974SMoore, Eric Dean  int		mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
841da177e4SLinus Torvalds static void	mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
850d0c7974SMoore, Eric Dean  int		mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds static int	mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
881da177e4SLinus Torvalds 				 SCSIIORequest_t *pReq, int req_idx);
891da177e4SLinus Torvalds static void	mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
900d0c7974SMoore, Eric Dean  static void	mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
911da177e4SLinus Torvalds static int	mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
921da177e4SLinus Torvalds static int	mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
933dc0b03fSEric Moore static int	SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
941da177e4SLinus Torvalds 
95793955f5SEric Moore static int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
961da177e4SLinus Torvalds 
970d0c7974SMoore, Eric Dean  int		mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
980d0c7974SMoore, Eric Dean  int		mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
991da177e4SLinus Torvalds 
1000d0c7974SMoore, Eric Dean  int		mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
1011da177e4SLinus Torvalds static int	mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
102c7c82987SMoore, Eric Dean static void	mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
1031da177e4SLinus Torvalds 
1040d0c7974SMoore, Eric Dean  void 		mptscsih_remove(struct pci_dev *);
105d18c3db5SGreg Kroah-Hartman void 		mptscsih_shutdown(struct pci_dev *);
1061da177e4SLinus Torvalds #ifdef CONFIG_PM
1070d0c7974SMoore, Eric Dean  int 		mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
1080d0c7974SMoore, Eric Dean  int 		mptscsih_resume(struct pci_dev *pdev);
1091da177e4SLinus Torvalds #endif
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds #define SNS_LEN(scp)	sizeof((scp)->sense_buffer)
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1141da177e4SLinus Torvalds /**
1151da177e4SLinus Torvalds  *	mptscsih_add_sge - Place a simple SGE at address pAddr.
1161da177e4SLinus Torvalds  *	@pAddr: virtual address for SGE
1171da177e4SLinus Torvalds  *	@flagslength: SGE flags and data transfer length
1181da177e4SLinus Torvalds  *	@dma_addr: Physical address
1191da177e4SLinus Torvalds  *
1201da177e4SLinus Torvalds  *	This routine places a MPT request frame back on the MPT adapter's
1211da177e4SLinus Torvalds  *	FreeQ.
1221da177e4SLinus Torvalds  */
1231da177e4SLinus Torvalds static inline void
1241da177e4SLinus Torvalds mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds 	if (sizeof(dma_addr_t) == sizeof(u64)) {
1271da177e4SLinus Torvalds 		SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1281da177e4SLinus Torvalds 		u32 tmp = dma_addr & 0xFFFFFFFF;
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 		pSge->FlagsLength = cpu_to_le32(flagslength);
1311da177e4SLinus Torvalds 		pSge->Address.Low = cpu_to_le32(tmp);
1321da177e4SLinus Torvalds 		tmp = (u32) ((u64)dma_addr >> 32);
1331da177e4SLinus Torvalds 		pSge->Address.High = cpu_to_le32(tmp);
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 	} else {
1361da177e4SLinus Torvalds 		SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1371da177e4SLinus Torvalds 		pSge->FlagsLength = cpu_to_le32(flagslength);
1381da177e4SLinus Torvalds 		pSge->Address = cpu_to_le32(dma_addr);
1391da177e4SLinus Torvalds 	}
1401da177e4SLinus Torvalds } /* mptscsih_add_sge() */
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1431da177e4SLinus Torvalds /**
1441da177e4SLinus Torvalds  *	mptscsih_add_chain - Place a chain SGE at address pAddr.
1451da177e4SLinus Torvalds  *	@pAddr: virtual address for SGE
1461da177e4SLinus Torvalds  *	@next: nextChainOffset value (u32's)
1471da177e4SLinus Torvalds  *	@length: length of next SGL segment
1481da177e4SLinus Torvalds  *	@dma_addr: Physical address
1491da177e4SLinus Torvalds  *
1501da177e4SLinus Torvalds  *	This routine places a MPT request frame back on the MPT adapter's
1511da177e4SLinus Torvalds  *	FreeQ.
1521da177e4SLinus Torvalds  */
1531da177e4SLinus Torvalds static inline void
1541da177e4SLinus Torvalds mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1551da177e4SLinus Torvalds {
1561da177e4SLinus Torvalds 	if (sizeof(dma_addr_t) == sizeof(u64)) {
1571da177e4SLinus Torvalds 		SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
1581da177e4SLinus Torvalds 		u32 tmp = dma_addr & 0xFFFFFFFF;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 		pChain->Length = cpu_to_le16(length);
1611da177e4SLinus Torvalds 		pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 		pChain->NextChainOffset = next;
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 		pChain->Address.Low = cpu_to_le32(tmp);
1661da177e4SLinus Torvalds 		tmp = (u32) ((u64)dma_addr >> 32);
1671da177e4SLinus Torvalds 		pChain->Address.High = cpu_to_le32(tmp);
1681da177e4SLinus Torvalds 	} else {
1691da177e4SLinus Torvalds 		SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1701da177e4SLinus Torvalds 		pChain->Length = cpu_to_le16(length);
1711da177e4SLinus Torvalds 		pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
1721da177e4SLinus Torvalds 		pChain->NextChainOffset = next;
1731da177e4SLinus Torvalds 		pChain->Address = cpu_to_le32(dma_addr);
1741da177e4SLinus Torvalds 	}
1751da177e4SLinus Torvalds } /* mptscsih_add_chain() */
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1781da177e4SLinus Torvalds /*
1791da177e4SLinus Torvalds  *	mptscsih_getFreeChainBuffer - Function to get a free chain
1801da177e4SLinus Torvalds  *	from the MPT_SCSI_HOST FreeChainQ.
1811da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
1821da177e4SLinus Torvalds  *	@req_idx: Index of the SCSI IO request frame. (output)
1831da177e4SLinus Torvalds  *
1841da177e4SLinus Torvalds  *	return SUCCESS or FAILED
1851da177e4SLinus Torvalds  */
1861da177e4SLinus Torvalds static inline int
1871da177e4SLinus Torvalds mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
1881da177e4SLinus Torvalds {
1891da177e4SLinus Torvalds 	MPT_FRAME_HDR *chainBuf;
1901da177e4SLinus Torvalds 	unsigned long flags;
1911da177e4SLinus Torvalds 	int rc;
1921da177e4SLinus Torvalds 	int chain_idx;
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 	dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
1951da177e4SLinus Torvalds 			ioc->name));
1961da177e4SLinus Torvalds 	spin_lock_irqsave(&ioc->FreeQlock, flags);
1971da177e4SLinus Torvalds 	if (!list_empty(&ioc->FreeChainQ)) {
1981da177e4SLinus Torvalds 		int offset;
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 		chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
2011da177e4SLinus Torvalds 				u.frame.linkage.list);
2021da177e4SLinus Torvalds 		list_del(&chainBuf->u.frame.linkage.list);
2031da177e4SLinus Torvalds 		offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
2041da177e4SLinus Torvalds 		chain_idx = offset / ioc->req_sz;
2051da177e4SLinus Torvalds 		rc = SUCCESS;
206c6678e0cSChristoph Hellwig 		dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
207c6678e0cSChristoph Hellwig 			ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
2081da177e4SLinus Torvalds 	} else {
2091da177e4SLinus Torvalds 		rc = FAILED;
2101da177e4SLinus Torvalds 		chain_idx = MPT_HOST_NO_CHAIN;
211c6678e0cSChristoph Hellwig 		dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
2121da177e4SLinus Torvalds 			ioc->name));
2131da177e4SLinus Torvalds 	}
2141da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds 	*retIndex = chain_idx;
2171da177e4SLinus Torvalds 	return rc;
2181da177e4SLinus Torvalds } /* mptscsih_getFreeChainBuffer() */
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2211da177e4SLinus Torvalds /*
2221da177e4SLinus Torvalds  *	mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
2231da177e4SLinus Torvalds  *	SCSIIORequest_t Message Frame.
2241da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
2251da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure
2261da177e4SLinus Torvalds  *	@pReq: Pointer to SCSIIORequest_t structure
2271da177e4SLinus Torvalds  *
2281da177e4SLinus Torvalds  *	Returns ...
2291da177e4SLinus Torvalds  */
2301da177e4SLinus Torvalds static int
2311da177e4SLinus Torvalds mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
2321da177e4SLinus Torvalds 		SCSIIORequest_t *pReq, int req_idx)
2331da177e4SLinus Torvalds {
2341da177e4SLinus Torvalds 	char 	*psge;
2351da177e4SLinus Torvalds 	char	*chainSge;
2361da177e4SLinus Torvalds 	struct scatterlist *sg;
2371da177e4SLinus Torvalds 	int	 frm_sz;
2381da177e4SLinus Torvalds 	int	 sges_left, sg_done;
2391da177e4SLinus Torvalds 	int	 chain_idx = MPT_HOST_NO_CHAIN;
2401da177e4SLinus Torvalds 	int	 sgeOffset;
2411da177e4SLinus Torvalds 	int	 numSgeSlots, numSgeThisFrame;
2421da177e4SLinus Torvalds 	u32	 sgflags, sgdir, thisxfer = 0;
2431da177e4SLinus Torvalds 	int	 chain_dma_off = 0;
2441da177e4SLinus Torvalds 	int	 newIndex;
2451da177e4SLinus Torvalds 	int	 ii;
2461da177e4SLinus Torvalds 	dma_addr_t v2;
2471da177e4SLinus Torvalds 	u32	RequestNB;
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
2501da177e4SLinus Torvalds 	if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {
2511da177e4SLinus Torvalds 		sgdir = MPT_TRANSFER_HOST_TO_IOC;
2521da177e4SLinus Torvalds 	} else {
2531da177e4SLinus Torvalds 		sgdir = MPT_TRANSFER_IOC_TO_HOST;
2541da177e4SLinus Torvalds 	}
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	psge = (char *) &pReq->SGL;
2571da177e4SLinus Torvalds 	frm_sz = ioc->req_sz;
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 	/* Map the data portion, if any.
2601da177e4SLinus Torvalds 	 * sges_left  = 0 if no data transfer.
2611da177e4SLinus Torvalds 	 */
2621928d73fSFUJITA Tomonori 	sges_left = scsi_dma_map(SCpnt);
2631928d73fSFUJITA Tomonori 	if (sges_left < 0)
2641da177e4SLinus Torvalds 		return FAILED;
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	/* Handle the SG case.
2671da177e4SLinus Torvalds 	 */
2681928d73fSFUJITA Tomonori 	sg = scsi_sglist(SCpnt);
2691da177e4SLinus Torvalds 	sg_done  = 0;
2701da177e4SLinus Torvalds 	sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
2711da177e4SLinus Torvalds 	chainSge = NULL;
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 	/* Prior to entering this loop - the following must be set
2741da177e4SLinus Torvalds 	 * current MF:  sgeOffset (bytes)
2751da177e4SLinus Torvalds 	 *              chainSge (Null if original MF is not a chain buffer)
2761da177e4SLinus Torvalds 	 *              sg_done (num SGE done for this MF)
2771da177e4SLinus Torvalds 	 */
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds nextSGEset:
2801da177e4SLinus Torvalds 	numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
2811da177e4SLinus Torvalds 	numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	/* Get first (num - 1) SG elements
2861da177e4SLinus Torvalds 	 * Skip any SG entries with a length of 0
2871da177e4SLinus Torvalds 	 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
2881da177e4SLinus Torvalds 	 */
2891da177e4SLinus Torvalds 	for (ii=0; ii < (numSgeThisFrame-1); ii++) {
2901da177e4SLinus Torvalds 		thisxfer = sg_dma_len(sg);
2911da177e4SLinus Torvalds 		if (thisxfer == 0) {
2921da177e4SLinus Torvalds 			sg ++; /* Get next SG element from the OS */
2931da177e4SLinus Torvalds 			sg_done++;
2941da177e4SLinus Torvalds 			continue;
2951da177e4SLinus Torvalds 		}
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds 		v2 = sg_dma_address(sg);
2981da177e4SLinus Torvalds 		mptscsih_add_sge(psge, sgflags | thisxfer, v2);
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 		sg++;		/* Get next SG element from the OS */
3011da177e4SLinus Torvalds 		psge += (sizeof(u32) + sizeof(dma_addr_t));
3021da177e4SLinus Torvalds 		sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
3031da177e4SLinus Torvalds 		sg_done++;
3041da177e4SLinus Torvalds 	}
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds 	if (numSgeThisFrame == sges_left) {
3071da177e4SLinus Torvalds 		/* Add last element, end of buffer and end of list flags.
3081da177e4SLinus Torvalds 		 */
3091da177e4SLinus Torvalds 		sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
3101da177e4SLinus Torvalds 				MPT_SGE_FLAGS_END_OF_BUFFER |
3111da177e4SLinus Torvalds 				MPT_SGE_FLAGS_END_OF_LIST;
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 		/* Add last SGE and set termination flags.
3141da177e4SLinus Torvalds 		 * Note: Last SGE may have a length of 0 - which should be ok.
3151da177e4SLinus Torvalds 		 */
3161da177e4SLinus Torvalds 		thisxfer = sg_dma_len(sg);
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 		v2 = sg_dma_address(sg);
3191da177e4SLinus Torvalds 		mptscsih_add_sge(psge, sgflags | thisxfer, v2);
3201da177e4SLinus Torvalds 		/*
3211da177e4SLinus Torvalds 		sg++;
3221da177e4SLinus Torvalds 		psge += (sizeof(u32) + sizeof(dma_addr_t));
3231da177e4SLinus Torvalds 		*/
3241da177e4SLinus Torvalds 		sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
3251da177e4SLinus Torvalds 		sg_done++;
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 		if (chainSge) {
3281da177e4SLinus Torvalds 			/* The current buffer is a chain buffer,
3291da177e4SLinus Torvalds 			 * but there is not another one.
3301da177e4SLinus Torvalds 			 * Update the chain element
3311da177e4SLinus Torvalds 			 * Offset and Length fields.
3321da177e4SLinus Torvalds 			 */
3331da177e4SLinus Torvalds 			mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
3341da177e4SLinus Torvalds 		} else {
3351da177e4SLinus Torvalds 			/* The current buffer is the original MF
3361da177e4SLinus Torvalds 			 * and there is no Chain buffer.
3371da177e4SLinus Torvalds 			 */
3381da177e4SLinus Torvalds 			pReq->ChainOffset = 0;
3391da177e4SLinus Torvalds 			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;
340c6678e0cSChristoph Hellwig 			dsgprintk((MYIOC_s_INFO_FMT
3411da177e4SLinus Torvalds 			    "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
3421da177e4SLinus Torvalds 			ioc->RequestNB[req_idx] = RequestNB;
3431da177e4SLinus Torvalds 		}
3441da177e4SLinus Torvalds 	} else {
3451da177e4SLinus Torvalds 		/* At least one chain buffer is needed.
3461da177e4SLinus Torvalds 		 * Complete the first MF
3471da177e4SLinus Torvalds 		 *  - last SGE element, set the LastElement bit
3481da177e4SLinus Torvalds 		 *  - set ChainOffset (words) for orig MF
3491da177e4SLinus Torvalds 		 *             (OR finish previous MF chain buffer)
3501da177e4SLinus Torvalds 		 *  - update MFStructPtr ChainIndex
3511da177e4SLinus Torvalds 		 *  - Populate chain element
3521da177e4SLinus Torvalds 		 * Also
3531da177e4SLinus Torvalds 		 * Loop until done.
3541da177e4SLinus Torvalds 		 */
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds 		dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
3571da177e4SLinus Torvalds 				ioc->name, sg_done));
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 		/* Set LAST_ELEMENT flag for last non-chain element
3601da177e4SLinus Torvalds 		 * in the buffer. Since psge points at the NEXT
3611da177e4SLinus Torvalds 		 * SGE element, go back one SGE element, update the flags
3621da177e4SLinus Torvalds 		 * and reset the pointer. (Note: sgflags & thisxfer are already
3631da177e4SLinus Torvalds 		 * set properly).
3641da177e4SLinus Torvalds 		 */
3651da177e4SLinus Torvalds 		if (sg_done) {
3661da177e4SLinus Torvalds 			u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
3671da177e4SLinus Torvalds 			sgflags = le32_to_cpu(*ptmp);
3681da177e4SLinus Torvalds 			sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
3691da177e4SLinus Torvalds 			*ptmp = cpu_to_le32(sgflags);
3701da177e4SLinus Torvalds 		}
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 		if (chainSge) {
3731da177e4SLinus Torvalds 			/* The current buffer is a chain buffer.
3741da177e4SLinus Torvalds 			 * chainSge points to the previous Chain Element.
3751da177e4SLinus Torvalds 			 * Update its chain element Offset and Length (must
3761da177e4SLinus Torvalds 			 * include chain element size) fields.
3771da177e4SLinus Torvalds 			 * Old chain element is now complete.
3781da177e4SLinus Torvalds 			 */
3791da177e4SLinus Torvalds 			u8 nextChain = (u8) (sgeOffset >> 2);
3801da177e4SLinus Torvalds 			sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
3811da177e4SLinus Torvalds 			mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
3821da177e4SLinus Torvalds 		} else {
3831da177e4SLinus Torvalds 			/* The original MF buffer requires a chain buffer -
3841da177e4SLinus Torvalds 			 * set the offset.
3851da177e4SLinus Torvalds 			 * Last element in this MF is a chain element.
3861da177e4SLinus Torvalds 			 */
3871da177e4SLinus Torvalds 			pReq->ChainOffset = (u8) (sgeOffset >> 2);
3881da177e4SLinus Torvalds 			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;
3891da177e4SLinus Torvalds 			dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
3901da177e4SLinus Torvalds 			ioc->RequestNB[req_idx] = RequestNB;
3911da177e4SLinus Torvalds 		}
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 		sges_left -= sg_done;
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 		/* NOTE: psge points to the beginning of the chain element
3971da177e4SLinus Torvalds 		 * in current buffer. Get a chain buffer.
3981da177e4SLinus Torvalds 		 */
399c6678e0cSChristoph Hellwig 		if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
400c6678e0cSChristoph Hellwig 			dfailprintk((MYIOC_s_INFO_FMT
401c6678e0cSChristoph Hellwig 			    "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
4021da177e4SLinus Torvalds  			    ioc->name, pReq->CDB[0], SCpnt));
4031da177e4SLinus Torvalds 			return FAILED;
404c6678e0cSChristoph Hellwig 		}
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds 		/* Update the tracking arrays.
4071da177e4SLinus Torvalds 		 * If chainSge == NULL, update ReqToChain, else ChainToChain
4081da177e4SLinus Torvalds 		 */
4091da177e4SLinus Torvalds 		if (chainSge) {
4101da177e4SLinus Torvalds 			ioc->ChainToChain[chain_idx] = newIndex;
4111da177e4SLinus Torvalds 		} else {
4121da177e4SLinus Torvalds 			ioc->ReqToChain[req_idx] = newIndex;
4131da177e4SLinus Torvalds 		}
4141da177e4SLinus Torvalds 		chain_idx = newIndex;
4151da177e4SLinus Torvalds 		chain_dma_off = ioc->req_sz * chain_idx;
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds 		/* Populate the chainSGE for the current buffer.
4181da177e4SLinus Torvalds 		 * - Set chain buffer pointer to psge and fill
4191da177e4SLinus Torvalds 		 *   out the Address and Flags fields.
4201da177e4SLinus Torvalds 		 */
4211da177e4SLinus Torvalds 		chainSge = (char *) psge;
4221da177e4SLinus Torvalds 		dsgprintk((KERN_INFO "  Current buff @ %p (index 0x%x)",
4231da177e4SLinus Torvalds 				psge, req_idx));
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 		/* Start the SGE for the next buffer
4261da177e4SLinus Torvalds 		 */
4271da177e4SLinus Torvalds 		psge = (char *) (ioc->ChainBuffer + chain_dma_off);
4281da177e4SLinus Torvalds 		sgeOffset = 0;
4291da177e4SLinus Torvalds 		sg_done = 0;
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds 		dsgprintk((KERN_INFO "  Chain buff @ %p (index 0x%x)\n",
4321da177e4SLinus Torvalds 				psge, chain_idx));
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 		/* Start the SGE for the next buffer
4351da177e4SLinus Torvalds 		 */
4361da177e4SLinus Torvalds 
4371da177e4SLinus Torvalds 		goto nextSGEset;
4381da177e4SLinus Torvalds 	}
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds 	return SUCCESS;
4411da177e4SLinus Torvalds } /* mptscsih_AddSGE() */
4421da177e4SLinus Torvalds 
443786899b0SEric Moore static void
444786899b0SEric Moore mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
445786899b0SEric Moore     U32 SlotStatus)
446786899b0SEric Moore {
447786899b0SEric Moore 	MPT_FRAME_HDR *mf;
448786899b0SEric Moore 	SEPRequest_t 	 *SEPMsg;
449786899b0SEric Moore 
450786899b0SEric Moore 	if (ioc->bus_type == FC)
451786899b0SEric Moore 		return;
452786899b0SEric Moore 
453786899b0SEric Moore 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
454786899b0SEric Moore 		dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
455786899b0SEric Moore 		    ioc->name,__FUNCTION__));
456786899b0SEric Moore 		return;
457786899b0SEric Moore 	}
458786899b0SEric Moore 
459786899b0SEric Moore 	SEPMsg = (SEPRequest_t *)mf;
460786899b0SEric Moore 	SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
461793955f5SEric Moore 	SEPMsg->Bus = vtarget->channel;
462793955f5SEric Moore 	SEPMsg->TargetID = vtarget->id;
463786899b0SEric Moore 	SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
464786899b0SEric Moore 	SEPMsg->SlotStatus = SlotStatus;
465786899b0SEric Moore 	devtverboseprintk((MYIOC_s_WARN_FMT
466793955f5SEric Moore 	    "Sending SEP cmd=%x channel=%d id=%d\n",
467793955f5SEric Moore 	    ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
468786899b0SEric Moore 	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
469786899b0SEric Moore }
470786899b0SEric Moore 
471c6c727a1SEric Moore #ifdef MPT_DEBUG_REPLY
472c6c727a1SEric Moore /**
473c6c727a1SEric Moore  *	mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO
474c6c727a1SEric Moore  *	@ioc: Pointer to MPT_ADAPTER structure
475c6c727a1SEric Moore  *	@ioc_status: U32 IOCStatus word from IOC
476c6c727a1SEric Moore  *	@scsi_status: U8 sam status from target
477c6c727a1SEric Moore  *	@scsi_state: U8 scsi state
478c6c727a1SEric Moore  *	@sc: original scsi cmnd pointer
479c6c727a1SEric Moore  *	@mf: Pointer to MPT request frame
480c6c727a1SEric Moore  *
481c6c727a1SEric Moore  *	Refer to lsi/mpi.h.
482c6c727a1SEric Moore  **/
483c6c727a1SEric Moore static void
484c6c727a1SEric Moore mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status,
485c6c727a1SEric Moore     u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc)
486c6c727a1SEric Moore {
487c6c727a1SEric Moore 	char extend_desc[EVENT_DESCR_STR_SZ];
488c6c727a1SEric Moore 	char *desc = NULL;
489c6c727a1SEric Moore 
490c6c727a1SEric Moore 	switch (ioc_status) {
491c6c727a1SEric Moore 
492c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
493c6c727a1SEric Moore 		desc = "SCSI Invalid Bus";
494c6c727a1SEric Moore 		break;
495c6c727a1SEric Moore 
496c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
497c6c727a1SEric Moore 		desc = "SCSI Invalid TargetID";
498c6c727a1SEric Moore 		break;
499c6c727a1SEric Moore 
500c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
501c6c727a1SEric Moore 		/*
502c6c727a1SEric Moore 		 * Inquiry is issued for device scanning
503c6c727a1SEric Moore 		 */
504c6c727a1SEric Moore 		if (sc->cmnd[0] != 0x12)
505c6c727a1SEric Moore 			desc = "SCSI Device Not There";
506c6c727a1SEric Moore 		break;
507c6c727a1SEric Moore 
508c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
509c6c727a1SEric Moore 		desc = "SCSI Data Overrun";
510c6c727a1SEric Moore 		break;
511c6c727a1SEric Moore 
512c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
513c6c727a1SEric Moore 		desc = "SCSI I/O Data Error";
514c6c727a1SEric Moore 		break;
515c6c727a1SEric Moore 
516c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
517c6c727a1SEric Moore 		desc = "SCSI Protocol Error";
518c6c727a1SEric Moore 		break;
519c6c727a1SEric Moore 
520c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
521c6c727a1SEric Moore 		desc = "SCSI Task Terminated";
522c6c727a1SEric Moore 		break;
523c6c727a1SEric Moore 
524c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
525c6c727a1SEric Moore 		desc = "SCSI Residual Mismatch";
526c6c727a1SEric Moore 		break;
527c6c727a1SEric Moore 
528c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
529c6c727a1SEric Moore 		desc = "SCSI Task Management Failed";
530c6c727a1SEric Moore 		break;
531c6c727a1SEric Moore 
532c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
533c6c727a1SEric Moore 		desc = "SCSI IOC Terminated";
534c6c727a1SEric Moore 		break;
535c6c727a1SEric Moore 
536c6c727a1SEric Moore 	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
537c6c727a1SEric Moore 		desc = "SCSI Ext Terminated";
538c6c727a1SEric Moore 		break;
539c6c727a1SEric Moore 	}
540c6c727a1SEric Moore 
541c6c727a1SEric Moore 	if (!desc)
542c6c727a1SEric Moore 		return;
543c6c727a1SEric Moore 
544c6c727a1SEric Moore 	snprintf(extend_desc, EVENT_DESCR_STR_SZ,
545c6c727a1SEric Moore 	    "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh",
546c6c727a1SEric Moore 		sc->device->host->host_no,
547c6c727a1SEric Moore 		sc->device->channel, sc->device->id, sc->device->lun,
548c6c727a1SEric Moore 		sc->cmnd[0], scsi_status, scsi_state);
549c6c727a1SEric Moore 
550c6c727a1SEric Moore 	printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
551c6c727a1SEric Moore 	    ioc->name, ioc_status, desc, extend_desc);
552c6c727a1SEric Moore }
553c6c727a1SEric Moore #endif
554c6c727a1SEric Moore 
5551da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5561da177e4SLinus Torvalds /*
5571da177e4SLinus Torvalds  *	mptscsih_io_done - Main SCSI IO callback routine registered to
5581da177e4SLinus Torvalds  *	Fusion MPT (base) driver
5591da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
5601da177e4SLinus Torvalds  *	@mf: Pointer to original MPT request frame
5611da177e4SLinus Torvalds  *	@r: Pointer to MPT reply frame (NULL if TurboReply)
5621da177e4SLinus Torvalds  *
5631da177e4SLinus Torvalds  *	This routine is called from mpt.c::mpt_interrupt() at the completion
5641da177e4SLinus Torvalds  *	of any SCSI IO request.
5651da177e4SLinus Torvalds  *	This routine is registered with the Fusion MPT (base) driver at driver
5661da177e4SLinus Torvalds  *	load/init time via the mpt_register() API call.
5671da177e4SLinus Torvalds  *
5681da177e4SLinus Torvalds  *	Returns 1 indicating alloc'd request frame ptr should be freed.
5691da177e4SLinus Torvalds  */
5700d0c7974SMoore, Eric Dean  int
5711da177e4SLinus Torvalds mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
5721da177e4SLinus Torvalds {
5731da177e4SLinus Torvalds 	struct scsi_cmnd	*sc;
5741da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
5751da177e4SLinus Torvalds 	SCSIIORequest_t	*pScsiReq;
5761da177e4SLinus Torvalds 	SCSIIOReply_t	*pScsiReply;
5772254c86dSMoore, Eric 	u16		 req_idx, req_idx_MR;
578786899b0SEric Moore 	VirtDevice	 *vdev;
579786899b0SEric Moore 	VirtTarget	 *vtarget;
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds 	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
5821da177e4SLinus Torvalds 
5831da177e4SLinus Torvalds 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
5842254c86dSMoore, Eric 	req_idx_MR = (mr != NULL) ?
5852254c86dSMoore, Eric 	    le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
5862254c86dSMoore, Eric 	if ((req_idx != req_idx_MR) ||
5872254c86dSMoore, Eric 	    (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
5882254c86dSMoore, Eric 		printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
5892254c86dSMoore, Eric 		    ioc->name);
5902254c86dSMoore, Eric 		printk (MYIOC_s_ERR_FMT
5912254c86dSMoore, Eric 		    "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
5922254c86dSMoore, Eric 		    ioc->name, req_idx, req_idx_MR, mf, mr,
5932254c86dSMoore, Eric 		    hd->ScsiLookup[req_idx_MR]);
5942254c86dSMoore, Eric 		return 0;
5952254c86dSMoore, Eric 	}
5962254c86dSMoore, Eric 
5971da177e4SLinus Torvalds 	sc = hd->ScsiLookup[req_idx];
5983dc0b03fSEric Moore 	hd->ScsiLookup[req_idx] = NULL;
5991da177e4SLinus Torvalds 	if (sc == NULL) {
6001da177e4SLinus Torvalds 		MPIHeader_t *hdr = (MPIHeader_t *)mf;
6011da177e4SLinus Torvalds 
6021da177e4SLinus Torvalds 		/* Remark: writeSDP1 will use the ScsiDoneCtx
6031da177e4SLinus Torvalds 		 * If a SCSI I/O cmd, device disabled by OS and
6041da177e4SLinus Torvalds 		 * completion done. Cannot touch sc struct. Just free mem.
6051da177e4SLinus Torvalds 		 */
6061da177e4SLinus Torvalds 		if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
6071da177e4SLinus Torvalds 			printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
6081da177e4SLinus Torvalds 			ioc->name);
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 		mptscsih_freeChainBuffers(ioc, req_idx);
6111da177e4SLinus Torvalds 		return 1;
6121da177e4SLinus Torvalds 	}
6131da177e4SLinus Torvalds 
6143dc0b03fSEric Moore 	if ((unsigned char *)mf != sc->host_scribble) {
6153dc0b03fSEric Moore 		mptscsih_freeChainBuffers(ioc, req_idx);
6163dc0b03fSEric Moore 		return 1;
6173dc0b03fSEric Moore 	}
6183dc0b03fSEric Moore 
6193dc0b03fSEric Moore 	sc->host_scribble = NULL;
6201da177e4SLinus Torvalds 	sc->result = DID_OK << 16;		/* Set default reply as OK */
6211da177e4SLinus Torvalds 	pScsiReq = (SCSIIORequest_t *) mf;
6221da177e4SLinus Torvalds 	pScsiReply = (SCSIIOReply_t *) mr;
6231da177e4SLinus Torvalds 
624c6678e0cSChristoph Hellwig 	if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
625c6678e0cSChristoph Hellwig 		dmfprintk((MYIOC_s_INFO_FMT
626c6678e0cSChristoph Hellwig 			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
627c6678e0cSChristoph Hellwig 			ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
628c6678e0cSChristoph Hellwig 	}else{
629c6678e0cSChristoph Hellwig 		dmfprintk((MYIOC_s_INFO_FMT
630c6678e0cSChristoph Hellwig 			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
631c6678e0cSChristoph Hellwig 			ioc->name, mf, mr, sc, req_idx));
632c6678e0cSChristoph Hellwig 	}
633c6678e0cSChristoph Hellwig 
6341da177e4SLinus Torvalds 	if (pScsiReply == NULL) {
6351da177e4SLinus Torvalds 		/* special context reply handling */
6361da177e4SLinus Torvalds 		;
6371da177e4SLinus Torvalds 	} else {
6381da177e4SLinus Torvalds 		u32	 xfer_cnt;
6391da177e4SLinus Torvalds 		u16	 status;
6401da177e4SLinus Torvalds 		u8	 scsi_state, scsi_status;
641c6c727a1SEric Moore 		u32	 log_info;
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds 		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6441da177e4SLinus Torvalds 		scsi_state = pScsiReply->SCSIState;
6451da177e4SLinus Torvalds 		scsi_status = pScsiReply->SCSIStatus;
6461da177e4SLinus Torvalds 		xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
6471928d73fSFUJITA Tomonori 		scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
648c6c727a1SEric Moore 		log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
6491da177e4SLinus Torvalds 
650466544d8SMoore, Eric Dean 		/*
651466544d8SMoore, Eric Dean 		 *  if we get a data underrun indication, yet no data was
652466544d8SMoore, Eric Dean 		 *  transferred and the SCSI status indicates that the
653466544d8SMoore, Eric Dean 		 *  command was never started, change the data underrun
654466544d8SMoore, Eric Dean 		 *  to success
655466544d8SMoore, Eric Dean 		 */
656466544d8SMoore, Eric Dean 		if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
657466544d8SMoore, Eric Dean 		    (scsi_status == MPI_SCSI_STATUS_BUSY ||
658466544d8SMoore, Eric Dean 		     scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
659466544d8SMoore, Eric Dean 		     scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
660466544d8SMoore, Eric Dean 			status = MPI_IOCSTATUS_SUCCESS;
661466544d8SMoore, Eric Dean 		}
662466544d8SMoore, Eric Dean 
6631da177e4SLinus Torvalds 		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
6640d0c7974SMoore, Eric Dean  			mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 		/*
6671da177e4SLinus Torvalds 		 *  Look for + dump FCP ResponseInfo[]!
6681da177e4SLinus Torvalds 		 */
669466544d8SMoore, Eric Dean 		if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
670466544d8SMoore, Eric Dean 		    pScsiReply->ResponseInfo) {
671c6c727a1SEric Moore 			printk(KERN_NOTICE "[%d:%d:%d:%d] "
672466544d8SMoore, Eric Dean 			"FCP_ResponseInfo=%08xh\n",
673c6c727a1SEric Moore 			sc->device->host->host_no, sc->device->channel,
674c6c727a1SEric Moore 			sc->device->id, sc->device->lun,
6751da177e4SLinus Torvalds 			le32_to_cpu(pScsiReply->ResponseInfo));
6761da177e4SLinus Torvalds 		}
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds 		switch(status) {
6791da177e4SLinus Torvalds 		case MPI_IOCSTATUS_BUSY:			/* 0x0002 */
6801da177e4SLinus Torvalds 			/* CHECKME!
6811da177e4SLinus Torvalds 			 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
6821da177e4SLinus Torvalds 			 * But not: DID_BUS_BUSY lest one risk
6831da177e4SLinus Torvalds 			 * killing interrupt handler:-(
6841da177e4SLinus Torvalds 			 */
6851da177e4SLinus Torvalds 			sc->result = SAM_STAT_BUSY;
6861da177e4SLinus Torvalds 			break;
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_INVALID_BUS:		/* 0x0041 */
6891da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:	/* 0x0042 */
6901da177e4SLinus Torvalds 			sc->result = DID_BAD_TARGET << 16;
6911da177e4SLinus Torvalds 			break;
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
6941da177e4SLinus Torvalds 			/* Spoof to SCSI Selection Timeout! */
69565207fedSMoore, Eric 			if (ioc->bus_type != FC)
6961da177e4SLinus Torvalds 				sc->result = DID_NO_CONNECT << 16;
69765207fedSMoore, Eric 			/* else fibre, just stall until rescan event */
69865207fedSMoore, Eric 			else
69965207fedSMoore, Eric 				sc->result = DID_REQUEUE << 16;
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 			if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
7021da177e4SLinus Torvalds 				hd->sel_timeout[pScsiReq->TargetID]++;
703786899b0SEric Moore 
704786899b0SEric Moore 			vdev = sc->device->hostdata;
705786899b0SEric Moore 			if (!vdev)
706786899b0SEric Moore 				break;
707786899b0SEric Moore 			vtarget = vdev->vtarget;
708786899b0SEric Moore 			if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
709786899b0SEric Moore 				mptscsih_issue_sep_command(ioc, vtarget,
710786899b0SEric Moore 				    MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
711786899b0SEric Moore 				vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
712786899b0SEric Moore 			}
7131da177e4SLinus Torvalds 			break;
7141da177e4SLinus Torvalds 
7151da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
716bf451522SEric Moore 			if ( ioc->bus_type == SAS ) {
717bf451522SEric Moore 				u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
718bf451522SEric Moore 				if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
719c6c727a1SEric Moore 					if ((log_info & SAS_LOGINFO_MASK)
720c6c727a1SEric Moore 					    == SAS_LOGINFO_NEXUS_LOSS) {
721bf451522SEric Moore 						sc->result = (DID_BUS_BUSY << 16);
722bf451522SEric Moore 						break;
723bf451522SEric Moore 					}
724bf451522SEric Moore 				}
72586dd4242SEric Moore 			} else if (ioc->bus_type == FC) {
72686dd4242SEric Moore 				/*
72786dd4242SEric Moore 				 * The FC IOC may kill a request for variety of
72886dd4242SEric Moore 				 * reasons, some of which may be recovered by a
72986dd4242SEric Moore 				 * retry, some which are unlikely to be
73086dd4242SEric Moore 				 * recovered. Return DID_ERROR instead of
73186dd4242SEric Moore 				 * DID_RESET to permit retry of the command,
73286dd4242SEric Moore 				 * just not an infinite number of them
73386dd4242SEric Moore 				 */
73486dd4242SEric Moore 				sc->result = DID_ERROR << 16;
73586dd4242SEric Moore 				break;
736bf451522SEric Moore 			}
737bf451522SEric Moore 
738bf451522SEric Moore 			/*
739bf451522SEric Moore 			 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
740bf451522SEric Moore 			 */
741bf451522SEric Moore 
742bf451522SEric Moore 		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
7431da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
7441da177e4SLinus Torvalds 			/* Linux handles an unsolicited DID_RESET better
7451da177e4SLinus Torvalds 			 * than an unsolicited DID_ABORT.
7461da177e4SLinus Torvalds 			 */
7471da177e4SLinus Torvalds 			sc->result = DID_RESET << 16;
7481da177e4SLinus Torvalds 
7491da177e4SLinus Torvalds 			break;
7501da177e4SLinus Torvalds 
7511da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
7521928d73fSFUJITA Tomonori 			scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
753466544d8SMoore, Eric Dean 			if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
7541da177e4SLinus Torvalds 				sc->result=DID_SOFT_ERROR << 16;
755466544d8SMoore, Eric Dean 			else /* Sufficient data transfer occurred */
756466544d8SMoore, Eric Dean 				sc->result = (DID_OK << 16) | scsi_status;
757c6678e0cSChristoph Hellwig 			dreplyprintk((KERN_NOTICE
758c6c727a1SEric Moore 			    "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
759c6c727a1SEric Moore 			    sc->result, sc->device->channel, sc->device->id));
7601da177e4SLinus Torvalds 			break;
7611da177e4SLinus Torvalds 
7621da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
7631da177e4SLinus Torvalds 			/*
7641da177e4SLinus Torvalds 			 *  Do upfront check for valid SenseData and give it
7651da177e4SLinus Torvalds 			 *  precedence!
7661da177e4SLinus Torvalds 			 */
7671da177e4SLinus Torvalds 			sc->result = (DID_OK << 16) | scsi_status;
7681da177e4SLinus Torvalds 			if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
7691da177e4SLinus Torvalds 				/* Have already saved the status and sense data
7701da177e4SLinus Torvalds 				 */
7711da177e4SLinus Torvalds 				;
7721da177e4SLinus Torvalds 			} else {
7731da177e4SLinus Torvalds 				if (xfer_cnt < sc->underflow) {
774466544d8SMoore, Eric Dean 					if (scsi_status == SAM_STAT_BUSY)
775466544d8SMoore, Eric Dean 						sc->result = SAM_STAT_BUSY;
776466544d8SMoore, Eric Dean 					else
7771da177e4SLinus Torvalds 						sc->result = DID_SOFT_ERROR << 16;
7781da177e4SLinus Torvalds 				}
7791da177e4SLinus Torvalds 				if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
7801da177e4SLinus Torvalds 					/* What to do?
7811da177e4SLinus Torvalds 				 	*/
7821da177e4SLinus Torvalds 					sc->result = DID_SOFT_ERROR << 16;
7831da177e4SLinus Torvalds 				}
7841da177e4SLinus Torvalds 				else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
7851da177e4SLinus Torvalds 					/*  Not real sure here either...  */
7861da177e4SLinus Torvalds 					sc->result = DID_RESET << 16;
7871da177e4SLinus Torvalds 				}
7881da177e4SLinus Torvalds 			}
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds 			dreplyprintk((KERN_NOTICE "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
7911da177e4SLinus Torvalds 					sc->underflow));
7921da177e4SLinus Torvalds 			dreplyprintk((KERN_NOTICE "  ActBytesXferd=%02xh\n", xfer_cnt));
7931da177e4SLinus Torvalds 			/* Report Queue Full
7941da177e4SLinus Torvalds 			 */
7951da177e4SLinus Torvalds 			if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
7961da177e4SLinus Torvalds 				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds 			break;
7991da177e4SLinus Torvalds 
8007e55147fSMoore, Eric 		case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:		/* 0x0044 */
8011928d73fSFUJITA Tomonori 			scsi_set_resid(sc, 0);
8021da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
8031da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
8041da177e4SLinus Torvalds 			sc->result = (DID_OK << 16) | scsi_status;
8051da177e4SLinus Torvalds 			if (scsi_state == 0) {
8061da177e4SLinus Torvalds 				;
8071da177e4SLinus Torvalds 			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
8081da177e4SLinus Torvalds 				/*
8091da177e4SLinus Torvalds 				 * If running against circa 200003dd 909 MPT f/w,
8101da177e4SLinus Torvalds 				 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
8111da177e4SLinus Torvalds 				 * (QUEUE_FULL) returned from device! --> get 0x0000?128
8121da177e4SLinus Torvalds 				 * and with SenseBytes set to 0.
8131da177e4SLinus Torvalds 				 */
8141da177e4SLinus Torvalds 				if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
8151da177e4SLinus Torvalds 					mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds 			}
8181da177e4SLinus Torvalds 			else if (scsi_state &
8191da177e4SLinus Torvalds 			         (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
8201da177e4SLinus Torvalds 			   ) {
8211da177e4SLinus Torvalds 				/*
8221da177e4SLinus Torvalds 				 * What to do?
8231da177e4SLinus Torvalds 				 */
8241da177e4SLinus Torvalds 				sc->result = DID_SOFT_ERROR << 16;
8251da177e4SLinus Torvalds 			}
8261da177e4SLinus Torvalds 			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
8271da177e4SLinus Torvalds 				/*  Not real sure here either...  */
8281da177e4SLinus Torvalds 				sc->result = DID_RESET << 16;
8291da177e4SLinus Torvalds 			}
8301da177e4SLinus Torvalds 			else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
8311da177e4SLinus Torvalds 				/* Device Inq. data indicates that it supports
8321da177e4SLinus Torvalds 				 * QTags, but rejects QTag messages.
8331da177e4SLinus Torvalds 				 * This command completed OK.
8341da177e4SLinus Torvalds 				 *
8351da177e4SLinus Torvalds 				 * Not real sure here either so do nothing...  */
8361da177e4SLinus Torvalds 			}
8371da177e4SLinus Torvalds 
8381da177e4SLinus Torvalds 			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
8391da177e4SLinus Torvalds 				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
8401da177e4SLinus Torvalds 
8411da177e4SLinus Torvalds 			/* Add handling of:
8421da177e4SLinus Torvalds 			 * Reservation Conflict, Busy,
8431da177e4SLinus Torvalds 			 * Command Terminated, CHECK
8441da177e4SLinus Torvalds 			 */
8451da177e4SLinus Torvalds 			break;
8461da177e4SLinus Torvalds 
8471da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
8481da177e4SLinus Torvalds 			sc->result = DID_SOFT_ERROR << 16;
8491da177e4SLinus Torvalds 			break;
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_FUNCTION:		/* 0x0001 */
8521da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_SGL:			/* 0x0003 */
8531da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INTERNAL_ERROR:		/* 0x0004 */
8541da177e4SLinus Torvalds 		case MPI_IOCSTATUS_RESERVED:			/* 0x0005 */
8551da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:	/* 0x0006 */
8561da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_FIELD:		/* 0x0007 */
8571da177e4SLinus Torvalds 		case MPI_IOCSTATUS_INVALID_STATE:		/* 0x0008 */
8581da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
8591da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:	/* 0x004A */
8601da177e4SLinus Torvalds 		default:
8611da177e4SLinus Torvalds 			/*
8621da177e4SLinus Torvalds 			 * What to do?
8631da177e4SLinus Torvalds 			 */
8641da177e4SLinus Torvalds 			sc->result = DID_SOFT_ERROR << 16;
8651da177e4SLinus Torvalds 			break;
8661da177e4SLinus Torvalds 
8671da177e4SLinus Torvalds 		}	/* switch(status) */
8681da177e4SLinus Torvalds 
869c6c727a1SEric Moore #ifdef MPT_DEBUG_REPLY
870c6c727a1SEric Moore 		if (sc->result) {
871c6c727a1SEric Moore 
872c6c727a1SEric Moore 			mptscsih_iocstatus_info_scsiio(ioc, status,
873c6c727a1SEric Moore 			    scsi_status, scsi_state, sc);
874c6c727a1SEric Moore 
875c6c727a1SEric Moore 			dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x "
876c6c727a1SEric Moore 			    "result=0x%08x\n\tiocstatus=0x%04X "
877c6c727a1SEric Moore 			    "scsi_state=0x%02X scsi_status=0x%02X "
878c6c727a1SEric Moore 			    "loginfo=0x%08X\n", __FUNCTION__,
879c6c727a1SEric Moore 			    sc->device->host->host_no, sc->device->channel, sc->device->id,
880c6c727a1SEric Moore 			    sc->device->lun, sc->cmnd[0], sc->result, status,
881c6c727a1SEric Moore 			    scsi_state, scsi_status, log_info));
882c6c727a1SEric Moore 
883c6c727a1SEric Moore 			dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
884c6c727a1SEric Moore 				      "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
8851928d73fSFUJITA Tomonori 				      sc->device->host->host_no,
8861928d73fSFUJITA Tomonori 				      sc->device->channel, sc->device->id,
8871928d73fSFUJITA Tomonori 				      sc->device->lun, scsi_get_resid(sc),
8881928d73fSFUJITA Tomonori 				      scsi_bufflen(sc), xfer_cnt));
889c6c727a1SEric Moore 		}
890c6c727a1SEric Moore #endif
891c6c727a1SEric Moore 
8921da177e4SLinus Torvalds 	} /* end of address reply case */
8931da177e4SLinus Torvalds 
8941da177e4SLinus Torvalds 	/* Unmap the DMA buffers, if any. */
8951928d73fSFUJITA Tomonori 	scsi_dma_unmap(sc);
8961da177e4SLinus Torvalds 
8971da177e4SLinus Torvalds 	sc->scsi_done(sc);		/* Issue the command callback */
8981da177e4SLinus Torvalds 
8991da177e4SLinus Torvalds 	/* Free Chain buffers */
9001da177e4SLinus Torvalds 	mptscsih_freeChainBuffers(ioc, req_idx);
9011da177e4SLinus Torvalds 	return 1;
9021da177e4SLinus Torvalds }
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds /*
9051da177e4SLinus Torvalds  *	mptscsih_flush_running_cmds - For each command found, search
9061da177e4SLinus Torvalds  *		Scsi_Host instance taskQ and reply to OS.
9071da177e4SLinus Torvalds  *		Called only if recovering from a FW reload.
9081da177e4SLinus Torvalds  *	@hd: Pointer to a SCSI HOST structure
9091da177e4SLinus Torvalds  *
9101da177e4SLinus Torvalds  *	Returns: None.
9111da177e4SLinus Torvalds  *
9121da177e4SLinus Torvalds  *	Must be called while new I/Os are being queued.
9131da177e4SLinus Torvalds  */
9141da177e4SLinus Torvalds static void
9151da177e4SLinus Torvalds mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
9161da177e4SLinus Torvalds {
9171da177e4SLinus Torvalds 	MPT_ADAPTER *ioc = hd->ioc;
9181da177e4SLinus Torvalds 	struct scsi_cmnd	*SCpnt;
9191da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
9201da177e4SLinus Torvalds 	int		 ii;
9211da177e4SLinus Torvalds 	int		 max = ioc->req_depth;
9221da177e4SLinus Torvalds 
9231da177e4SLinus Torvalds 	dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
9241da177e4SLinus Torvalds 	for (ii= 0; ii < max; ii++) {
9251da177e4SLinus Torvalds 		if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
9261da177e4SLinus Torvalds 
9271da177e4SLinus Torvalds 			/* Command found.
9281da177e4SLinus Torvalds 			 */
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 			/* Null ScsiLookup index
9311da177e4SLinus Torvalds 			 */
9321da177e4SLinus Torvalds 			hd->ScsiLookup[ii] = NULL;
9331da177e4SLinus Torvalds 
9341da177e4SLinus Torvalds 			mf = MPT_INDEX_2_MFPTR(ioc, ii);
9351da177e4SLinus Torvalds 			dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
9361da177e4SLinus Torvalds 					mf, SCpnt));
9371da177e4SLinus Torvalds 
9383dc0b03fSEric Moore 			/* Free Chain buffers */
9393dc0b03fSEric Moore 			mptscsih_freeChainBuffers(ioc, ii);
9403dc0b03fSEric Moore 
9413dc0b03fSEric Moore 			/* Free Message frames */
9423dc0b03fSEric Moore 			mpt_free_msg_frame(ioc, mf);
9433dc0b03fSEric Moore 
9443dc0b03fSEric Moore 			if ((unsigned char *)mf != SCpnt->host_scribble)
9453dc0b03fSEric Moore 				continue;
9463dc0b03fSEric Moore 
9471da177e4SLinus Torvalds 			/* Set status, free OS resources (SG DMA buffers)
9481da177e4SLinus Torvalds 			 * Do OS callback
9491da177e4SLinus Torvalds 			 */
9501928d73fSFUJITA Tomonori 			scsi_dma_unmap(SCpnt);
9511928d73fSFUJITA Tomonori 
9521da177e4SLinus Torvalds 			SCpnt->result = DID_RESET << 16;
9531da177e4SLinus Torvalds 			SCpnt->host_scribble = NULL;
9541da177e4SLinus Torvalds 
9551da177e4SLinus Torvalds 			SCpnt->scsi_done(SCpnt);	/* Issue the command callback */
9561da177e4SLinus Torvalds 		}
9571da177e4SLinus Torvalds 	}
9581da177e4SLinus Torvalds 
9591da177e4SLinus Torvalds 	return;
9601da177e4SLinus Torvalds }
9611da177e4SLinus Torvalds 
9621da177e4SLinus Torvalds /*
9631da177e4SLinus Torvalds  *	mptscsih_search_running_cmds - Delete any commands associated
9641da177e4SLinus Torvalds  *		with the specified target and lun. Function called only
9651da177e4SLinus Torvalds  *		when a lun is disable by mid-layer.
9661da177e4SLinus Torvalds  *		Do NOT access the referenced scsi_cmnd structure or
9671da177e4SLinus Torvalds  *		members. Will cause either a paging or NULL ptr error.
96805e8ec17SMichael Reed  *		(BUT, BUT, BUT, the code does reference it! - mdr)
9691da177e4SLinus Torvalds  *      @hd: Pointer to a SCSI HOST structure
970c7c82987SMoore, Eric Dean  *	@vdevice: per device private data
9711da177e4SLinus Torvalds  *
9721da177e4SLinus Torvalds  *	Returns: None.
9731da177e4SLinus Torvalds  *
9741da177e4SLinus Torvalds  *	Called from slave_destroy.
9751da177e4SLinus Torvalds  */
9761da177e4SLinus Torvalds static void
977c7c82987SMoore, Eric Dean mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
9781da177e4SLinus Torvalds {
9791da177e4SLinus Torvalds 	SCSIIORequest_t	*mf = NULL;
9801da177e4SLinus Torvalds 	int		 ii;
9811da177e4SLinus Torvalds 	int		 max = hd->ioc->req_depth;
982466544d8SMoore, Eric Dean 	struct scsi_cmnd *sc;
983793955f5SEric Moore 	struct scsi_lun  lun;
9841da177e4SLinus Torvalds 
985793955f5SEric Moore 	dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
986793955f5SEric Moore 	    vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
9871da177e4SLinus Torvalds 
9881da177e4SLinus Torvalds 	for (ii=0; ii < max; ii++) {
989466544d8SMoore, Eric Dean 		if ((sc = hd->ScsiLookup[ii]) != NULL) {
9901da177e4SLinus Torvalds 
9911da177e4SLinus Torvalds 			mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
9923dc0b03fSEric Moore 			if (mf == NULL)
9933dc0b03fSEric Moore 				continue;
994793955f5SEric Moore 			int_to_scsilun(vdevice->lun, &lun);
995793955f5SEric Moore 			if ((mf->Bus != vdevice->vtarget->channel) ||
996793955f5SEric Moore 			    (mf->TargetID != vdevice->vtarget->id) ||
997793955f5SEric Moore 			    memcmp(lun.scsi_lun, mf->LUN, 8))
9981da177e4SLinus Torvalds 				continue;
999793955f5SEric Moore 			dsprintk(( "search_running: found (sc=%p, mf = %p) "
1000793955f5SEric Moore 			    "channel %d id %d, lun %d \n", hd->ScsiLookup[ii],
1001793955f5SEric Moore 			    mf, mf->Bus, mf->TargetID, vdevice->lun));
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds 			/* Cleanup
10041da177e4SLinus Torvalds 			 */
10051da177e4SLinus Torvalds 			hd->ScsiLookup[ii] = NULL;
10061da177e4SLinus Torvalds 			mptscsih_freeChainBuffers(hd->ioc, ii);
10071da177e4SLinus Torvalds 			mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
10083dc0b03fSEric Moore 			if ((unsigned char *)mf != sc->host_scribble)
10093dc0b03fSEric Moore 				continue;
10101928d73fSFUJITA Tomonori 			scsi_dma_unmap(sc);
10111928d73fSFUJITA Tomonori 
1012466544d8SMoore, Eric Dean 			sc->host_scribble = NULL;
1013466544d8SMoore, Eric Dean 			sc->result = DID_NO_CONNECT << 16;
1014466544d8SMoore, Eric Dean 			sc->scsi_done(sc);
10151da177e4SLinus Torvalds 		}
10161da177e4SLinus Torvalds 	}
10171da177e4SLinus Torvalds 	return;
10181da177e4SLinus Torvalds }
10191da177e4SLinus Torvalds 
10201da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10211da177e4SLinus Torvalds 
10221da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10231da177e4SLinus Torvalds /*
10241da177e4SLinus Torvalds  *	mptscsih_report_queue_full - Report QUEUE_FULL status returned
10251da177e4SLinus Torvalds  *	from a SCSI target device.
10261da177e4SLinus Torvalds  *	@sc: Pointer to scsi_cmnd structure
10271da177e4SLinus Torvalds  *	@pScsiReply: Pointer to SCSIIOReply_t
10281da177e4SLinus Torvalds  *	@pScsiReq: Pointer to original SCSI request
10291da177e4SLinus Torvalds  *
10301da177e4SLinus Torvalds  *	This routine periodically reports QUEUE_FULL status returned from a
10311da177e4SLinus Torvalds  *	SCSI target device.  It reports this to the console via kernel
10321da177e4SLinus Torvalds  *	printk() API call, not more than once every 10 seconds.
10331da177e4SLinus Torvalds  */
10341da177e4SLinus Torvalds static void
10351da177e4SLinus Torvalds mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
10361da177e4SLinus Torvalds {
10371da177e4SLinus Torvalds 	long time = jiffies;
10381da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
10391da177e4SLinus Torvalds 
10400d0c7974SMoore, Eric Dean  	if (sc->device == NULL)
10410d0c7974SMoore, Eric Dean  		return;
10420d0c7974SMoore, Eric Dean  	if (sc->device->host == NULL)
10430d0c7974SMoore, Eric Dean  		return;
10440d0c7974SMoore, Eric Dean  	if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
10450d0c7974SMoore, Eric Dean  		return;
10461da177e4SLinus Torvalds 
10470d0c7974SMoore, Eric Dean  	if (time - hd->last_queue_full > 10 * HZ) {
10480d0c7974SMoore, Eric Dean  		dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
10490d0c7974SMoore, Eric Dean  				hd->ioc->name, 0, sc->device->id, sc->device->lun));
10500d0c7974SMoore, Eric Dean  		hd->last_queue_full = time;
10511da177e4SLinus Torvalds 	}
10521da177e4SLinus Torvalds }
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10551da177e4SLinus Torvalds /*
10561da177e4SLinus Torvalds  *	mptscsih_remove - Removed scsi devices
10571da177e4SLinus Torvalds  *	@pdev: Pointer to pci_dev structure
10581da177e4SLinus Torvalds  *
10591da177e4SLinus Torvalds  *
10601da177e4SLinus Torvalds  */
10610d0c7974SMoore, Eric Dean  void
10621da177e4SLinus Torvalds mptscsih_remove(struct pci_dev *pdev)
10631da177e4SLinus Torvalds {
10641da177e4SLinus Torvalds 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
10651da177e4SLinus Torvalds 	struct Scsi_Host 	*host = ioc->sh;
10661da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
10670d0c7974SMoore, Eric Dean  	int sz1;
10681da177e4SLinus Torvalds 
1069466544d8SMoore, Eric Dean 	if(!host) {
1070466544d8SMoore, Eric Dean 		mpt_detach(pdev);
10711da177e4SLinus Torvalds 		return;
1072466544d8SMoore, Eric Dean 	}
10731da177e4SLinus Torvalds 
10741da177e4SLinus Torvalds 	scsi_remove_host(host);
10751da177e4SLinus Torvalds 
10760d0c7974SMoore, Eric Dean  	if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
10770d0c7974SMoore, Eric Dean  		return;
10780d0c7974SMoore, Eric Dean  
1079d18c3db5SGreg Kroah-Hartman 	mptscsih_shutdown(pdev);
10801da177e4SLinus Torvalds 
10811da177e4SLinus Torvalds 	sz1=0;
10821da177e4SLinus Torvalds 
10831da177e4SLinus Torvalds 	if (hd->ScsiLookup != NULL) {
10841da177e4SLinus Torvalds 		sz1 = hd->ioc->req_depth * sizeof(void *);
10851da177e4SLinus Torvalds 		kfree(hd->ScsiLookup);
10861da177e4SLinus Torvalds 		hd->ScsiLookup = NULL;
10871da177e4SLinus Torvalds 	}
10881da177e4SLinus Torvalds 
10891da177e4SLinus Torvalds 	dprintk((MYIOC_s_INFO_FMT
10901da177e4SLinus Torvalds 	    "Free'd ScsiLookup (%d) memory\n",
10911da177e4SLinus Torvalds 	    hd->ioc->name, sz1));
10921da177e4SLinus Torvalds 
10930d0c7974SMoore, Eric Dean  	kfree(hd->info_kbuf);
10940d0c7974SMoore, Eric Dean  
10951da177e4SLinus Torvalds 	/* NULL the Scsi_Host pointer
10961da177e4SLinus Torvalds 	 */
10971da177e4SLinus Torvalds 	hd->ioc->sh = NULL;
10981da177e4SLinus Torvalds 
10991da177e4SLinus Torvalds 	scsi_host_put(host);
11000d0c7974SMoore, Eric Dean  
11010d0c7974SMoore, Eric Dean  	mpt_detach(pdev);
11021da177e4SLinus Torvalds 
11031da177e4SLinus Torvalds }
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11061da177e4SLinus Torvalds /*
11071da177e4SLinus Torvalds  *	mptscsih_shutdown - reboot notifier
11081da177e4SLinus Torvalds  *
11091da177e4SLinus Torvalds  */
11100d0c7974SMoore, Eric Dean  void
1111d18c3db5SGreg Kroah-Hartman mptscsih_shutdown(struct pci_dev *pdev)
11121da177e4SLinus Torvalds {
1113d18c3db5SGreg Kroah-Hartman 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
11141da177e4SLinus Torvalds 	struct Scsi_Host 	*host = ioc->sh;
11151da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
11161da177e4SLinus Torvalds 
11171da177e4SLinus Torvalds 	if(!host)
11181da177e4SLinus Torvalds 		return;
11191da177e4SLinus Torvalds 
11201da177e4SLinus Torvalds 	hd = (MPT_SCSI_HOST *)host->hostdata;
11211da177e4SLinus Torvalds 
11221da177e4SLinus Torvalds }
11231da177e4SLinus Torvalds 
11241da177e4SLinus Torvalds #ifdef CONFIG_PM
11251da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11261da177e4SLinus Torvalds /*
11270d0c7974SMoore, Eric Dean   *	mptscsih_suspend - Fusion MPT scsi driver suspend routine.
11281da177e4SLinus Torvalds  *
11291da177e4SLinus Torvalds  *
11301da177e4SLinus Torvalds  */
11310d0c7974SMoore, Eric Dean  int
11328d189f72SPavel Machek mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
11331da177e4SLinus Torvalds {
1134d18c3db5SGreg Kroah-Hartman 	mptscsih_shutdown(pdev);
11350d0c7974SMoore, Eric Dean  	return mpt_suspend(pdev,state);
11361da177e4SLinus Torvalds }
11371da177e4SLinus Torvalds 
11381da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11391da177e4SLinus Torvalds /*
11401da177e4SLinus Torvalds  *	mptscsih_resume - Fusion MPT scsi driver resume routine.
11411da177e4SLinus Torvalds  *
11421da177e4SLinus Torvalds  *
11431da177e4SLinus Torvalds  */
11440d0c7974SMoore, Eric Dean  int
11451da177e4SLinus Torvalds mptscsih_resume(struct pci_dev *pdev)
11461da177e4SLinus Torvalds {
1147b364fd50SHorms 	return mpt_resume(pdev);
11481da177e4SLinus Torvalds }
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds #endif
11511da177e4SLinus Torvalds 
11521da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11531da177e4SLinus Torvalds /**
11541da177e4SLinus Torvalds  *	mptscsih_info - Return information about MPT adapter
11551da177e4SLinus Torvalds  *	@SChost: Pointer to Scsi_Host structure
11561da177e4SLinus Torvalds  *
11571da177e4SLinus Torvalds  *	(linux scsi_host_template.info routine)
11581da177e4SLinus Torvalds  *
11591da177e4SLinus Torvalds  *	Returns pointer to buffer where information was written.
11601da177e4SLinus Torvalds  */
11610d0c7974SMoore, Eric Dean  const char *
11621da177e4SLinus Torvalds mptscsih_info(struct Scsi_Host *SChost)
11631da177e4SLinus Torvalds {
11641da177e4SLinus Torvalds 	MPT_SCSI_HOST *h;
11651da177e4SLinus Torvalds 	int size = 0;
11661da177e4SLinus Torvalds 
11671da177e4SLinus Torvalds 	h = (MPT_SCSI_HOST *)SChost->hostdata;
11680d0c7974SMoore, Eric Dean  
11691da177e4SLinus Torvalds 	if (h) {
11700d0c7974SMoore, Eric Dean  		if (h->info_kbuf == NULL)
11710d0c7974SMoore, Eric Dean  			if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
11720d0c7974SMoore, Eric Dean  				return h->info_kbuf;
11730d0c7974SMoore, Eric Dean  		h->info_kbuf[0] = '\0';
11740d0c7974SMoore, Eric Dean  
11750d0c7974SMoore, Eric Dean  		mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
11760d0c7974SMoore, Eric Dean  		h->info_kbuf[size-1] = '\0';
11771da177e4SLinus Torvalds 	}
11781da177e4SLinus Torvalds 
11790d0c7974SMoore, Eric Dean  	return h->info_kbuf;
11801da177e4SLinus Torvalds }
11811da177e4SLinus Torvalds 
11821da177e4SLinus Torvalds struct info_str {
11831da177e4SLinus Torvalds 	char *buffer;
11841da177e4SLinus Torvalds 	int   length;
11851da177e4SLinus Torvalds 	int   offset;
11861da177e4SLinus Torvalds 	int   pos;
11871da177e4SLinus Torvalds };
11881da177e4SLinus Torvalds 
11890d0c7974SMoore, Eric Dean  static void
11900d0c7974SMoore, Eric Dean  mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
11911da177e4SLinus Torvalds {
11921da177e4SLinus Torvalds 	if (info->pos + len > info->length)
11931da177e4SLinus Torvalds 		len = info->length - info->pos;
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds 	if (info->pos + len < info->offset) {
11961da177e4SLinus Torvalds 		info->pos += len;
11971da177e4SLinus Torvalds 		return;
11981da177e4SLinus Torvalds 	}
11991da177e4SLinus Torvalds 
12001da177e4SLinus Torvalds 	if (info->pos < info->offset) {
12011da177e4SLinus Torvalds 	        data += (info->offset - info->pos);
12021da177e4SLinus Torvalds 	        len  -= (info->offset - info->pos);
12031da177e4SLinus Torvalds 	}
12041da177e4SLinus Torvalds 
12051da177e4SLinus Torvalds 	if (len > 0) {
12061da177e4SLinus Torvalds                 memcpy(info->buffer + info->pos, data, len);
12071da177e4SLinus Torvalds                 info->pos += len;
12081da177e4SLinus Torvalds 	}
12091da177e4SLinus Torvalds }
12101da177e4SLinus Torvalds 
12110d0c7974SMoore, Eric Dean  static int
12120d0c7974SMoore, Eric Dean  mptscsih_copy_info(struct info_str *info, char *fmt, ...)
12131da177e4SLinus Torvalds {
12141da177e4SLinus Torvalds 	va_list args;
12151da177e4SLinus Torvalds 	char buf[81];
12161da177e4SLinus Torvalds 	int len;
12171da177e4SLinus Torvalds 
12181da177e4SLinus Torvalds 	va_start(args, fmt);
12191da177e4SLinus Torvalds 	len = vsprintf(buf, fmt, args);
12201da177e4SLinus Torvalds 	va_end(args);
12211da177e4SLinus Torvalds 
12220d0c7974SMoore, Eric Dean  	mptscsih_copy_mem_info(info, buf, len);
12231da177e4SLinus Torvalds 	return len;
12241da177e4SLinus Torvalds }
12251da177e4SLinus Torvalds 
12260d0c7974SMoore, Eric Dean  static int
12270d0c7974SMoore, Eric Dean  mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
12281da177e4SLinus Torvalds {
12291da177e4SLinus Torvalds 	struct info_str info;
12301da177e4SLinus Torvalds 
12311da177e4SLinus Torvalds 	info.buffer	= pbuf;
12321da177e4SLinus Torvalds 	info.length	= len;
12331da177e4SLinus Torvalds 	info.offset	= offset;
12341da177e4SLinus Torvalds 	info.pos	= 0;
12351da177e4SLinus Torvalds 
12360d0c7974SMoore, Eric Dean  	mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
12370d0c7974SMoore, Eric Dean  	mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
12380d0c7974SMoore, Eric Dean  	mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
12390d0c7974SMoore, Eric Dean  	mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
12401da177e4SLinus Torvalds 
12411da177e4SLinus Torvalds 	return ((info.pos > info.offset) ? info.pos - info.offset : 0);
12421da177e4SLinus Torvalds }
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12451da177e4SLinus Torvalds /**
12461da177e4SLinus Torvalds  *	mptscsih_proc_info - Return information about MPT adapter
1247d9489fb6SRandy Dunlap  * 	@host:   scsi host struct
1248d9489fb6SRandy Dunlap  * 	@buffer: if write, user data; if read, buffer for user
1249d9489fb6SRandy Dunlap  *	@start: returns the buffer address
1250d9489fb6SRandy Dunlap  * 	@offset: if write, 0; if read, the current offset into the buffer from
1251d9489fb6SRandy Dunlap  * 		 the previous read.
1252d9489fb6SRandy Dunlap  * 	@length: if write, return length;
1253d9489fb6SRandy Dunlap  *	@func:   write = 1; read = 0
12541da177e4SLinus Torvalds  *
12551da177e4SLinus Torvalds  *	(linux scsi_host_template.info routine)
12561da177e4SLinus Torvalds  */
12570d0c7974SMoore, Eric Dean  int
12581da177e4SLinus Torvalds mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
12591da177e4SLinus Torvalds 			int length, int func)
12601da177e4SLinus Torvalds {
12611da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
12621da177e4SLinus Torvalds 	MPT_ADAPTER	*ioc = hd->ioc;
12631da177e4SLinus Torvalds 	int size = 0;
12641da177e4SLinus Torvalds 
12651da177e4SLinus Torvalds 	if (func) {
12661da177e4SLinus Torvalds 		/*
12671da177e4SLinus Torvalds 		 * write is not supported
12681da177e4SLinus Torvalds 		 */
12691da177e4SLinus Torvalds 	} else {
12701da177e4SLinus Torvalds 		if (start)
12711da177e4SLinus Torvalds 			*start = buffer;
12721da177e4SLinus Torvalds 
12731da177e4SLinus Torvalds 		size = mptscsih_host_info(ioc, buffer, offset, length);
12741da177e4SLinus Torvalds 	}
12751da177e4SLinus Torvalds 
12761da177e4SLinus Torvalds 	return size;
12771da177e4SLinus Torvalds }
12781da177e4SLinus Torvalds 
12791da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12801da177e4SLinus Torvalds #define ADD_INDEX_LOG(req_ent)	do { } while(0)
12811da177e4SLinus Torvalds 
12821da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12831da177e4SLinus Torvalds /**
12841da177e4SLinus Torvalds  *	mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
12851da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure
12861da177e4SLinus Torvalds  *	@done: Pointer SCSI mid-layer IO completion function
12871da177e4SLinus Torvalds  *
12881da177e4SLinus Torvalds  *	(linux scsi_host_template.queuecommand routine)
12891da177e4SLinus Torvalds  *	This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
12901da177e4SLinus Torvalds  *	from a linux scsi_cmnd request and send it to the IOC.
12911da177e4SLinus Torvalds  *
12921da177e4SLinus Torvalds  *	Returns 0. (rtn value discarded by linux scsi mid-layer)
12931da177e4SLinus Torvalds  */
12940d0c7974SMoore, Eric Dean  int
12951da177e4SLinus Torvalds mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
12961da177e4SLinus Torvalds {
12971da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
12981da177e4SLinus Torvalds 	MPT_FRAME_HDR		*mf;
12991da177e4SLinus Torvalds 	SCSIIORequest_t		*pScsiReq;
1300c7c82987SMoore, Eric Dean 	VirtDevice		*vdev = SCpnt->device->hostdata;
13011da177e4SLinus Torvalds 	int	 lun;
13021da177e4SLinus Torvalds 	u32	 datalen;
13031da177e4SLinus Torvalds 	u32	 scsictl;
13041da177e4SLinus Torvalds 	u32	 scsidir;
13051da177e4SLinus Torvalds 	u32	 cmd_len;
13061da177e4SLinus Torvalds 	int	 my_idx;
13071da177e4SLinus Torvalds 	int	 ii;
13081da177e4SLinus Torvalds 
13091da177e4SLinus Torvalds 	hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
13101da177e4SLinus Torvalds 	lun = SCpnt->device->lun;
13111da177e4SLinus Torvalds 	SCpnt->scsi_done = done;
13121da177e4SLinus Torvalds 
13131da177e4SLinus Torvalds 	dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
13141da177e4SLinus Torvalds 			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds 	if (hd->resetPending) {
13171da177e4SLinus Torvalds 		dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
13181da177e4SLinus Torvalds 			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
13191da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
13201da177e4SLinus Torvalds 	}
13211da177e4SLinus Torvalds 
13221da177e4SLinus Torvalds 	/*
13231da177e4SLinus Torvalds 	 *  Put together a MPT SCSI request...
13241da177e4SLinus Torvalds 	 */
13250d0c7974SMoore, Eric Dean  	if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
13261da177e4SLinus Torvalds 		dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
13271da177e4SLinus Torvalds 				hd->ioc->name));
13281da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
13291da177e4SLinus Torvalds 	}
13301da177e4SLinus Torvalds 
13311da177e4SLinus Torvalds 	pScsiReq = (SCSIIORequest_t *) mf;
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds 	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
13341da177e4SLinus Torvalds 
13351da177e4SLinus Torvalds 	ADD_INDEX_LOG(my_idx);
13361da177e4SLinus Torvalds 
13370d0c7974SMoore, Eric Dean  	/*    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
13381da177e4SLinus Torvalds 	 *    Seems we may receive a buffer (datalen>0) even when there
13391da177e4SLinus Torvalds 	 *    will be no data transfer!  GRRRRR...
13401da177e4SLinus Torvalds 	 */
13411da177e4SLinus Torvalds 	if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
13421928d73fSFUJITA Tomonori 		datalen = scsi_bufflen(SCpnt);
13431da177e4SLinus Torvalds 		scsidir = MPI_SCSIIO_CONTROL_READ;	/* DATA IN  (host<--ioc<--dev) */
13441da177e4SLinus Torvalds 	} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
13451928d73fSFUJITA Tomonori 		datalen = scsi_bufflen(SCpnt);
13461da177e4SLinus Torvalds 		scsidir = MPI_SCSIIO_CONTROL_WRITE;	/* DATA OUT (host-->ioc-->dev) */
13471da177e4SLinus Torvalds 	} else {
13481da177e4SLinus Torvalds 		datalen = 0;
13491da177e4SLinus Torvalds 		scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
13501da177e4SLinus Torvalds 	}
13511da177e4SLinus Torvalds 
13521da177e4SLinus Torvalds 	/* Default to untagged. Once a target structure has been allocated,
13531da177e4SLinus Torvalds 	 * use the Inquiry data to determine if device supports tagged.
13541da177e4SLinus Torvalds 	 */
1355c7c82987SMoore, Eric Dean 	if (vdev
1356c7c82987SMoore, Eric Dean 	    && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
13571da177e4SLinus Torvalds 	    && (SCpnt->device->tagged_supported)) {
13581da177e4SLinus Torvalds 		scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
13591da177e4SLinus Torvalds 	} else {
13601da177e4SLinus Torvalds 		scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
13611da177e4SLinus Torvalds 	}
13621da177e4SLinus Torvalds 
13631da177e4SLinus Torvalds 	/* Use the above information to set up the message frame
13641da177e4SLinus Torvalds 	 */
1365793955f5SEric Moore 	pScsiReq->TargetID = (u8) vdev->vtarget->id;
1366793955f5SEric Moore 	pScsiReq->Bus = vdev->vtarget->channel;
13671da177e4SLinus Torvalds 	pScsiReq->ChainOffset = 0;
1368c92f222eSJames Bottomley 	if (vdev->vtarget->tflags &  MPT_TARGET_FLAGS_RAID_COMPONENT)
1369c92f222eSJames Bottomley 		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1370c92f222eSJames Bottomley 	else
13711da177e4SLinus Torvalds 		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
13721da177e4SLinus Torvalds 	pScsiReq->CDBLength = SCpnt->cmd_len;
13731da177e4SLinus Torvalds 	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
13741da177e4SLinus Torvalds 	pScsiReq->Reserved = 0;
13751da177e4SLinus Torvalds 	pScsiReq->MsgFlags = mpt_msg_flags();
1376793955f5SEric Moore 	int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
13771da177e4SLinus Torvalds 	pScsiReq->Control = cpu_to_le32(scsictl);
13781da177e4SLinus Torvalds 
13791da177e4SLinus Torvalds 	/*
13801da177e4SLinus Torvalds 	 *  Write SCSI CDB into the message
13811da177e4SLinus Torvalds 	 */
13821da177e4SLinus Torvalds 	cmd_len = SCpnt->cmd_len;
13831da177e4SLinus Torvalds 	for (ii=0; ii < cmd_len; ii++)
13841da177e4SLinus Torvalds 		pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
13851da177e4SLinus Torvalds 
13861da177e4SLinus Torvalds 	for (ii=cmd_len; ii < 16; ii++)
13871da177e4SLinus Torvalds 		pScsiReq->CDB[ii] = 0;
13881da177e4SLinus Torvalds 
13891da177e4SLinus Torvalds 	/* DataLength */
13901da177e4SLinus Torvalds 	pScsiReq->DataLength = cpu_to_le32(datalen);
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	/* SenseBuffer low address */
13931da177e4SLinus Torvalds 	pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
13941da177e4SLinus Torvalds 					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
13951da177e4SLinus Torvalds 
13961da177e4SLinus Torvalds 	/* Now add the SG list
13971da177e4SLinus Torvalds 	 * Always have a SGE even if null length.
13981da177e4SLinus Torvalds 	 */
13991da177e4SLinus Torvalds 	if (datalen == 0) {
14001da177e4SLinus Torvalds 		/* Add a NULL SGE */
14011da177e4SLinus Torvalds 		mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
14021da177e4SLinus Torvalds 			(dma_addr_t) -1);
14031da177e4SLinus Torvalds 	} else {
14041da177e4SLinus Torvalds 		/* Add a 32 or 64 bit SGE */
14051da177e4SLinus Torvalds 		if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
14061da177e4SLinus Torvalds 			goto fail;
14071da177e4SLinus Torvalds 	}
14081da177e4SLinus Torvalds 
14093dc0b03fSEric Moore 	SCpnt->host_scribble = (unsigned char *)mf;
14101da177e4SLinus Torvalds 	hd->ScsiLookup[my_idx] = SCpnt;
14111da177e4SLinus Torvalds 
14120d0c7974SMoore, Eric Dean  	mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
14131da177e4SLinus Torvalds 	dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
14141da177e4SLinus Torvalds 			hd->ioc->name, SCpnt, mf, my_idx));
14151da177e4SLinus Torvalds 	DBG_DUMP_REQUEST_FRAME(mf)
14161da177e4SLinus Torvalds 	return 0;
14171da177e4SLinus Torvalds 
14181da177e4SLinus Torvalds  fail:
1419466544d8SMoore, Eric Dean 	hd->ScsiLookup[my_idx] = NULL;
14201da177e4SLinus Torvalds 	mptscsih_freeChainBuffers(hd->ioc, my_idx);
14211da177e4SLinus Torvalds 	mpt_free_msg_frame(hd->ioc, mf);
14221da177e4SLinus Torvalds 	return SCSI_MLQUEUE_HOST_BUSY;
14231da177e4SLinus Torvalds }
14241da177e4SLinus Torvalds 
14251da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
14261da177e4SLinus Torvalds /*
14271da177e4SLinus Torvalds  *	mptscsih_freeChainBuffers - Function to free chain buffers associated
14281da177e4SLinus Torvalds  *	with a SCSI IO request
14291da177e4SLinus Torvalds  *	@hd: Pointer to the MPT_SCSI_HOST instance
14301da177e4SLinus Torvalds  *	@req_idx: Index of the SCSI IO request frame.
14311da177e4SLinus Torvalds  *
14321da177e4SLinus Torvalds  *	Called if SG chain buffer allocation fails and mptscsih callbacks.
14331da177e4SLinus Torvalds  *	No return.
14341da177e4SLinus Torvalds  */
14351da177e4SLinus Torvalds static void
14361da177e4SLinus Torvalds mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
14371da177e4SLinus Torvalds {
14381da177e4SLinus Torvalds 	MPT_FRAME_HDR *chain;
14391da177e4SLinus Torvalds 	unsigned long flags;
14401da177e4SLinus Torvalds 	int chain_idx;
14411da177e4SLinus Torvalds 	int next;
14421da177e4SLinus Torvalds 
14431da177e4SLinus Torvalds 	/* Get the first chain index and reset
14441da177e4SLinus Torvalds 	 * tracker state.
14451da177e4SLinus Torvalds 	 */
14461da177e4SLinus Torvalds 	chain_idx = ioc->ReqToChain[req_idx];
14471da177e4SLinus Torvalds 	ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
14481da177e4SLinus Torvalds 
14491da177e4SLinus Torvalds 	while (chain_idx != MPT_HOST_NO_CHAIN) {
14501da177e4SLinus Torvalds 
14511da177e4SLinus Torvalds 		/* Save the next chain buffer index */
14521da177e4SLinus Torvalds 		next = ioc->ChainToChain[chain_idx];
14531da177e4SLinus Torvalds 
14541da177e4SLinus Torvalds 		/* Free this chain buffer and reset
14551da177e4SLinus Torvalds 		 * tracker
14561da177e4SLinus Torvalds 		 */
14571da177e4SLinus Torvalds 		ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
14581da177e4SLinus Torvalds 
14591da177e4SLinus Torvalds 		chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
14601da177e4SLinus Torvalds 					+ (chain_idx * ioc->req_sz));
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds 		spin_lock_irqsave(&ioc->FreeQlock, flags);
14631da177e4SLinus Torvalds 		list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
14641da177e4SLinus Torvalds 		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
14651da177e4SLinus Torvalds 
14661da177e4SLinus Torvalds 		dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
14671da177e4SLinus Torvalds 				ioc->name, chain_idx));
14681da177e4SLinus Torvalds 
14691da177e4SLinus Torvalds 		/* handle next */
14701da177e4SLinus Torvalds 		chain_idx = next;
14711da177e4SLinus Torvalds 	}
14721da177e4SLinus Torvalds 	return;
14731da177e4SLinus Torvalds }
14741da177e4SLinus Torvalds 
14751da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
14761da177e4SLinus Torvalds /*
14771da177e4SLinus Torvalds  *	Reset Handling
14781da177e4SLinus Torvalds  */
14791da177e4SLinus Torvalds 
14801da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1481cd2c6191SEric Moore /**
14821da177e4SLinus Torvalds  *	mptscsih_TMHandler - Generic handler for SCSI Task Management.
14831544d677SRandy Dunlap  *	@hd: Pointer to MPT SCSI HOST structure
14841da177e4SLinus Torvalds  *	@type: Task Management type
14851544d677SRandy Dunlap  *	@channel: channel number for task management
1486793955f5SEric Moore  *	@id: Logical Target ID for reset (if appropriate)
14871da177e4SLinus Torvalds  *	@lun: Logical Unit for reset (if appropriate)
14881da177e4SLinus Torvalds  *	@ctx2abort: Context for the task to be aborted (if appropriate)
14891544d677SRandy Dunlap  *	@timeout: timeout for task management control
14901544d677SRandy Dunlap  *
14911544d677SRandy Dunlap  *	Fall through to mpt_HardResetHandler if: not operational, too many
14921544d677SRandy Dunlap  *	failed TM requests or handshake failure.
14931da177e4SLinus Torvalds  *
14941da177e4SLinus Torvalds  *	Remark: Currently invoked from a non-interrupt thread (_bh).
14951da177e4SLinus Torvalds  *
14961da177e4SLinus Torvalds  *	Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
14971da177e4SLinus Torvalds  *	will be active.
14981da177e4SLinus Torvalds  *
14991544d677SRandy Dunlap  *	Returns 0 for SUCCESS, or %FAILED.
1500cd2c6191SEric Moore  **/
1501663e1aa1SJames Bottomley int
1502793955f5SEric Moore mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
15031da177e4SLinus Torvalds {
15041da177e4SLinus Torvalds 	MPT_ADAPTER	*ioc;
15051da177e4SLinus Torvalds 	int		 rc = -1;
15061da177e4SLinus Torvalds 	u32		 ioc_raw_state;
15071da177e4SLinus Torvalds 	unsigned long	 flags;
15081da177e4SLinus Torvalds 
15091da177e4SLinus Torvalds 	ioc = hd->ioc;
15101da177e4SLinus Torvalds 	dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
15111da177e4SLinus Torvalds 
15121da177e4SLinus Torvalds 	// SJR - CHECKME - Can we avoid this here?
15131da177e4SLinus Torvalds 	// (mpt_HardResetHandler has this check...)
15141da177e4SLinus Torvalds 	spin_lock_irqsave(&ioc->diagLock, flags);
15151da177e4SLinus Torvalds 	if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
15161da177e4SLinus Torvalds 		spin_unlock_irqrestore(&ioc->diagLock, flags);
15171da177e4SLinus Torvalds 		return FAILED;
15181da177e4SLinus Torvalds 	}
15191da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ioc->diagLock, flags);
15201da177e4SLinus Torvalds 
15211da177e4SLinus Torvalds 	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
1522cd2c6191SEric Moore 	 *  If we time out and not bus reset, then we return a FAILED status
1523cd2c6191SEric Moore 	 *  to the caller.
1524cd2c6191SEric Moore 	 *  The call to mptscsih_tm_pending_wait() will set the pending flag
1525cd2c6191SEric Moore 	 *  if we are
15261da177e4SLinus Torvalds 	 *  successful. Otherwise, reload the FW.
15271da177e4SLinus Torvalds 	 */
15281da177e4SLinus Torvalds 	if (mptscsih_tm_pending_wait(hd) == FAILED) {
15291da177e4SLinus Torvalds 		if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
1530c6678e0cSChristoph Hellwig 			dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
15311da177e4SLinus Torvalds 			   "Timed out waiting for last TM (%d) to complete! \n",
15321da177e4SLinus Torvalds 			   hd->ioc->name, hd->tmPending));
15331da177e4SLinus Torvalds 			return FAILED;
15341da177e4SLinus Torvalds 		} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
1535cd2c6191SEric Moore 			dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
1536cd2c6191SEric Moore 				"reset: Timed out waiting for last TM (%d) "
1537cd2c6191SEric Moore 				"to complete! \n", hd->ioc->name,
1538cd2c6191SEric Moore 				hd->tmPending));
15391da177e4SLinus Torvalds 			return FAILED;
15401da177e4SLinus Torvalds 		} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
1541c6678e0cSChristoph Hellwig 			dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
15421da177e4SLinus Torvalds 			   "Timed out waiting for last TM (%d) to complete! \n",
15431da177e4SLinus Torvalds 			   hd->ioc->name, hd->tmPending));
15441da177e4SLinus Torvalds 			return FAILED;
15451da177e4SLinus Torvalds 		}
15461da177e4SLinus Torvalds 	} else {
15471da177e4SLinus Torvalds 		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
15481da177e4SLinus Torvalds 		hd->tmPending |=  (1 << type);
15491da177e4SLinus Torvalds 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
15501da177e4SLinus Torvalds 	}
15511da177e4SLinus Torvalds 
15521da177e4SLinus Torvalds 	ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
15531da177e4SLinus Torvalds 
15541da177e4SLinus Torvalds 	if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
15551da177e4SLinus Torvalds 		printk(MYIOC_s_WARN_FMT
1556cd2c6191SEric Moore 			"TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1557cd2c6191SEric Moore 			ioc->name, type, ioc_raw_state);
1558cd2c6191SEric Moore 		printk(KERN_WARNING " Issuing HardReset!!\n");
1559cd2c6191SEric Moore 		if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1560cd2c6191SEric Moore 			printk((KERN_WARNING "TMHandler: HardReset "
1561cd2c6191SEric Moore 				"FAILED!!\n"));
1562cd2c6191SEric Moore 		return FAILED;
15631da177e4SLinus Torvalds 	}
15641da177e4SLinus Torvalds 
1565cd2c6191SEric Moore 	if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1566cd2c6191SEric Moore 		printk(MYIOC_s_WARN_FMT
1567cd2c6191SEric Moore 			"TM Handler for type=%x: ioc_state: "
1568cd2c6191SEric Moore 			"DOORBELL_ACTIVE (0x%x)!\n",
1569cd2c6191SEric Moore 			ioc->name, type, ioc_raw_state);
1570cd2c6191SEric Moore 		return FAILED;
1571cd2c6191SEric Moore 	}
15721da177e4SLinus Torvalds 
15731da177e4SLinus Torvalds 	/* Isse the Task Mgmt request.
15741da177e4SLinus Torvalds 	 */
15751da177e4SLinus Torvalds 	if (hd->hard_resets < -1)
15761da177e4SLinus Torvalds 		hd->hard_resets++;
15771da177e4SLinus Torvalds 
1578cd2c6191SEric Moore 	rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1579cd2c6191SEric Moore 	    ctx2abort, timeout);
1580cd2c6191SEric Moore 	if (rc)
1581cd2c6191SEric Moore 		printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
1582cd2c6191SEric Moore 		       hd->ioc->name);
1583cd2c6191SEric Moore 	else
1584cd2c6191SEric Moore 		dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
15851da177e4SLinus Torvalds 			   hd->ioc->name));
15863dc0b03fSEric Moore 
15871da177e4SLinus Torvalds 	dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
15881da177e4SLinus Torvalds 
15891da177e4SLinus Torvalds 	return rc;
15901da177e4SLinus Torvalds }
15911da177e4SLinus Torvalds 
15921da177e4SLinus Torvalds 
15931da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1594cd2c6191SEric Moore /**
15951da177e4SLinus Torvalds  *	mptscsih_IssueTaskMgmt - Generic send Task Management function.
15961da177e4SLinus Torvalds  *	@hd: Pointer to MPT_SCSI_HOST structure
15971da177e4SLinus Torvalds  *	@type: Task Management type
15981544d677SRandy Dunlap  *	@channel: channel number for task management
1599793955f5SEric Moore  *	@id: Logical Target ID for reset (if appropriate)
16001da177e4SLinus Torvalds  *	@lun: Logical Unit for reset (if appropriate)
16011da177e4SLinus Torvalds  *	@ctx2abort: Context for the task to be aborted (if appropriate)
16021544d677SRandy Dunlap  *	@timeout: timeout for task management control
16031da177e4SLinus Torvalds  *
16041da177e4SLinus Torvalds  *	Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
16051da177e4SLinus Torvalds  *	or a non-interrupt thread.  In the former, must not call schedule().
16061da177e4SLinus Torvalds  *
16071da177e4SLinus Torvalds  *	Not all fields are meaningfull for all task types.
16081da177e4SLinus Torvalds  *
1609cd2c6191SEric Moore  *	Returns 0 for SUCCESS, or FAILED.
1610cd2c6191SEric Moore  *
1611cd2c6191SEric Moore  **/
16121da177e4SLinus Torvalds static int
1613793955f5SEric Moore mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
16141da177e4SLinus Torvalds {
16151da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
16161da177e4SLinus Torvalds 	SCSITaskMgmt_t	*pScsiTm;
16171da177e4SLinus Torvalds 	int		 ii;
16181da177e4SLinus Torvalds 	int		 retval;
16191da177e4SLinus Torvalds 
16201da177e4SLinus Torvalds 	/* Return Fail to calling function if no message frames available.
16211da177e4SLinus Torvalds 	 */
16220d0c7974SMoore, Eric Dean  	if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
16231da177e4SLinus Torvalds 		dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
16241da177e4SLinus Torvalds 				hd->ioc->name));
1625c6678e0cSChristoph Hellwig 		return FAILED;
16261da177e4SLinus Torvalds 	}
16271da177e4SLinus Torvalds 	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
16281da177e4SLinus Torvalds 			hd->ioc->name, mf));
16291da177e4SLinus Torvalds 
16301da177e4SLinus Torvalds 	/* Format the Request
16311da177e4SLinus Torvalds 	 */
16321da177e4SLinus Torvalds 	pScsiTm = (SCSITaskMgmt_t *) mf;
1633793955f5SEric Moore 	pScsiTm->TargetID = id;
16341da177e4SLinus Torvalds 	pScsiTm->Bus = channel;
16351da177e4SLinus Torvalds 	pScsiTm->ChainOffset = 0;
16361da177e4SLinus Torvalds 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
16371da177e4SLinus Torvalds 
16381da177e4SLinus Torvalds 	pScsiTm->Reserved = 0;
16391da177e4SLinus Torvalds 	pScsiTm->TaskType = type;
16401da177e4SLinus Torvalds 	pScsiTm->Reserved1 = 0;
16411da177e4SLinus Torvalds 	pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
16421da177e4SLinus Torvalds                     ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
16431da177e4SLinus Torvalds 
1644793955f5SEric Moore 	int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
16451da177e4SLinus Torvalds 
16461da177e4SLinus Torvalds 	for (ii=0; ii < 7; ii++)
16471da177e4SLinus Torvalds 		pScsiTm->Reserved2[ii] = 0;
16481da177e4SLinus Torvalds 
16491da177e4SLinus Torvalds 	pScsiTm->TaskMsgContext = ctx2abort;
16501da177e4SLinus Torvalds 
1651cd2c6191SEric Moore 	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1652cd2c6191SEric Moore 		"type=%d\n", hd->ioc->name, ctx2abort, type));
16531da177e4SLinus Torvalds 
16541da177e4SLinus Torvalds 	DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
16551da177e4SLinus Torvalds 
16560d0c7974SMoore, Eric Dean  	if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
1657cd2c6191SEric Moore 		sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
1658cd2c6191SEric Moore 		dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
1659cd2c6191SEric Moore 			" (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1660cd2c6191SEric Moore 			hd->ioc, mf, retval));
1661cd2c6191SEric Moore 		goto fail_out;
16621da177e4SLinus Torvalds 	}
16631da177e4SLinus Torvalds 
16641da177e4SLinus Torvalds 	if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1665cd2c6191SEric Moore 		dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
16661da177e4SLinus Torvalds 			" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
16671da177e4SLinus Torvalds 			hd->ioc, mf));
16681da177e4SLinus Torvalds 		dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
16691da177e4SLinus Torvalds 			 hd->ioc->name));
16701da177e4SLinus Torvalds 		retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1671cd2c6191SEric Moore 		dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
1672cd2c6191SEric Moore 			 hd->ioc->name, retval));
1673cd2c6191SEric Moore 		goto fail_out;
16741da177e4SLinus Torvalds 	}
16751da177e4SLinus Torvalds 
1676cd2c6191SEric Moore 	/*
1677cd2c6191SEric Moore 	 * Handle success case, see if theres a non-zero ioc_status.
1678cd2c6191SEric Moore 	 */
1679cd2c6191SEric Moore 	if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1680cd2c6191SEric Moore 	   hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1681cd2c6191SEric Moore 	   hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1682cd2c6191SEric Moore 		retval = 0;
1683cd2c6191SEric Moore 	else
1684cd2c6191SEric Moore 		retval = FAILED;
1685cd2c6191SEric Moore 
16861da177e4SLinus Torvalds 	return retval;
1687cd2c6191SEric Moore 
1688cd2c6191SEric Moore  fail_out:
1689cd2c6191SEric Moore 
1690cd2c6191SEric Moore 	/*
1691cd2c6191SEric Moore 	 * Free task managment mf, and corresponding tm flags
1692cd2c6191SEric Moore 	 */
1693cd2c6191SEric Moore 	mpt_free_msg_frame(hd->ioc, mf);
1694cd2c6191SEric Moore 	hd->tmPending = 0;
1695cd2c6191SEric Moore 	hd->tmState = TM_STATE_NONE;
1696cd2c6191SEric Moore 	return FAILED;
16971da177e4SLinus Torvalds }
16981da177e4SLinus Torvalds 
1699d66c7a0fSChristoph Hellwig static int
1700d66c7a0fSChristoph Hellwig mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1701d66c7a0fSChristoph Hellwig {
1702d66c7a0fSChristoph Hellwig 	switch (ioc->bus_type) {
1703d66c7a0fSChristoph Hellwig 	case FC:
1704d66c7a0fSChristoph Hellwig 		return 40;
1705d66c7a0fSChristoph Hellwig 	case SAS:
1706d66c7a0fSChristoph Hellwig 		return 10;
1707d66c7a0fSChristoph Hellwig 	case SPI:
1708d66c7a0fSChristoph Hellwig 	default:
1709d66c7a0fSChristoph Hellwig 		return 2;
1710d66c7a0fSChristoph Hellwig 	}
1711d66c7a0fSChristoph Hellwig }
1712d66c7a0fSChristoph Hellwig 
17131da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
17141da177e4SLinus Torvalds /**
17151da177e4SLinus Torvalds  *	mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
17161da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
17171da177e4SLinus Torvalds  *
17181da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_abort_handler routine)
17191da177e4SLinus Torvalds  *
17201da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
1721cd2c6191SEric Moore  **/
17220d0c7974SMoore, Eric Dean  int
17231da177e4SLinus Torvalds mptscsih_abort(struct scsi_cmnd * SCpnt)
17241da177e4SLinus Torvalds {
17251da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
17261da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
17271da177e4SLinus Torvalds 	u32		 ctx2abort;
17281da177e4SLinus Torvalds 	int		 scpnt_idx;
1729466544d8SMoore, Eric Dean 	int		 retval;
1730958d4a32SEric Moore 	VirtDevice	 *vdevice;
17313dc0b03fSEric Moore 	ulong	 	 sn = SCpnt->serial_number;
1732958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
17331da177e4SLinus Torvalds 
17341da177e4SLinus Torvalds 	/* If we can't locate our host adapter structure, return FAILED status.
17351da177e4SLinus Torvalds 	 */
17361da177e4SLinus Torvalds 	if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
17371da177e4SLinus Torvalds 		SCpnt->result = DID_RESET << 16;
17381da177e4SLinus Torvalds 		SCpnt->scsi_done(SCpnt);
1739958d4a32SEric Moore 		dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: Can't locate "
1740958d4a32SEric Moore 		    "host! (sc=%p)\n", SCpnt));
17411da177e4SLinus Torvalds 		return FAILED;
17421da177e4SLinus Torvalds 	}
17431da177e4SLinus Torvalds 
1744958d4a32SEric Moore 	ioc = hd->ioc;
1745958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1746958d4a32SEric Moore 	       ioc->name, SCpnt);
1747958d4a32SEric Moore 	scsi_print_command(SCpnt);
1748958d4a32SEric Moore 
1749958d4a32SEric Moore 	vdevice = SCpnt->device->hostdata;
1750958d4a32SEric Moore 	if (!vdevice || !vdevice->vtarget) {
1751958d4a32SEric Moore 		dtmprintk((MYIOC_s_DEBUG_FMT "task abort: device has been "
1752958d4a32SEric Moore 		    "deleted (sc=%p)\n", ioc->name, SCpnt));
1753958d4a32SEric Moore 		SCpnt->result = DID_NO_CONNECT << 16;
1754958d4a32SEric Moore 		SCpnt->scsi_done(SCpnt);
1755958d4a32SEric Moore 		retval = 0;
1756958d4a32SEric Moore 		goto out;
1757958d4a32SEric Moore 	}
1758958d4a32SEric Moore 
17591da177e4SLinus Torvalds 	/* Find this command
17601da177e4SLinus Torvalds 	 */
17611da177e4SLinus Torvalds 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
17621da177e4SLinus Torvalds 		/* Cmd not found in ScsiLookup.
17631da177e4SLinus Torvalds 		 * Do OS callback.
17641da177e4SLinus Torvalds 		 */
17651da177e4SLinus Torvalds 		SCpnt->result = DID_RESET << 16;
1766466544d8SMoore, Eric Dean 		dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
1767958d4a32SEric Moore 		   "Command not in the active list! (sc=%p)\n", ioc->name,
1768958d4a32SEric Moore 		   SCpnt));
1769958d4a32SEric Moore 		retval = 0;
1770958d4a32SEric Moore 		goto out;
17711da177e4SLinus Torvalds 	}
17721da177e4SLinus Torvalds 
1773958d4a32SEric Moore 	if (hd->resetPending) {
1774958d4a32SEric Moore 		retval = FAILED;
1775958d4a32SEric Moore 		goto out;
1776958d4a32SEric Moore 	}
177765207fedSMoore, Eric 
177865207fedSMoore, Eric 	if (hd->timeouts < -1)
177965207fedSMoore, Eric 		hd->timeouts++;
178065207fedSMoore, Eric 
17811da177e4SLinus Torvalds 	/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
17821da177e4SLinus Torvalds 	 * (the IO to be ABORT'd)
17831da177e4SLinus Torvalds 	 *
17841da177e4SLinus Torvalds 	 * NOTE: Since we do not byteswap MsgContext, we do not
17851da177e4SLinus Torvalds 	 *	 swap it here either.  It is an opaque cookie to
17861da177e4SLinus Torvalds 	 *	 the controller, so it does not matter. -DaveM
17871da177e4SLinus Torvalds 	 */
17881da177e4SLinus Torvalds 	mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
17891da177e4SLinus Torvalds 	ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
17901da177e4SLinus Torvalds 
17911da177e4SLinus Torvalds 	hd->abortSCpnt = SCpnt;
17921da177e4SLinus Torvalds 
1793466544d8SMoore, Eric Dean 	retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1794958d4a32SEric Moore 	    vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1795958d4a32SEric Moore 	    ctx2abort, mptscsih_get_tm_timeout(ioc));
17961da177e4SLinus Torvalds 
17973dc0b03fSEric Moore 	if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
1798cd2c6191SEric Moore 	    SCpnt->serial_number == sn)
17993dc0b03fSEric Moore 		retval = FAILED;
18003dc0b03fSEric Moore 
1801958d4a32SEric Moore  out:
1802958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1803958d4a32SEric Moore 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
18041da177e4SLinus Torvalds 
1805466544d8SMoore, Eric Dean 	if (retval == 0)
1806466544d8SMoore, Eric Dean 		return SUCCESS;
1807cd2c6191SEric Moore 	else
18081da177e4SLinus Torvalds 		return FAILED;
18091da177e4SLinus Torvalds }
18101da177e4SLinus Torvalds 
18111da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
18121da177e4SLinus Torvalds /**
18131da177e4SLinus Torvalds  *	mptscsih_dev_reset - Perform a SCSI TARGET_RESET!  new_eh variant
18141da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
18151da177e4SLinus Torvalds  *
18161da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_dev_reset_handler routine)
18171da177e4SLinus Torvalds  *
18181da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
1819cd2c6191SEric Moore  **/
18200d0c7974SMoore, Eric Dean  int
18211da177e4SLinus Torvalds mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
18221da177e4SLinus Torvalds {
18231da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
1824466544d8SMoore, Eric Dean 	int		 retval;
1825958d4a32SEric Moore 	VirtDevice	 *vdevice;
1826958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
18271da177e4SLinus Torvalds 
18281da177e4SLinus Torvalds 	/* If we can't locate our host adapter structure, return FAILED status.
18291da177e4SLinus Torvalds 	 */
18301da177e4SLinus Torvalds 	if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
1831958d4a32SEric Moore 		dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: Can't "
1832958d4a32SEric Moore 		    "locate host! (sc=%p)\n", SCpnt));
18331da177e4SLinus Torvalds 		return FAILED;
18341da177e4SLinus Torvalds 	}
18351da177e4SLinus Torvalds 
1836958d4a32SEric Moore 	ioc = hd->ioc;
1837958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1838958d4a32SEric Moore 	       ioc->name, SCpnt);
1839466544d8SMoore, Eric Dean 	scsi_print_command(SCpnt);
18401da177e4SLinus Torvalds 
1841958d4a32SEric Moore 	if (hd->resetPending) {
1842958d4a32SEric Moore 		retval = FAILED;
1843958d4a32SEric Moore 		goto out;
1844958d4a32SEric Moore 	}
1845466544d8SMoore, Eric Dean 
1846958d4a32SEric Moore 	vdevice = SCpnt->device->hostdata;
1847958d4a32SEric Moore 	if (!vdevice || !vdevice->vtarget) {
1848958d4a32SEric Moore 		retval = 0;
1849958d4a32SEric Moore 		goto out;
1850958d4a32SEric Moore 	}
1851958d4a32SEric Moore 
1852958d4a32SEric Moore 	retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1853958d4a32SEric Moore 	    vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1854958d4a32SEric Moore 	    mptscsih_get_tm_timeout(ioc));
1855958d4a32SEric Moore 
1856958d4a32SEric Moore  out:
1857958d4a32SEric Moore 	printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1858958d4a32SEric Moore 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1859466544d8SMoore, Eric Dean 
1860466544d8SMoore, Eric Dean 	if (retval == 0)
1861466544d8SMoore, Eric Dean 		return SUCCESS;
1862cd2c6191SEric Moore 	else
1863466544d8SMoore, Eric Dean 		return FAILED;
18641da177e4SLinus Torvalds }
18651da177e4SLinus Torvalds 
1866cd2c6191SEric Moore 
18671da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
18681da177e4SLinus Torvalds /**
18691da177e4SLinus Torvalds  *	mptscsih_bus_reset - Perform a SCSI BUS_RESET!	new_eh variant
18701da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
18711da177e4SLinus Torvalds  *
18721da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_bus_reset_handler routine)
18731da177e4SLinus Torvalds  *
18741da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
1875cd2c6191SEric Moore  **/
18760d0c7974SMoore, Eric Dean  int
18771da177e4SLinus Torvalds mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
18781da177e4SLinus Torvalds {
18791da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
1880466544d8SMoore, Eric Dean 	int		 retval;
1881c7c82987SMoore, Eric Dean 	VirtDevice	 *vdev;
1882958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
18831da177e4SLinus Torvalds 
18841da177e4SLinus Torvalds 	/* If we can't locate our host adapter structure, return FAILED status.
18851da177e4SLinus Torvalds 	 */
18861da177e4SLinus Torvalds 	if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
1887958d4a32SEric Moore 		dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: Can't "
1888958d4a32SEric Moore 		    "locate host! (sc=%p)\n", SCpnt ));
18891da177e4SLinus Torvalds 		return FAILED;
18901da177e4SLinus Torvalds 	}
18911da177e4SLinus Torvalds 
1892958d4a32SEric Moore 	ioc = hd->ioc;
1893958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1894958d4a32SEric Moore 	       ioc->name, SCpnt);
1895466544d8SMoore, Eric Dean 	scsi_print_command(SCpnt);
18961da177e4SLinus Torvalds 
18971da177e4SLinus Torvalds 	if (hd->timeouts < -1)
18981da177e4SLinus Torvalds 		hd->timeouts++;
18991da177e4SLinus Torvalds 
1900c7c82987SMoore, Eric Dean 	vdev = SCpnt->device->hostdata;
1901466544d8SMoore, Eric Dean 	retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1902958d4a32SEric Moore 	    vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
19031da177e4SLinus Torvalds 
1904958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1905958d4a32SEric Moore 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1906466544d8SMoore, Eric Dean 
1907466544d8SMoore, Eric Dean 	if (retval == 0)
1908466544d8SMoore, Eric Dean 		return SUCCESS;
1909cd2c6191SEric Moore 	else
1910466544d8SMoore, Eric Dean 		return FAILED;
19111da177e4SLinus Torvalds }
19121da177e4SLinus Torvalds 
19131da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
19141da177e4SLinus Torvalds /**
1915d9489fb6SRandy Dunlap  *	mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
19161da177e4SLinus Torvalds  *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
19171da177e4SLinus Torvalds  *
19181da177e4SLinus Torvalds  *	(linux scsi_host_template.eh_host_reset_handler routine)
19191da177e4SLinus Torvalds  *
19201da177e4SLinus Torvalds  *	Returns SUCCESS or FAILED.
19211da177e4SLinus Torvalds  */
19220d0c7974SMoore, Eric Dean  int
19231da177e4SLinus Torvalds mptscsih_host_reset(struct scsi_cmnd *SCpnt)
19241da177e4SLinus Torvalds {
19251da177e4SLinus Torvalds 	MPT_SCSI_HOST *  hd;
1926958d4a32SEric Moore 	int              retval;
1927958d4a32SEric Moore 	MPT_ADAPTER	*ioc;
19281da177e4SLinus Torvalds 
19291da177e4SLinus Torvalds 	/*  If we can't locate the host to reset, then we failed. */
19301da177e4SLinus Torvalds 	if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
1931958d4a32SEric Moore 		dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: Can't "
1932958d4a32SEric Moore 		    "locate host! (sc=%p)\n", SCpnt));
19331da177e4SLinus Torvalds 		return FAILED;
19341da177e4SLinus Torvalds 	}
19351da177e4SLinus Torvalds 
1936958d4a32SEric Moore 	ioc = hd->ioc;
1937958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1938958d4a32SEric Moore 	    ioc->name, SCpnt);
19391da177e4SLinus Torvalds 
19401da177e4SLinus Torvalds 	/*  If our attempts to reset the host failed, then return a failed
19411da177e4SLinus Torvalds 	 *  status.  The host will be taken off line by the SCSI mid-layer.
19421da177e4SLinus Torvalds 	 */
19431da177e4SLinus Torvalds 	if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
1944958d4a32SEric Moore 		retval = FAILED;
19451da177e4SLinus Torvalds 	} else {
19461da177e4SLinus Torvalds 		/*  Make sure TM pending is cleared and TM state is set to
19471da177e4SLinus Torvalds 		 *  NONE.
19481da177e4SLinus Torvalds 		 */
1949958d4a32SEric Moore 		retval = 0;
19501da177e4SLinus Torvalds 		hd->tmPending = 0;
19511da177e4SLinus Torvalds 		hd->tmState = TM_STATE_NONE;
19521da177e4SLinus Torvalds 	}
19531da177e4SLinus Torvalds 
1954958d4a32SEric Moore 	printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1955958d4a32SEric Moore 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
19561da177e4SLinus Torvalds 
1957958d4a32SEric Moore 	return retval;
19581da177e4SLinus Torvalds }
19591da177e4SLinus Torvalds 
19601da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
19611da177e4SLinus Torvalds /**
1962d9489fb6SRandy Dunlap  *	mptscsih_tm_pending_wait - wait for pending task management request to complete
19631da177e4SLinus Torvalds  *	@hd: Pointer to MPT host structure.
19641da177e4SLinus Torvalds  *
19651da177e4SLinus Torvalds  *	Returns {SUCCESS,FAILED}.
19661da177e4SLinus Torvalds  */
19671da177e4SLinus Torvalds static int
19681da177e4SLinus Torvalds mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
19691da177e4SLinus Torvalds {
19701da177e4SLinus Torvalds 	unsigned long  flags;
19711da177e4SLinus Torvalds 	int            loop_count = 4 * 10;  /* Wait 10 seconds */
19721da177e4SLinus Torvalds 	int            status = FAILED;
19731da177e4SLinus Torvalds 
19741da177e4SLinus Torvalds 	do {
19751da177e4SLinus Torvalds 		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
19761da177e4SLinus Torvalds 		if (hd->tmState == TM_STATE_NONE) {
19771da177e4SLinus Torvalds 			hd->tmState = TM_STATE_IN_PROGRESS;
19781da177e4SLinus Torvalds 			hd->tmPending = 1;
19791da177e4SLinus Torvalds 			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1980c6678e0cSChristoph Hellwig 			status = SUCCESS;
19811da177e4SLinus Torvalds 			break;
19821da177e4SLinus Torvalds 		}
19831da177e4SLinus Torvalds 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
19841da177e4SLinus Torvalds 		msleep(250);
19851da177e4SLinus Torvalds 	} while (--loop_count);
19861da177e4SLinus Torvalds 
19871da177e4SLinus Torvalds 	return status;
19881da177e4SLinus Torvalds }
19891da177e4SLinus Torvalds 
19901da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
19911da177e4SLinus Torvalds /**
19921da177e4SLinus Torvalds  *	mptscsih_tm_wait_for_completion - wait for completion of TM task
19931da177e4SLinus Torvalds  *	@hd: Pointer to MPT host structure.
19941544d677SRandy Dunlap  *	@timeout: timeout value
19951da177e4SLinus Torvalds  *
19961da177e4SLinus Torvalds  *	Returns {SUCCESS,FAILED}.
19971da177e4SLinus Torvalds  */
19981da177e4SLinus Torvalds static int
19991da177e4SLinus Torvalds mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
20001da177e4SLinus Torvalds {
20011da177e4SLinus Torvalds 	unsigned long  flags;
20021da177e4SLinus Torvalds 	int            loop_count = 4 * timeout;
20031da177e4SLinus Torvalds 	int            status = FAILED;
20041da177e4SLinus Torvalds 
20051da177e4SLinus Torvalds 	do {
20061da177e4SLinus Torvalds 		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
20071da177e4SLinus Torvalds 		if(hd->tmPending == 0) {
20081da177e4SLinus Torvalds 			status = SUCCESS;
20091da177e4SLinus Torvalds  			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
20101da177e4SLinus Torvalds 			break;
20111da177e4SLinus Torvalds 		}
20121da177e4SLinus Torvalds 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2013d6be06c8SMichael Reed 		msleep(250);
20141da177e4SLinus Torvalds 	} while (--loop_count);
20151da177e4SLinus Torvalds 
20161da177e4SLinus Torvalds 	return status;
20171da177e4SLinus Torvalds }
20181da177e4SLinus Torvalds 
20191da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
20209f63bb73SMoore, Eric static void
20219f63bb73SMoore, Eric mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
20229f63bb73SMoore, Eric {
20239f63bb73SMoore, Eric 	char *desc;
20249f63bb73SMoore, Eric 
20259f63bb73SMoore, Eric 	switch (response_code) {
20269f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
20279f63bb73SMoore, Eric 		desc = "The task completed.";
20289f63bb73SMoore, Eric 		break;
20299f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
20309f63bb73SMoore, Eric 		desc = "The IOC received an invalid frame status.";
20319f63bb73SMoore, Eric 		break;
20329f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
20339f63bb73SMoore, Eric 		desc = "The task type is not supported.";
20349f63bb73SMoore, Eric 		break;
20359f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_FAILED:
20369f63bb73SMoore, Eric 		desc = "The requested task failed.";
20379f63bb73SMoore, Eric 		break;
20389f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
20399f63bb73SMoore, Eric 		desc = "The task completed successfully.";
20409f63bb73SMoore, Eric 		break;
20419f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
20429f63bb73SMoore, Eric 		desc = "The LUN request is invalid.";
20439f63bb73SMoore, Eric 		break;
20449f63bb73SMoore, Eric 	case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
20459f63bb73SMoore, Eric 		desc = "The task is in the IOC queue and has not been sent to target.";
20469f63bb73SMoore, Eric 		break;
20479f63bb73SMoore, Eric 	default:
20489f63bb73SMoore, Eric 		desc = "unknown";
20499f63bb73SMoore, Eric 		break;
20509f63bb73SMoore, Eric 	}
20519f63bb73SMoore, Eric 	printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
20529f63bb73SMoore, Eric 		ioc->name, response_code, desc);
20539f63bb73SMoore, Eric }
20549f63bb73SMoore, Eric 
20559f63bb73SMoore, Eric /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
20561da177e4SLinus Torvalds /**
20571da177e4SLinus Torvalds  *	mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
20581da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
20591da177e4SLinus Torvalds  *	@mf: Pointer to SCSI task mgmt request frame
20601da177e4SLinus Torvalds  *	@mr: Pointer to SCSI task mgmt reply frame
20611da177e4SLinus Torvalds  *
20621da177e4SLinus Torvalds  *	This routine is called from mptbase.c::mpt_interrupt() at the completion
20631da177e4SLinus Torvalds  *	of any SCSI task management request.
20641da177e4SLinus Torvalds  *	This routine is registered with the MPT (base) driver at driver
20651da177e4SLinus Torvalds  *	load/init time via the mpt_register() API call.
20661da177e4SLinus Torvalds  *
20671da177e4SLinus Torvalds  *	Returns 1 indicating alloc'd request frame ptr should be freed.
2068cd2c6191SEric Moore  **/
20690d0c7974SMoore, Eric Dean  int
20701da177e4SLinus Torvalds mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
20711da177e4SLinus Torvalds {
20721da177e4SLinus Torvalds 	SCSITaskMgmtReply_t	*pScsiTmReply;
20731da177e4SLinus Torvalds 	SCSITaskMgmt_t		*pScsiTmReq;
20741da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
20751da177e4SLinus Torvalds 	unsigned long		 flags;
20761da177e4SLinus Torvalds 	u16			 iocstatus;
20771da177e4SLinus Torvalds 	u8			 tmType;
2078cd2c6191SEric Moore 	u32			 termination_count;
20791da177e4SLinus Torvalds 
20801da177e4SLinus Torvalds 	dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
20811da177e4SLinus Torvalds 	    ioc->name, mf, mr));
2082cd2c6191SEric Moore 	if (!ioc->sh) {
2083cd2c6191SEric Moore 		dtmprintk((MYIOC_s_WARN_FMT
2084cd2c6191SEric Moore 		    "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
20851da177e4SLinus Torvalds 		return 1;
20861da177e4SLinus Torvalds 	}
20871da177e4SLinus Torvalds 
20881da177e4SLinus Torvalds 	if (mr == NULL) {
2089cd2c6191SEric Moore 		dtmprintk((MYIOC_s_WARN_FMT
2090cd2c6191SEric Moore 		    "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
20911da177e4SLinus Torvalds 		return 1;
2092cd2c6191SEric Moore 	}
2093cd2c6191SEric Moore 
2094cd2c6191SEric Moore 	hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
20951da177e4SLinus Torvalds 	pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
20961da177e4SLinus Torvalds 	pScsiTmReq = (SCSITaskMgmt_t*)mf;
20971da177e4SLinus Torvalds 	tmType = pScsiTmReq->TaskType;
2098cd2c6191SEric Moore 	iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2099cd2c6191SEric Moore 	termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
21001da177e4SLinus Torvalds 
21019f63bb73SMoore, Eric 	if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
21029f63bb73SMoore, Eric 	    pScsiTmReply->ResponseCode)
21039f63bb73SMoore, Eric 		mptscsih_taskmgmt_response_code(ioc,
21049f63bb73SMoore, Eric 		    pScsiTmReply->ResponseCode);
21051da177e4SLinus Torvalds 	DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
21061da177e4SLinus Torvalds 
2107cd2c6191SEric Moore #if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
2108cd2c6191SEric Moore 	printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2109cd2c6191SEric Moore 	    "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2110cd2c6191SEric Moore 	    "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2111cd2c6191SEric Moore 	    pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2112cd2c6191SEric Moore 	    le16_to_cpu(pScsiTmReply->IOCStatus),
2113cd2c6191SEric Moore 	    le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2114cd2c6191SEric Moore 	    le32_to_cpu(pScsiTmReply->TerminationCount));
2115cd2c6191SEric Moore #endif
2116cd2c6191SEric Moore 	if (!iocstatus) {
2117cd2c6191SEric Moore 		dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2118cd2c6191SEric Moore 			hd->abortSCpnt = NULL;
2119cd2c6191SEric Moore 		goto out;
2120cd2c6191SEric Moore 	}
2121cd2c6191SEric Moore 
21221da177e4SLinus Torvalds 	/* Error?  (anything non-zero?) */
21231da177e4SLinus Torvalds 
21241da177e4SLinus Torvalds 	/* clear flags and continue.
21251da177e4SLinus Torvalds 	 */
2126cd2c6191SEric Moore 	switch (tmType) {
2127cd2c6191SEric Moore 
2128cd2c6191SEric Moore 	case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2129cd2c6191SEric Moore 		if (termination_count == 1)
2130cd2c6191SEric Moore 			iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
21311da177e4SLinus Torvalds 		hd->abortSCpnt = NULL;
2132cd2c6191SEric Moore 		break;
2133cd2c6191SEric Moore 
2134cd2c6191SEric Moore 	case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
21351da177e4SLinus Torvalds 
21361da177e4SLinus Torvalds 		/* If an internal command is present
21371da177e4SLinus Torvalds 		 * or the TM failed - reload the FW.
21381da177e4SLinus Torvalds 		 * FC FW may respond FAILED to an ABORT
21391da177e4SLinus Torvalds 		 */
2140cd2c6191SEric Moore 		if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2141cd2c6191SEric Moore 		    hd->cmdPtr)
2142cd2c6191SEric Moore 			if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
2143cd2c6191SEric Moore 				printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
2144cd2c6191SEric Moore 		break;
21451da177e4SLinus Torvalds 
2146cd2c6191SEric Moore 	case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2147cd2c6191SEric Moore 	default:
2148cd2c6191SEric Moore 		break;
21491da177e4SLinus Torvalds 	}
21501da177e4SLinus Torvalds 
2151cd2c6191SEric Moore  out:
21521da177e4SLinus Torvalds 	spin_lock_irqsave(&ioc->FreeQlock, flags);
21531da177e4SLinus Torvalds 	hd->tmPending = 0;
21541da177e4SLinus Torvalds 	hd->tmState = TM_STATE_NONE;
2155cd2c6191SEric Moore 	hd->tm_iocstatus = iocstatus;
2156cd2c6191SEric Moore 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
21571da177e4SLinus Torvalds 
21581da177e4SLinus Torvalds 	return 1;
21591da177e4SLinus Torvalds }
21601da177e4SLinus Torvalds 
21611da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
21621da177e4SLinus Torvalds /*
21631da177e4SLinus Torvalds  *	This is anyones guess quite frankly.
21641da177e4SLinus Torvalds  */
21650d0c7974SMoore, Eric Dean  int
21661da177e4SLinus Torvalds mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
21671da177e4SLinus Torvalds 		sector_t capacity, int geom[])
21681da177e4SLinus Torvalds {
21691da177e4SLinus Torvalds 	int		heads;
21701da177e4SLinus Torvalds 	int		sectors;
21711da177e4SLinus Torvalds 	sector_t	cylinders;
21721da177e4SLinus Torvalds 	ulong 		dummy;
21731da177e4SLinus Torvalds 
21741da177e4SLinus Torvalds 	heads = 64;
21751da177e4SLinus Torvalds 	sectors = 32;
21761da177e4SLinus Torvalds 
21771da177e4SLinus Torvalds 	dummy = heads * sectors;
21781da177e4SLinus Torvalds 	cylinders = capacity;
21791da177e4SLinus Torvalds 	sector_div(cylinders,dummy);
21801da177e4SLinus Torvalds 
21811da177e4SLinus Torvalds 	/*
21821da177e4SLinus Torvalds 	 * Handle extended translation size for logical drives
21831da177e4SLinus Torvalds 	 * > 1Gb
21841da177e4SLinus Torvalds 	 */
21851da177e4SLinus Torvalds 	if ((ulong)capacity >= 0x200000) {
21861da177e4SLinus Torvalds 		heads = 255;
21871da177e4SLinus Torvalds 		sectors = 63;
21881da177e4SLinus Torvalds 		dummy = heads * sectors;
21891da177e4SLinus Torvalds 		cylinders = capacity;
21901da177e4SLinus Torvalds 		sector_div(cylinders,dummy);
21911da177e4SLinus Torvalds 	}
21921da177e4SLinus Torvalds 
21931da177e4SLinus Torvalds 	/* return result */
21941da177e4SLinus Torvalds 	geom[0] = heads;
21951da177e4SLinus Torvalds 	geom[1] = sectors;
21961da177e4SLinus Torvalds 	geom[2] = cylinders;
21971da177e4SLinus Torvalds 
21981da177e4SLinus Torvalds 	dprintk((KERN_NOTICE
21991da177e4SLinus Torvalds 		": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
22001da177e4SLinus Torvalds 		sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
22011da177e4SLinus Torvalds 
22021da177e4SLinus Torvalds 	return 0;
22031da177e4SLinus Torvalds }
22041da177e4SLinus Torvalds 
2205f44e5461SMoore, Eric /* Search IOC page 3 to determine if this is hidden physical disk
2206f44e5461SMoore, Eric  *
2207f44e5461SMoore, Eric  */
2208f44e5461SMoore, Eric int
2209793955f5SEric Moore mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
2210f44e5461SMoore, Eric {
2211b506ade9SEric Moore 	struct inactive_raid_component_info *component_info;
2212f44e5461SMoore, Eric 	int i;
2213793955f5SEric Moore 	int rc = 0;
2214f44e5461SMoore, Eric 
2215793955f5SEric Moore 	if (!ioc->raid_data.pIocPg3)
2216793955f5SEric Moore 		goto out;
2217f44e5461SMoore, Eric 	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2218793955f5SEric Moore 		if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2219793955f5SEric Moore 		    (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2220793955f5SEric Moore 			rc = 1;
2221793955f5SEric Moore 			goto out;
2222f44e5461SMoore, Eric 		}
2223793955f5SEric Moore 	}
2224793955f5SEric Moore 
2225b506ade9SEric Moore 	/*
2226b506ade9SEric Moore 	 * Check inactive list for matching phys disks
2227b506ade9SEric Moore 	 */
2228b506ade9SEric Moore 	if (list_empty(&ioc->raid_data.inactive_list))
2229b506ade9SEric Moore 		goto out;
2230b506ade9SEric Moore 
2231b506ade9SEric Moore 	down(&ioc->raid_data.inactive_list_mutex);
2232b506ade9SEric Moore 	list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2233b506ade9SEric Moore 	    list) {
2234b506ade9SEric Moore 		if ((component_info->d.PhysDiskID == id) &&
2235b506ade9SEric Moore 		    (component_info->d.PhysDiskBus == channel))
2236b506ade9SEric Moore 			rc = 1;
2237b506ade9SEric Moore 	}
2238b506ade9SEric Moore 	up(&ioc->raid_data.inactive_list_mutex);
2239b506ade9SEric Moore 
2240793955f5SEric Moore  out:
2241793955f5SEric Moore 	return rc;
2242f44e5461SMoore, Eric }
2243f44e5461SMoore, Eric EXPORT_SYMBOL(mptscsih_is_phys_disk);
2244f44e5461SMoore, Eric 
2245793955f5SEric Moore u8
2246793955f5SEric Moore mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2247c92f222eSJames Bottomley {
2248b506ade9SEric Moore 	struct inactive_raid_component_info *component_info;
2249c92f222eSJames Bottomley 	int i;
2250793955f5SEric Moore 	int rc = -ENXIO;
2251c92f222eSJames Bottomley 
2252793955f5SEric Moore 	if (!ioc->raid_data.pIocPg3)
2253793955f5SEric Moore 		goto out;
2254793955f5SEric Moore 	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2255793955f5SEric Moore 		if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2256793955f5SEric Moore 		    (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2257793955f5SEric Moore 			rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2258793955f5SEric Moore 			goto out;
2259793955f5SEric Moore 		}
2260c92f222eSJames Bottomley 	}
2261c92f222eSJames Bottomley 
2262b506ade9SEric Moore 	/*
2263b506ade9SEric Moore 	 * Check inactive list for matching phys disks
2264b506ade9SEric Moore 	 */
2265b506ade9SEric Moore 	if (list_empty(&ioc->raid_data.inactive_list))
2266b506ade9SEric Moore 		goto out;
2267b506ade9SEric Moore 
2268b506ade9SEric Moore 	down(&ioc->raid_data.inactive_list_mutex);
2269b506ade9SEric Moore 	list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2270b506ade9SEric Moore 	    list) {
2271b506ade9SEric Moore 		if ((component_info->d.PhysDiskID == id) &&
2272b506ade9SEric Moore 		    (component_info->d.PhysDiskBus == channel))
2273b506ade9SEric Moore 			rc = component_info->d.PhysDiskNum;
2274b506ade9SEric Moore 	}
2275b506ade9SEric Moore 	up(&ioc->raid_data.inactive_list_mutex);
2276b506ade9SEric Moore 
2277793955f5SEric Moore  out:
2278793955f5SEric Moore 	return rc;
2279c92f222eSJames Bottomley }
2280c92f222eSJames Bottomley EXPORT_SYMBOL(mptscsih_raid_id_to_num);
2281c92f222eSJames Bottomley 
2282c7c82987SMoore, Eric Dean /*
2283c7c82987SMoore, Eric Dean  *	OS entry point to allow for host driver to free allocated memory
2284c7c82987SMoore, Eric Dean  *	Called if no device present or device being unloaded
2285c7c82987SMoore, Eric Dean  */
2286c7c82987SMoore, Eric Dean void
2287c7c82987SMoore, Eric Dean mptscsih_slave_destroy(struct scsi_device *sdev)
2288c7c82987SMoore, Eric Dean {
2289c7c82987SMoore, Eric Dean 	struct Scsi_Host	*host = sdev->host;
22901da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd = (MPT_SCSI_HOST *)host->hostdata;
2291c7c82987SMoore, Eric Dean 	VirtTarget		*vtarget;
2292c7c82987SMoore, Eric Dean 	VirtDevice		*vdevice;
2293c7c82987SMoore, Eric Dean 	struct scsi_target 	*starget;
22941da177e4SLinus Torvalds 
2295c7c82987SMoore, Eric Dean 	starget = scsi_target(sdev);
2296c7c82987SMoore, Eric Dean 	vtarget = starget->hostdata;
2297c7c82987SMoore, Eric Dean 	vdevice = sdev->hostdata;
22981da177e4SLinus Torvalds 
2299c7c82987SMoore, Eric Dean 	mptscsih_search_running_cmds(hd, vdevice);
2300c7c82987SMoore, Eric Dean 	vtarget->num_luns--;
2301c7c82987SMoore, Eric Dean 	mptscsih_synchronize_cache(hd, vdevice);
2302c7c82987SMoore, Eric Dean 	kfree(vdevice);
2303c7c82987SMoore, Eric Dean 	sdev->hostdata = NULL;
23041da177e4SLinus Torvalds }
23051da177e4SLinus Torvalds 
23066e3815baSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
23076e3815baSMoore, Eric Dean /*
23086e3815baSMoore, Eric Dean  *	mptscsih_change_queue_depth - This function will set a devices queue depth
23096e3815baSMoore, Eric Dean  *	@sdev: per scsi_device pointer
23106e3815baSMoore, Eric Dean  *	@qdepth: requested queue depth
23116e3815baSMoore, Eric Dean  *
23126e3815baSMoore, Eric Dean  *	Adding support for new 'change_queue_depth' api.
23136e3815baSMoore, Eric Dean */
23146e3815baSMoore, Eric Dean int
23156e3815baSMoore, Eric Dean mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
23161da177e4SLinus Torvalds {
23176e3815baSMoore, Eric Dean 	MPT_SCSI_HOST		*hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2318c7c82987SMoore, Eric Dean 	VirtTarget 		*vtarget;
2319c7c82987SMoore, Eric Dean 	struct scsi_target 	*starget;
23201da177e4SLinus Torvalds 	int			max_depth;
23211da177e4SLinus Torvalds 	int			tagged;
23221da177e4SLinus Torvalds 
2323c7c82987SMoore, Eric Dean 	starget = scsi_target(sdev);
2324c7c82987SMoore, Eric Dean 	vtarget = starget->hostdata;
23256e3815baSMoore, Eric Dean 
2326a9b2937aSMoore, Eric Dean 	if (hd->ioc->bus_type == SPI) {
2327c7c82987SMoore, Eric Dean 		if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
23281da177e4SLinus Torvalds 			max_depth = 1;
2329c92f222eSJames Bottomley 		else if (sdev->type == TYPE_DISK &&
2330c92f222eSJames Bottomley 			 vtarget->minSyncFactor <= MPT_ULTRA160)
23311da177e4SLinus Torvalds 			max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
23321da177e4SLinus Torvalds 		else
23331da177e4SLinus Torvalds 			max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
23341da177e4SLinus Torvalds 	} else
23351da177e4SLinus Torvalds 		max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
23361da177e4SLinus Torvalds 
23371da177e4SLinus Torvalds 	if (qdepth > max_depth)
23381da177e4SLinus Torvalds 		qdepth = max_depth;
23391da177e4SLinus Torvalds 	if (qdepth == 1)
23401da177e4SLinus Torvalds 		tagged = 0;
23411da177e4SLinus Torvalds 	else
23421da177e4SLinus Torvalds 		tagged = MSG_SIMPLE_TAG;
23431da177e4SLinus Torvalds 
23446e3815baSMoore, Eric Dean 	scsi_adjust_queue_depth(sdev, tagged, qdepth);
23456e3815baSMoore, Eric Dean 	return sdev->queue_depth;
23461da177e4SLinus Torvalds }
23471da177e4SLinus Torvalds 
23481da177e4SLinus Torvalds /*
23491da177e4SLinus Torvalds  *	OS entry point to adjust the queue_depths on a per-device basis.
23501da177e4SLinus Torvalds  *	Called once per device the bus scan. Use it to force the queue_depth
23511da177e4SLinus Torvalds  *	member to 1 if a device does not support Q tags.
23521da177e4SLinus Torvalds  *	Return non-zero if fails.
23531da177e4SLinus Torvalds  */
23540d0c7974SMoore, Eric Dean  int
2355c7c82987SMoore, Eric Dean mptscsih_slave_configure(struct scsi_device *sdev)
23561da177e4SLinus Torvalds {
2357c7c82987SMoore, Eric Dean 	struct Scsi_Host	*sh = sdev->host;
2358c7c82987SMoore, Eric Dean 	VirtTarget		*vtarget;
2359c7c82987SMoore, Eric Dean 	VirtDevice		*vdevice;
2360c7c82987SMoore, Eric Dean 	struct scsi_target 	*starget;
23611da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd = (MPT_SCSI_HOST *)sh->hostdata;
23621da177e4SLinus Torvalds 
2363c7c82987SMoore, Eric Dean 	starget = scsi_target(sdev);
2364c7c82987SMoore, Eric Dean 	vtarget = starget->hostdata;
2365c7c82987SMoore, Eric Dean 	vdevice = sdev->hostdata;
23661da177e4SLinus Torvalds 
23671da177e4SLinus Torvalds 	dsprintk((MYIOC_s_INFO_FMT
2368793955f5SEric Moore 		"device @ %p, channel=%d, id=%d, lun=%d\n",
2369793955f5SEric Moore 		hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2370c7c82987SMoore, Eric Dean 	if (hd->ioc->bus_type == SPI)
23711da177e4SLinus Torvalds 		dsprintk((MYIOC_s_INFO_FMT
23721da177e4SLinus Torvalds 		    "sdtr %d wdtr %d ppr %d inq length=%d\n",
2373c7c82987SMoore, Eric Dean 		    hd->ioc->name, sdev->sdtr, sdev->wdtr,
2374c7c82987SMoore, Eric Dean 		    sdev->ppr, sdev->inquiry_len));
23751da177e4SLinus Torvalds 
2376c7c82987SMoore, Eric Dean 	if (sdev->id > sh->max_id) {
23771da177e4SLinus Torvalds 		/* error case, should never happen */
2378c7c82987SMoore, Eric Dean 		scsi_adjust_queue_depth(sdev, 0, 1);
23791da177e4SLinus Torvalds 		goto slave_configure_exit;
23801da177e4SLinus Torvalds 	}
23811da177e4SLinus Torvalds 
2382c7c82987SMoore, Eric Dean 	vdevice->configured_lun = 1;
2383c7c82987SMoore, Eric Dean 	mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
23841da177e4SLinus Torvalds 
23851da177e4SLinus Torvalds 	dsprintk((MYIOC_s_INFO_FMT
23861da177e4SLinus Torvalds 		"Queue depth=%d, tflags=%x\n",
2387c7c82987SMoore, Eric Dean 		hd->ioc->name, sdev->queue_depth, vtarget->tflags));
23881da177e4SLinus Torvalds 
2389c7c82987SMoore, Eric Dean 	if (hd->ioc->bus_type == SPI)
23901da177e4SLinus Torvalds 		dsprintk((MYIOC_s_INFO_FMT
23911da177e4SLinus Torvalds 		    "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2392c7c82987SMoore, Eric Dean 		    hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2393c7c82987SMoore, Eric Dean 		    vtarget->minSyncFactor));
23941da177e4SLinus Torvalds 
23951da177e4SLinus Torvalds slave_configure_exit:
23961da177e4SLinus Torvalds 
23971da177e4SLinus Torvalds 	dsprintk((MYIOC_s_INFO_FMT
23981da177e4SLinus Torvalds 		"tagged %d, simple %d, ordered %d\n",
2399c7c82987SMoore, Eric Dean 		hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2400c7c82987SMoore, Eric Dean 		sdev->ordered_tags));
24011da177e4SLinus Torvalds 
24021da177e4SLinus Torvalds 	return 0;
24031da177e4SLinus Torvalds }
24041da177e4SLinus Torvalds 
24051da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
24061da177e4SLinus Torvalds /*
24071da177e4SLinus Torvalds  *  Private routines...
24081da177e4SLinus Torvalds  */
24091da177e4SLinus Torvalds 
24101da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
24111da177e4SLinus Torvalds /* Utility function to copy sense data from the scsi_cmnd buffer
24121da177e4SLinus Torvalds  * to the FC and SCSI target structures.
24131da177e4SLinus Torvalds  *
24141da177e4SLinus Torvalds  */
24151da177e4SLinus Torvalds static void
24160d0c7974SMoore, Eric Dean  mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
24171da177e4SLinus Torvalds {
2418c7c82987SMoore, Eric Dean 	VirtDevice	*vdev;
24191da177e4SLinus Torvalds 	SCSIIORequest_t	*pReq;
24201da177e4SLinus Torvalds 	u32		 sense_count = le32_to_cpu(pScsiReply->SenseCount);
24211da177e4SLinus Torvalds 
24221da177e4SLinus Torvalds 	/* Get target structure
24231da177e4SLinus Torvalds 	 */
24241da177e4SLinus Torvalds 	pReq = (SCSIIORequest_t *) mf;
2425c7c82987SMoore, Eric Dean 	vdev = sc->device->hostdata;
24261da177e4SLinus Torvalds 
24271da177e4SLinus Torvalds 	if (sense_count) {
24281da177e4SLinus Torvalds 		u8 *sense_data;
24291da177e4SLinus Torvalds 		int req_index;
24301da177e4SLinus Torvalds 
24311da177e4SLinus Torvalds 		/* Copy the sense received into the scsi command block. */
24321da177e4SLinus Torvalds 		req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
24331da177e4SLinus Torvalds 		sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
24341da177e4SLinus Torvalds 		memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
24351da177e4SLinus Torvalds 
24361da177e4SLinus Torvalds 		/* Log SMART data (asc = 0x5D, non-IM case only) if required.
24371da177e4SLinus Torvalds 		 */
24381da177e4SLinus Torvalds 		if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
2439c7c82987SMoore, Eric Dean 			if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
24401da177e4SLinus Torvalds 				int idx;
24411da177e4SLinus Torvalds 				MPT_ADAPTER *ioc = hd->ioc;
24421da177e4SLinus Torvalds 
24435b5ef4f6SMoore, Eric 				idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
24441da177e4SLinus Torvalds 				ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
24451da177e4SLinus Torvalds 				ioc->events[idx].eventContext = ioc->eventContext;
24461da177e4SLinus Torvalds 
24473d9780b9SDave Jones 				ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
24483d9780b9SDave Jones 					(MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
24493d9780b9SDave Jones 					(sc->device->channel << 8) | sc->device->id;
24501da177e4SLinus Torvalds 
24513d9780b9SDave Jones 				ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
24521da177e4SLinus Torvalds 
24531da177e4SLinus Torvalds 				ioc->eventContext++;
2454786899b0SEric Moore 				if (hd->ioc->pcidev->vendor ==
2455786899b0SEric Moore 				    PCI_VENDOR_ID_IBM) {
2456786899b0SEric Moore 					mptscsih_issue_sep_command(hd->ioc,
2457786899b0SEric Moore 					    vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2458786899b0SEric Moore 					vdev->vtarget->tflags |=
2459786899b0SEric Moore 					    MPT_TARGET_FLAGS_LED_ON;
2460786899b0SEric Moore 				}
24611da177e4SLinus Torvalds 			}
24621da177e4SLinus Torvalds 		}
24631da177e4SLinus Torvalds 	} else {
24641da177e4SLinus Torvalds 		dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
24651da177e4SLinus Torvalds 				hd->ioc->name));
24661da177e4SLinus Torvalds 	}
24671da177e4SLinus Torvalds }
24681da177e4SLinus Torvalds 
24693dc0b03fSEric Moore static int
24701da177e4SLinus Torvalds SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
24711da177e4SLinus Torvalds {
24721da177e4SLinus Torvalds 	MPT_SCSI_HOST *hd;
24731da177e4SLinus Torvalds 	int i;
24741da177e4SLinus Torvalds 
24751da177e4SLinus Torvalds 	hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
24761da177e4SLinus Torvalds 
24771da177e4SLinus Torvalds 	for (i = 0; i < hd->ioc->req_depth; i++) {
24781da177e4SLinus Torvalds 		if (hd->ScsiLookup[i] == sc) {
24791da177e4SLinus Torvalds 			return i;
24801da177e4SLinus Torvalds 		}
24811da177e4SLinus Torvalds 	}
24821da177e4SLinus Torvalds 
24831da177e4SLinus Torvalds 	return -1;
24841da177e4SLinus Torvalds }
24851da177e4SLinus Torvalds 
24861da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
24870d0c7974SMoore, Eric Dean  int
24881da177e4SLinus Torvalds mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
24891da177e4SLinus Torvalds {
24901da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
24911da177e4SLinus Torvalds 	unsigned long	 flags;
2492466544d8SMoore, Eric Dean 	int 		ii;
24931da177e4SLinus Torvalds 
24941da177e4SLinus Torvalds 	dtmprintk((KERN_WARNING MYNAM
24951da177e4SLinus Torvalds 			": IOC %s_reset routed to SCSI host driver!\n",
24961da177e4SLinus Torvalds 			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
24971da177e4SLinus Torvalds 			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
24981da177e4SLinus Torvalds 
24991da177e4SLinus Torvalds 	/* If a FW reload request arrives after base installed but
25001da177e4SLinus Torvalds 	 * before all scsi hosts have been attached, then an alt_ioc
25011da177e4SLinus Torvalds 	 * may have a NULL sh pointer.
25021da177e4SLinus Torvalds 	 */
25031da177e4SLinus Torvalds 	if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
25041da177e4SLinus Torvalds 		return 0;
25051da177e4SLinus Torvalds 	else
25061da177e4SLinus Torvalds 		hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
25071da177e4SLinus Torvalds 
25081da177e4SLinus Torvalds 	if (reset_phase == MPT_IOC_SETUP_RESET) {
25091da177e4SLinus Torvalds 		dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
25101da177e4SLinus Torvalds 
25111da177e4SLinus Torvalds 		/* Clean Up:
25121da177e4SLinus Torvalds 		 * 1. Set Hard Reset Pending Flag
25131da177e4SLinus Torvalds 		 * All new commands go to doneQ
25141da177e4SLinus Torvalds 		 */
25151da177e4SLinus Torvalds 		hd->resetPending = 1;
25161da177e4SLinus Torvalds 
25171da177e4SLinus Torvalds 	} else if (reset_phase == MPT_IOC_PRE_RESET) {
25181da177e4SLinus Torvalds 		dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
25191da177e4SLinus Torvalds 
25201da177e4SLinus Torvalds 		/* 2. Flush running commands
25211da177e4SLinus Torvalds 		 *	Clean ScsiLookup (and associated memory)
25221da177e4SLinus Torvalds 		 *	AND clean mytaskQ
25231da177e4SLinus Torvalds 		 */
25241da177e4SLinus Torvalds 
25251da177e4SLinus Torvalds 		/* 2b. Reply to OS all known outstanding I/O commands.
25261da177e4SLinus Torvalds 		 */
25271da177e4SLinus Torvalds 		mptscsih_flush_running_cmds(hd);
25281da177e4SLinus Torvalds 
25291da177e4SLinus Torvalds 		/* 2c. If there was an internal command that
25301da177e4SLinus Torvalds 		 * has not completed, configuration or io request,
25311da177e4SLinus Torvalds 		 * free these resources.
25321da177e4SLinus Torvalds 		 */
25331da177e4SLinus Torvalds 		if (hd->cmdPtr) {
25341da177e4SLinus Torvalds 			del_timer(&hd->timer);
25351da177e4SLinus Torvalds 			mpt_free_msg_frame(ioc, hd->cmdPtr);
25361da177e4SLinus Torvalds 		}
25371da177e4SLinus Torvalds 
25381da177e4SLinus Torvalds 		dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
25391da177e4SLinus Torvalds 
25401da177e4SLinus Torvalds 	} else {
25411da177e4SLinus Torvalds 		dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
25421da177e4SLinus Torvalds 
25431da177e4SLinus Torvalds 		/* Once a FW reload begins, all new OS commands are
25441da177e4SLinus Torvalds 		 * redirected to the doneQ w/ a reset status.
25451da177e4SLinus Torvalds 		 * Init all control structures.
25461da177e4SLinus Torvalds 		 */
25471da177e4SLinus Torvalds 
25481da177e4SLinus Torvalds 		/* ScsiLookup initialization
25491da177e4SLinus Torvalds 		 */
25501da177e4SLinus Torvalds 		for (ii=0; ii < hd->ioc->req_depth; ii++)
25511da177e4SLinus Torvalds 			hd->ScsiLookup[ii] = NULL;
25521da177e4SLinus Torvalds 
25531da177e4SLinus Torvalds 		/* 2. Chain Buffer initialization
25541da177e4SLinus Torvalds 		 */
25551da177e4SLinus Torvalds 
2556a9b2937aSMoore, Eric Dean 		/* 4. Renegotiate to all devices, if SPI
25571da177e4SLinus Torvalds 		 */
25581da177e4SLinus Torvalds 
25591da177e4SLinus Torvalds 		/* 5. Enable new commands to be posted
25601da177e4SLinus Torvalds 		 */
25611da177e4SLinus Torvalds 		spin_lock_irqsave(&ioc->FreeQlock, flags);
25621da177e4SLinus Torvalds 		hd->tmPending = 0;
25631da177e4SLinus Torvalds 		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
25641da177e4SLinus Torvalds 		hd->resetPending = 0;
25651da177e4SLinus Torvalds 		hd->tmState = TM_STATE_NONE;
25661da177e4SLinus Torvalds 
25671da177e4SLinus Torvalds 		/* 6. If there was an internal command,
25681da177e4SLinus Torvalds 		 * wake this process up.
25691da177e4SLinus Torvalds 		 */
25701da177e4SLinus Torvalds 		if (hd->cmdPtr) {
25711da177e4SLinus Torvalds 			/*
25721da177e4SLinus Torvalds 			 * Wake up the original calling thread
25731da177e4SLinus Torvalds 			 */
25741da177e4SLinus Torvalds 			hd->pLocal = &hd->localReply;
25751da177e4SLinus Torvalds 			hd->pLocal->completion = MPT_SCANDV_DID_RESET;
25760d0c7974SMoore, Eric Dean  			hd->scandv_wait_done = 1;
25770d0c7974SMoore, Eric Dean  			wake_up(&hd->scandv_waitq);
25781da177e4SLinus Torvalds 			hd->cmdPtr = NULL;
25791da177e4SLinus Torvalds 		}
25801da177e4SLinus Torvalds 
25811da177e4SLinus Torvalds 		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
25821da177e4SLinus Torvalds 
25831da177e4SLinus Torvalds 	}
25841da177e4SLinus Torvalds 
25851da177e4SLinus Torvalds 	return 1;		/* currently means nothing really */
25861da177e4SLinus Torvalds }
25871da177e4SLinus Torvalds 
25881da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
25890d0c7974SMoore, Eric Dean  int
25901da177e4SLinus Torvalds mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
25911da177e4SLinus Torvalds {
25921da177e4SLinus Torvalds 	MPT_SCSI_HOST *hd;
25931da177e4SLinus Torvalds 	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
25941da177e4SLinus Torvalds 
25953a892befSMoore, Eric 	devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
25961da177e4SLinus Torvalds 			ioc->name, event));
25971da177e4SLinus Torvalds 
2598466544d8SMoore, Eric Dean 	if (ioc->sh == NULL ||
2599466544d8SMoore, Eric Dean 		((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2600466544d8SMoore, Eric Dean 		return 1;
2601466544d8SMoore, Eric Dean 
26021da177e4SLinus Torvalds 	switch (event) {
26031da177e4SLinus Torvalds 	case MPI_EVENT_UNIT_ATTENTION:			/* 03 */
26041da177e4SLinus Torvalds 		/* FIXME! */
26051da177e4SLinus Torvalds 		break;
26061da177e4SLinus Torvalds 	case MPI_EVENT_IOC_BUS_RESET:			/* 04 */
26071da177e4SLinus Torvalds 	case MPI_EVENT_EXT_BUS_RESET:			/* 05 */
2608a9b2937aSMoore, Eric Dean 		if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
26091da177e4SLinus Torvalds 			hd->soft_resets++;
26101da177e4SLinus Torvalds 		break;
26111da177e4SLinus Torvalds 	case MPI_EVENT_LOGOUT:				/* 09 */
26121da177e4SLinus Torvalds 		/* FIXME! */
26131da177e4SLinus Torvalds 		break;
26141da177e4SLinus Torvalds 
261505e8ec17SMichael Reed 	case MPI_EVENT_RESCAN:				/* 06 */
261605e8ec17SMichael Reed 		break;
261705e8ec17SMichael Reed 
26181da177e4SLinus Torvalds 		/*
26191da177e4SLinus Torvalds 		 *  CHECKME! Don't think we need to do
26201da177e4SLinus Torvalds 		 *  anything for these, but...
26211da177e4SLinus Torvalds 		 */
26221da177e4SLinus Torvalds 	case MPI_EVENT_LINK_STATUS_CHANGE:		/* 07 */
26231da177e4SLinus Torvalds 	case MPI_EVENT_LOOP_STATE_CHANGE:		/* 08 */
26241da177e4SLinus Torvalds 		/*
26251da177e4SLinus Torvalds 		 *  CHECKME!  Falling thru...
26261da177e4SLinus Torvalds 		 */
26271da177e4SLinus Torvalds 		break;
26281da177e4SLinus Torvalds 
26291da177e4SLinus Torvalds 	case MPI_EVENT_INTEGRATED_RAID:			/* 0B */
26301da177e4SLinus Torvalds 		break;
26311da177e4SLinus Torvalds 
26321da177e4SLinus Torvalds 	case MPI_EVENT_NONE:				/* 00 */
26331da177e4SLinus Torvalds 	case MPI_EVENT_LOG_DATA:			/* 01 */
26341da177e4SLinus Torvalds 	case MPI_EVENT_STATE_CHANGE:			/* 02 */
26351da177e4SLinus Torvalds 	case MPI_EVENT_EVENT_CHANGE:			/* 0A */
26361da177e4SLinus Torvalds 	default:
26371da177e4SLinus Torvalds 		dprintk((KERN_INFO "  Ignoring event (=%02Xh)\n", event));
26381da177e4SLinus Torvalds 		break;
26391da177e4SLinus Torvalds 	}
26401da177e4SLinus Torvalds 
26411da177e4SLinus Torvalds 	return 1;		/* currently means nothing really */
26421da177e4SLinus Torvalds }
26431da177e4SLinus Torvalds 
26441da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26451da177e4SLinus Torvalds /*
26461da177e4SLinus Torvalds  *  Bus Scan and Domain Validation functionality ...
26471da177e4SLinus Torvalds  */
26481da177e4SLinus Torvalds 
26491da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26501da177e4SLinus Torvalds /*
26511da177e4SLinus Torvalds  *	mptscsih_scandv_complete - Scan and DV callback routine registered
26521da177e4SLinus Torvalds  *	to Fustion MPT (base) driver.
26531da177e4SLinus Torvalds  *
26541da177e4SLinus Torvalds  *	@ioc: Pointer to MPT_ADAPTER structure
26551da177e4SLinus Torvalds  *	@mf: Pointer to original MPT request frame
26561da177e4SLinus Torvalds  *	@mr: Pointer to MPT reply frame (NULL if TurboReply)
26571da177e4SLinus Torvalds  *
26581da177e4SLinus Torvalds  *	This routine is called from mpt.c::mpt_interrupt() at the completion
26591da177e4SLinus Torvalds  *	of any SCSI IO request.
26601da177e4SLinus Torvalds  *	This routine is registered with the Fusion MPT (base) driver at driver
26611da177e4SLinus Torvalds  *	load/init time via the mpt_register() API call.
26621da177e4SLinus Torvalds  *
26631da177e4SLinus Torvalds  *	Returns 1 indicating alloc'd request frame ptr should be freed.
26641da177e4SLinus Torvalds  *
26651da177e4SLinus Torvalds  *	Remark: Sets a completion code and (possibly) saves sense data
26661da177e4SLinus Torvalds  *	in the IOC member localReply structure.
26671da177e4SLinus Torvalds  *	Used ONLY for DV and other internal commands.
26681da177e4SLinus Torvalds  */
26690d0c7974SMoore, Eric Dean  int
26701da177e4SLinus Torvalds mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
26711da177e4SLinus Torvalds {
26721da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
26731da177e4SLinus Torvalds 	SCSIIORequest_t *pReq;
26741da177e4SLinus Torvalds 	int		 completionCode;
26751da177e4SLinus Torvalds 	u16		 req_idx;
26761da177e4SLinus Torvalds 
26770d0c7974SMoore, Eric Dean  	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
26780d0c7974SMoore, Eric Dean  
26791da177e4SLinus Torvalds 	if ((mf == NULL) ||
26801da177e4SLinus Torvalds 	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
26811da177e4SLinus Torvalds 		printk(MYIOC_s_ERR_FMT
26821da177e4SLinus Torvalds 			"ScanDvComplete, %s req frame ptr! (=%p)\n",
26831da177e4SLinus Torvalds 				ioc->name, mf?"BAD":"NULL", (void *) mf);
26841da177e4SLinus Torvalds 		goto wakeup;
26851da177e4SLinus Torvalds 	}
26861da177e4SLinus Torvalds 
26871da177e4SLinus Torvalds 	del_timer(&hd->timer);
26881da177e4SLinus Torvalds 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
26891da177e4SLinus Torvalds 	hd->ScsiLookup[req_idx] = NULL;
26901da177e4SLinus Torvalds 	pReq = (SCSIIORequest_t *) mf;
26911da177e4SLinus Torvalds 
26921da177e4SLinus Torvalds 	if (mf != hd->cmdPtr) {
26931da177e4SLinus Torvalds 		printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
26941da177e4SLinus Torvalds 				hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
26951da177e4SLinus Torvalds 	}
26961da177e4SLinus Torvalds 	hd->cmdPtr = NULL;
26971da177e4SLinus Torvalds 
26981da177e4SLinus Torvalds 	ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
26991da177e4SLinus Torvalds 			hd->ioc->name, mf, mr, req_idx));
27001da177e4SLinus Torvalds 
27011da177e4SLinus Torvalds 	hd->pLocal = &hd->localReply;
27021da177e4SLinus Torvalds 	hd->pLocal->scsiStatus = 0;
27031da177e4SLinus Torvalds 
27041da177e4SLinus Torvalds 	/* If target struct exists, clear sense valid flag.
27051da177e4SLinus Torvalds 	 */
27061da177e4SLinus Torvalds 	if (mr == NULL) {
27071da177e4SLinus Torvalds 		completionCode = MPT_SCANDV_GOOD;
27081da177e4SLinus Torvalds 	} else {
27091da177e4SLinus Torvalds 		SCSIIOReply_t	*pReply;
27101da177e4SLinus Torvalds 		u16		 status;
27111da177e4SLinus Torvalds 		u8		 scsi_status;
27121da177e4SLinus Torvalds 
27131da177e4SLinus Torvalds 		pReply = (SCSIIOReply_t *) mr;
27141da177e4SLinus Torvalds 
27151da177e4SLinus Torvalds 		status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
27161da177e4SLinus Torvalds 		scsi_status = pReply->SCSIStatus;
27171da177e4SLinus Torvalds 
27181da177e4SLinus Torvalds 		ddvtprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
27191da177e4SLinus Torvalds 			     status, pReply->SCSIState, scsi_status,
27201da177e4SLinus Torvalds 			     le32_to_cpu(pReply->IOCLogInfo)));
27211da177e4SLinus Torvalds 
27221da177e4SLinus Torvalds 		switch(status) {
27231da177e4SLinus Torvalds 
27241da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
27251da177e4SLinus Torvalds 			completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
27261da177e4SLinus Torvalds 			break;
27271da177e4SLinus Torvalds 
27281da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
27291da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
27301da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
27311da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
27321da177e4SLinus Torvalds 			completionCode = MPT_SCANDV_DID_RESET;
27331da177e4SLinus Torvalds 			break;
27341da177e4SLinus Torvalds 
27351da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
27361da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
27371da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
27381da177e4SLinus Torvalds 			if (pReply->Function == MPI_FUNCTION_CONFIG) {
27391da177e4SLinus Torvalds 				ConfigReply_t *pr = (ConfigReply_t *)mr;
27401da177e4SLinus Torvalds 				completionCode = MPT_SCANDV_GOOD;
27411da177e4SLinus Torvalds 				hd->pLocal->header.PageVersion = pr->Header.PageVersion;
27421da177e4SLinus Torvalds 				hd->pLocal->header.PageLength = pr->Header.PageLength;
27431da177e4SLinus Torvalds 				hd->pLocal->header.PageNumber = pr->Header.PageNumber;
27441da177e4SLinus Torvalds 				hd->pLocal->header.PageType = pr->Header.PageType;
27451da177e4SLinus Torvalds 
27461da177e4SLinus Torvalds 			} else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
27471da177e4SLinus Torvalds 				/* If the RAID Volume request is successful,
27481da177e4SLinus Torvalds 				 * return GOOD, else indicate that
27491da177e4SLinus Torvalds 				 * some type of error occurred.
27501da177e4SLinus Torvalds 				 */
27511da177e4SLinus Torvalds 				MpiRaidActionReply_t	*pr = (MpiRaidActionReply_t *)mr;
2752637fa99bSChristoph Hellwig 				if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
27531da177e4SLinus Torvalds 					completionCode = MPT_SCANDV_GOOD;
27541da177e4SLinus Torvalds 				else
27551da177e4SLinus Torvalds 					completionCode = MPT_SCANDV_SOME_ERROR;
2756c92f222eSJames Bottomley 				memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
27571da177e4SLinus Torvalds 
27581da177e4SLinus Torvalds 			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
27591da177e4SLinus Torvalds 				u8		*sense_data;
27601da177e4SLinus Torvalds 				int		 sz;
27611da177e4SLinus Torvalds 
27621da177e4SLinus Torvalds 				/* save sense data in global structure
27631da177e4SLinus Torvalds 				 */
27641da177e4SLinus Torvalds 				completionCode = MPT_SCANDV_SENSE;
27651da177e4SLinus Torvalds 				hd->pLocal->scsiStatus = scsi_status;
27661da177e4SLinus Torvalds 				sense_data = ((u8 *)hd->ioc->sense_buf_pool +
27671da177e4SLinus Torvalds 					(req_idx * MPT_SENSE_BUFFER_ALLOC));
27681da177e4SLinus Torvalds 
27691da177e4SLinus Torvalds 				sz = min_t(int, pReq->SenseBufferLength,
27701da177e4SLinus Torvalds 							SCSI_STD_SENSE_BYTES);
27711da177e4SLinus Torvalds 				memcpy(hd->pLocal->sense, sense_data, sz);
27721da177e4SLinus Torvalds 
27731da177e4SLinus Torvalds 				ddvprintk((KERN_NOTICE "  Check Condition, sense ptr %p\n",
27741da177e4SLinus Torvalds 						sense_data));
27751da177e4SLinus Torvalds 			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
27761da177e4SLinus Torvalds 				if (pReq->CDB[0] == INQUIRY)
27771da177e4SLinus Torvalds 					completionCode = MPT_SCANDV_ISSUE_SENSE;
27781da177e4SLinus Torvalds 				else
27791da177e4SLinus Torvalds 					completionCode = MPT_SCANDV_DID_RESET;
27801da177e4SLinus Torvalds 			}
27811da177e4SLinus Torvalds 			else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
27821da177e4SLinus Torvalds 				completionCode = MPT_SCANDV_DID_RESET;
27831da177e4SLinus Torvalds 			else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
27841da177e4SLinus Torvalds 				completionCode = MPT_SCANDV_DID_RESET;
27851da177e4SLinus Torvalds 			else {
27861da177e4SLinus Torvalds 				completionCode = MPT_SCANDV_GOOD;
27871da177e4SLinus Torvalds 				hd->pLocal->scsiStatus = scsi_status;
27881da177e4SLinus Torvalds 			}
27891da177e4SLinus Torvalds 			break;
27901da177e4SLinus Torvalds 
27911da177e4SLinus Torvalds 		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
27921da177e4SLinus Torvalds 			if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
27931da177e4SLinus Torvalds 				completionCode = MPT_SCANDV_DID_RESET;
27941da177e4SLinus Torvalds 			else
27951da177e4SLinus Torvalds 				completionCode = MPT_SCANDV_SOME_ERROR;
27961da177e4SLinus Torvalds 			break;
27971da177e4SLinus Torvalds 
27981da177e4SLinus Torvalds 		default:
27991da177e4SLinus Torvalds 			completionCode = MPT_SCANDV_SOME_ERROR;
28001da177e4SLinus Torvalds 			break;
28011da177e4SLinus Torvalds 
28021da177e4SLinus Torvalds 		}	/* switch(status) */
28031da177e4SLinus Torvalds 
28041da177e4SLinus Torvalds 		ddvtprintk((KERN_NOTICE "  completionCode set to %08xh\n",
28051da177e4SLinus Torvalds 				completionCode));
28061da177e4SLinus Torvalds 	} /* end of address reply case */
28071da177e4SLinus Torvalds 
28081da177e4SLinus Torvalds 	hd->pLocal->completion = completionCode;
28091da177e4SLinus Torvalds 
28101da177e4SLinus Torvalds 	/* MF and RF are freed in mpt_interrupt
28111da177e4SLinus Torvalds 	 */
28121da177e4SLinus Torvalds wakeup:
28131da177e4SLinus Torvalds 	/* Free Chain buffers (will never chain) in scan or dv */
28141da177e4SLinus Torvalds 	//mptscsih_freeChainBuffers(ioc, req_idx);
28151da177e4SLinus Torvalds 
28161da177e4SLinus Torvalds 	/*
28171da177e4SLinus Torvalds 	 * Wake up the original calling thread
28181da177e4SLinus Torvalds 	 */
28190d0c7974SMoore, Eric Dean  	hd->scandv_wait_done = 1;
28200d0c7974SMoore, Eric Dean  	wake_up(&hd->scandv_waitq);
28211da177e4SLinus Torvalds 
28221da177e4SLinus Torvalds 	return 1;
28231da177e4SLinus Torvalds }
28241da177e4SLinus Torvalds 
28251da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
28261da177e4SLinus Torvalds /*	mptscsih_timer_expired - Call back for timer process.
28271da177e4SLinus Torvalds  *	Used only for dv functionality.
28281da177e4SLinus Torvalds  *	@data: Pointer to MPT_SCSI_HOST recast as an unsigned long
28291da177e4SLinus Torvalds  *
28301da177e4SLinus Torvalds  */
28310d0c7974SMoore, Eric Dean  void
28320d0c7974SMoore, Eric Dean  mptscsih_timer_expired(unsigned long data)
28331da177e4SLinus Torvalds {
28341da177e4SLinus Torvalds 	MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
28351da177e4SLinus Torvalds 
28361da177e4SLinus Torvalds 	ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
28371da177e4SLinus Torvalds 
28381da177e4SLinus Torvalds 	if (hd->cmdPtr) {
28391da177e4SLinus Torvalds 		MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
28401da177e4SLinus Torvalds 
28411da177e4SLinus Torvalds 		if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
28421da177e4SLinus Torvalds 			/* Desire to issue a task management request here.
28431da177e4SLinus Torvalds 			 * TM requests MUST be single threaded.
28441da177e4SLinus Torvalds 			 * If old eh code and no TM current, issue request.
28451da177e4SLinus Torvalds 			 * If new eh code, do nothing. Wait for OS cmd timeout
28461da177e4SLinus Torvalds 			 *	for bus reset.
28471da177e4SLinus Torvalds 			 */
28481da177e4SLinus Torvalds 			ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
28491da177e4SLinus Torvalds 		} else {
28501da177e4SLinus Torvalds 			/* Perform a FW reload */
28511da177e4SLinus Torvalds 			if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
28521da177e4SLinus Torvalds 				printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
28531da177e4SLinus Torvalds 			}
28541da177e4SLinus Torvalds 		}
28551da177e4SLinus Torvalds 	} else {
28561da177e4SLinus Torvalds 		/* This should NEVER happen */
28571da177e4SLinus Torvalds 		printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
28581da177e4SLinus Torvalds 	}
28591da177e4SLinus Torvalds 
28601da177e4SLinus Torvalds 	/* No more processing.
28611da177e4SLinus Torvalds 	 * TM call will generate an interrupt for SCSI TM Management.
28621da177e4SLinus Torvalds 	 * The FW will reply to all outstanding commands, callback will finish cleanup.
28631da177e4SLinus Torvalds 	 * Hard reset clean-up will free all resources.
28641da177e4SLinus Torvalds 	 */
28651da177e4SLinus Torvalds 	ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
28661da177e4SLinus Torvalds 
28671da177e4SLinus Torvalds 	return;
28681da177e4SLinus Torvalds }
28691da177e4SLinus Torvalds 
28701da177e4SLinus Torvalds 
28711da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
28721da177e4SLinus Torvalds /**
28731da177e4SLinus Torvalds  *	mptscsih_do_cmd - Do internal command.
28741da177e4SLinus Torvalds  *	@hd: MPT_SCSI_HOST pointer
28751da177e4SLinus Torvalds  *	@io: INTERNAL_CMD pointer.
28761da177e4SLinus Torvalds  *
28771da177e4SLinus Torvalds  *	Issue the specified internally generated command and do command
28781da177e4SLinus Torvalds  *	specific cleanup. For bus scan / DV only.
28791da177e4SLinus Torvalds  *	NOTES: If command is Inquiry and status is good,
28801da177e4SLinus Torvalds  *	initialize a target structure, save the data
28811da177e4SLinus Torvalds  *
28821da177e4SLinus Torvalds  *	Remark: Single threaded access only.
28831da177e4SLinus Torvalds  *
28841da177e4SLinus Torvalds  *	Return:
28851da177e4SLinus Torvalds  *		< 0 if an illegal command or no resources
28861da177e4SLinus Torvalds  *
28871da177e4SLinus Torvalds  *		   0 if good
28881da177e4SLinus Torvalds  *
28891da177e4SLinus Torvalds  *		 > 0 if command complete but some type of completion error.
28901da177e4SLinus Torvalds  */
28911da177e4SLinus Torvalds static int
28921da177e4SLinus Torvalds mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
28931da177e4SLinus Torvalds {
28941da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
28951da177e4SLinus Torvalds 	SCSIIORequest_t	*pScsiReq;
28961da177e4SLinus Torvalds 	SCSIIORequest_t	 ReqCopy;
28971da177e4SLinus Torvalds 	int		 my_idx, ii, dir;
28981da177e4SLinus Torvalds 	int		 rc, cmdTimeout;
28991da177e4SLinus Torvalds 	int		in_isr;
29001da177e4SLinus Torvalds 	char		 cmdLen;
29011da177e4SLinus Torvalds 	char		 CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
29021da177e4SLinus Torvalds 	char		 cmd = io->cmd;
29031da177e4SLinus Torvalds 
29041da177e4SLinus Torvalds 	in_isr = in_interrupt();
29051da177e4SLinus Torvalds 	if (in_isr) {
29061da177e4SLinus Torvalds 		dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
29071da177e4SLinus Torvalds        				hd->ioc->name));
29081da177e4SLinus Torvalds 		return -EPERM;
29091da177e4SLinus Torvalds 	}
29101da177e4SLinus Torvalds 
29111da177e4SLinus Torvalds 
29121da177e4SLinus Torvalds 	/* Set command specific information
29131da177e4SLinus Torvalds 	 */
29141da177e4SLinus Torvalds 	switch (cmd) {
29151da177e4SLinus Torvalds 	case INQUIRY:
29161da177e4SLinus Torvalds 		cmdLen = 6;
29171da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29181da177e4SLinus Torvalds 		CDB[0] = cmd;
29191da177e4SLinus Torvalds 		CDB[4] = io->size;
29201da177e4SLinus Torvalds 		cmdTimeout = 10;
29211da177e4SLinus Torvalds 		break;
29221da177e4SLinus Torvalds 
29231da177e4SLinus Torvalds 	case TEST_UNIT_READY:
29241da177e4SLinus Torvalds 		cmdLen = 6;
29251da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29261da177e4SLinus Torvalds 		cmdTimeout = 10;
29271da177e4SLinus Torvalds 		break;
29281da177e4SLinus Torvalds 
29291da177e4SLinus Torvalds 	case START_STOP:
29301da177e4SLinus Torvalds 		cmdLen = 6;
29311da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29321da177e4SLinus Torvalds 		CDB[0] = cmd;
29331da177e4SLinus Torvalds 		CDB[4] = 1;	/*Spin up the disk */
29341da177e4SLinus Torvalds 		cmdTimeout = 15;
29351da177e4SLinus Torvalds 		break;
29361da177e4SLinus Torvalds 
29371da177e4SLinus Torvalds 	case REQUEST_SENSE:
29381da177e4SLinus Torvalds 		cmdLen = 6;
29391da177e4SLinus Torvalds 		CDB[0] = cmd;
29401da177e4SLinus Torvalds 		CDB[4] = io->size;
29411da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29421da177e4SLinus Torvalds 		cmdTimeout = 10;
29431da177e4SLinus Torvalds 		break;
29441da177e4SLinus Torvalds 
29451da177e4SLinus Torvalds 	case READ_BUFFER:
29461da177e4SLinus Torvalds 		cmdLen = 10;
29471da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29481da177e4SLinus Torvalds 		CDB[0] = cmd;
29491da177e4SLinus Torvalds 		if (io->flags & MPT_ICFLAG_ECHO) {
29501da177e4SLinus Torvalds 			CDB[1] = 0x0A;
29511da177e4SLinus Torvalds 		} else {
29521da177e4SLinus Torvalds 			CDB[1] = 0x02;
29531da177e4SLinus Torvalds 		}
29541da177e4SLinus Torvalds 
29551da177e4SLinus Torvalds 		if (io->flags & MPT_ICFLAG_BUF_CAP) {
29561da177e4SLinus Torvalds 			CDB[1] |= 0x01;
29571da177e4SLinus Torvalds 		}
29581da177e4SLinus Torvalds 		CDB[6] = (io->size >> 16) & 0xFF;
29591da177e4SLinus Torvalds 		CDB[7] = (io->size >>  8) & 0xFF;
29601da177e4SLinus Torvalds 		CDB[8] = io->size & 0xFF;
29611da177e4SLinus Torvalds 		cmdTimeout = 10;
29621da177e4SLinus Torvalds 		break;
29631da177e4SLinus Torvalds 
29641da177e4SLinus Torvalds 	case WRITE_BUFFER:
29651da177e4SLinus Torvalds 		cmdLen = 10;
29661da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_WRITE;
29671da177e4SLinus Torvalds 		CDB[0] = cmd;
29681da177e4SLinus Torvalds 		if (io->flags & MPT_ICFLAG_ECHO) {
29691da177e4SLinus Torvalds 			CDB[1] = 0x0A;
29701da177e4SLinus Torvalds 		} else {
29711da177e4SLinus Torvalds 			CDB[1] = 0x02;
29721da177e4SLinus Torvalds 		}
29731da177e4SLinus Torvalds 		CDB[6] = (io->size >> 16) & 0xFF;
29741da177e4SLinus Torvalds 		CDB[7] = (io->size >>  8) & 0xFF;
29751da177e4SLinus Torvalds 		CDB[8] = io->size & 0xFF;
29761da177e4SLinus Torvalds 		cmdTimeout = 10;
29771da177e4SLinus Torvalds 		break;
29781da177e4SLinus Torvalds 
29791da177e4SLinus Torvalds 	case RESERVE:
29801da177e4SLinus Torvalds 		cmdLen = 6;
29811da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29821da177e4SLinus Torvalds 		CDB[0] = cmd;
29831da177e4SLinus Torvalds 		cmdTimeout = 10;
29841da177e4SLinus Torvalds 		break;
29851da177e4SLinus Torvalds 
29861da177e4SLinus Torvalds 	case RELEASE:
29871da177e4SLinus Torvalds 		cmdLen = 6;
29881da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29891da177e4SLinus Torvalds 		CDB[0] = cmd;
29901da177e4SLinus Torvalds 		cmdTimeout = 10;
29911da177e4SLinus Torvalds 		break;
29921da177e4SLinus Torvalds 
29931da177e4SLinus Torvalds 	case SYNCHRONIZE_CACHE:
29941da177e4SLinus Torvalds 		cmdLen = 10;
29951da177e4SLinus Torvalds 		dir = MPI_SCSIIO_CONTROL_READ;
29961da177e4SLinus Torvalds 		CDB[0] = cmd;
29971da177e4SLinus Torvalds //		CDB[1] = 0x02;	/* set immediate bit */
29981da177e4SLinus Torvalds 		cmdTimeout = 10;
29991da177e4SLinus Torvalds 		break;
30001da177e4SLinus Torvalds 
30011da177e4SLinus Torvalds 	default:
30021da177e4SLinus Torvalds 		/* Error Case */
30031da177e4SLinus Torvalds 		return -EFAULT;
30041da177e4SLinus Torvalds 	}
30051da177e4SLinus Torvalds 
30061da177e4SLinus Torvalds 	/* Get and Populate a free Frame
30071da177e4SLinus Torvalds 	 */
30080d0c7974SMoore, Eric Dean  	if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
30091da177e4SLinus Torvalds 		ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
30101da177e4SLinus Torvalds 					hd->ioc->name));
30111da177e4SLinus Torvalds 		return -EBUSY;
30121da177e4SLinus Torvalds 	}
30131da177e4SLinus Torvalds 
30141da177e4SLinus Torvalds 	pScsiReq = (SCSIIORequest_t *) mf;
30151da177e4SLinus Torvalds 
30161da177e4SLinus Torvalds 	/* Get the request index */
30171da177e4SLinus Torvalds 	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
30181da177e4SLinus Torvalds 	ADD_INDEX_LOG(my_idx); /* for debug */
30191da177e4SLinus Torvalds 
30201da177e4SLinus Torvalds 	if (io->flags & MPT_ICFLAG_PHYS_DISK) {
30211da177e4SLinus Torvalds 		pScsiReq->TargetID = io->physDiskNum;
30221da177e4SLinus Torvalds 		pScsiReq->Bus = 0;
30231da177e4SLinus Torvalds 		pScsiReq->ChainOffset = 0;
30241da177e4SLinus Torvalds 		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
30251da177e4SLinus Torvalds 	} else {
30261da177e4SLinus Torvalds 		pScsiReq->TargetID = io->id;
3027793955f5SEric Moore 		pScsiReq->Bus = io->channel;
30281da177e4SLinus Torvalds 		pScsiReq->ChainOffset = 0;
30291da177e4SLinus Torvalds 		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
30301da177e4SLinus Torvalds 	}
30311da177e4SLinus Torvalds 
30321da177e4SLinus Torvalds 	pScsiReq->CDBLength = cmdLen;
30331da177e4SLinus Torvalds 	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
30341da177e4SLinus Torvalds 
30351da177e4SLinus Torvalds 	pScsiReq->Reserved = 0;
30361da177e4SLinus Torvalds 
30371da177e4SLinus Torvalds 	pScsiReq->MsgFlags = mpt_msg_flags();
30381da177e4SLinus Torvalds 	/* MsgContext set in mpt_get_msg_fram call  */
30391da177e4SLinus Torvalds 
3040793955f5SEric Moore 	int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
30411da177e4SLinus Torvalds 
30421da177e4SLinus Torvalds 	if (io->flags & MPT_ICFLAG_TAGGED_CMD)
30431da177e4SLinus Torvalds 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
30441da177e4SLinus Torvalds 	else
30451da177e4SLinus Torvalds 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
30461da177e4SLinus Torvalds 
30471da177e4SLinus Torvalds 	if (cmd == REQUEST_SENSE) {
30481da177e4SLinus Torvalds 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
30491da177e4SLinus Torvalds 		ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
30501da177e4SLinus Torvalds 			hd->ioc->name, cmd));
30511da177e4SLinus Torvalds 	}
30521da177e4SLinus Torvalds 
30531da177e4SLinus Torvalds 	for (ii=0; ii < 16; ii++)
30541da177e4SLinus Torvalds 		pScsiReq->CDB[ii] = CDB[ii];
30551da177e4SLinus Torvalds 
30561da177e4SLinus Torvalds 	pScsiReq->DataLength = cpu_to_le32(io->size);
30571da177e4SLinus Torvalds 	pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
30581da177e4SLinus Torvalds 					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
30591da177e4SLinus Torvalds 
30601da177e4SLinus Torvalds 	ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3061793955f5SEric Moore 			hd->ioc->name, cmd, io->channel, io->id, io->lun));
30621da177e4SLinus Torvalds 
30631da177e4SLinus Torvalds 	if (dir == MPI_SCSIIO_CONTROL_READ) {
30641da177e4SLinus Torvalds 		mpt_add_sge((char *) &pScsiReq->SGL,
30651da177e4SLinus Torvalds 			MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
30661da177e4SLinus Torvalds 			io->data_dma);
30671da177e4SLinus Torvalds 	} else {
30681da177e4SLinus Torvalds 		mpt_add_sge((char *) &pScsiReq->SGL,
30691da177e4SLinus Torvalds 			MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
30701da177e4SLinus Torvalds 			io->data_dma);
30711da177e4SLinus Torvalds 	}
30721da177e4SLinus Torvalds 
30731da177e4SLinus Torvalds 	/* The ISR will free the request frame, but we need
30741da177e4SLinus Torvalds 	 * the information to initialize the target. Duplicate.
30751da177e4SLinus Torvalds 	 */
30761da177e4SLinus Torvalds 	memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
30771da177e4SLinus Torvalds 
30781da177e4SLinus Torvalds 	/* Issue this command after:
30791da177e4SLinus Torvalds 	 *	finish init
30801da177e4SLinus Torvalds 	 *	add timer
30811da177e4SLinus Torvalds 	 * Wait until the reply has been received
30821da177e4SLinus Torvalds 	 *  ScsiScanDvCtx callback function will
30831da177e4SLinus Torvalds 	 *	set hd->pLocal;
30841da177e4SLinus Torvalds 	 *	set scandv_wait_done and call wake_up
30851da177e4SLinus Torvalds 	 */
30861da177e4SLinus Torvalds 	hd->pLocal = NULL;
30871da177e4SLinus Torvalds 	hd->timer.expires = jiffies + HZ*cmdTimeout;
30880d0c7974SMoore, Eric Dean  	hd->scandv_wait_done = 0;
30891da177e4SLinus Torvalds 
30901da177e4SLinus Torvalds 	/* Save cmd pointer, for resource free if timeout or
30911da177e4SLinus Torvalds 	 * FW reload occurs
30921da177e4SLinus Torvalds 	 */
30931da177e4SLinus Torvalds 	hd->cmdPtr = mf;
30941da177e4SLinus Torvalds 
30951da177e4SLinus Torvalds 	add_timer(&hd->timer);
30960d0c7974SMoore, Eric Dean  	mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
30970d0c7974SMoore, Eric Dean  	wait_event(hd->scandv_waitq, hd->scandv_wait_done);
30981da177e4SLinus Torvalds 
30991da177e4SLinus Torvalds 	if (hd->pLocal) {
31001da177e4SLinus Torvalds 		rc = hd->pLocal->completion;
31011da177e4SLinus Torvalds 		hd->pLocal->skip = 0;
31021da177e4SLinus Torvalds 
31031da177e4SLinus Torvalds 		/* Always set fatal error codes in some cases.
31041da177e4SLinus Torvalds 		 */
31051da177e4SLinus Torvalds 		if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
31061da177e4SLinus Torvalds 			rc = -ENXIO;
31071da177e4SLinus Torvalds 		else if (rc == MPT_SCANDV_SOME_ERROR)
31081da177e4SLinus Torvalds 			rc =  -rc;
31091da177e4SLinus Torvalds 	} else {
31101da177e4SLinus Torvalds 		rc = -EFAULT;
31111da177e4SLinus Torvalds 		/* This should never happen. */
31121da177e4SLinus Torvalds 		ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
31131da177e4SLinus Torvalds 				hd->ioc->name));
31141da177e4SLinus Torvalds 	}
31151da177e4SLinus Torvalds 
31161da177e4SLinus Torvalds 	return rc;
31171da177e4SLinus Torvalds }
31181da177e4SLinus Torvalds 
31191da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
31201da177e4SLinus Torvalds /**
3121c7c82987SMoore, Eric Dean  *	mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3122c7c82987SMoore, Eric Dean  *	@hd: Pointer to a SCSI HOST structure
3123d9489fb6SRandy Dunlap  *	@vdevice: virtual target device
3124c7c82987SMoore, Eric Dean  *
3125c7c82987SMoore, Eric Dean  *	Uses the ISR, but with special processing.
3126c7c82987SMoore, Eric Dean  *	MUST be single-threaded.
3127c7c82987SMoore, Eric Dean  *
3128c7c82987SMoore, Eric Dean  */
3129c7c82987SMoore, Eric Dean static void
3130c7c82987SMoore, Eric Dean mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3131c7c82987SMoore, Eric Dean {
3132c7c82987SMoore, Eric Dean 	INTERNAL_CMD		 iocmd;
31331da177e4SLinus Torvalds 
31341da177e4SLinus Torvalds 	/* Following parameters will not change
31351da177e4SLinus Torvalds 	 * in this routine.
31361da177e4SLinus Torvalds 	 */
31371da177e4SLinus Torvalds 	iocmd.cmd = SYNCHRONIZE_CACHE;
31381da177e4SLinus Torvalds 	iocmd.flags = 0;
31391da177e4SLinus Torvalds 	iocmd.physDiskNum = -1;
31401da177e4SLinus Torvalds 	iocmd.data = NULL;
31411da177e4SLinus Torvalds 	iocmd.data_dma = -1;
31421da177e4SLinus Torvalds 	iocmd.size = 0;
31431da177e4SLinus Torvalds 	iocmd.rsvd = iocmd.rsvd2 = 0;
3144793955f5SEric Moore 	iocmd.channel = vdevice->vtarget->channel;
3145793955f5SEric Moore 	iocmd.id = vdevice->vtarget->id;
3146793955f5SEric Moore 	iocmd.lun = vdevice->lun;
31471da177e4SLinus Torvalds 
3148c92f222eSJames Bottomley 	if ((vdevice->vtarget->type == TYPE_DISK) &&
3149c7c82987SMoore, Eric Dean 	    (vdevice->configured_lun))
3150c7c82987SMoore, Eric Dean 		mptscsih_do_cmd(hd, &iocmd);
31511da177e4SLinus Torvalds }
31521da177e4SLinus Torvalds 
31530d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_remove);
31540d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_shutdown);
31550d0c7974SMoore, Eric Dean  #ifdef CONFIG_PM
31560d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_suspend);
31570d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_resume);
31580d0c7974SMoore, Eric Dean  #endif
31590d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_proc_info);
31600d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_info);
31610d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_qcmd);
31620d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_slave_destroy);
31630d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_slave_configure);
31640d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_abort);
31650d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_dev_reset);
31660d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_bus_reset);
31670d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_host_reset);
31680d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_bios_param);
31690d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_io_done);
31700d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
31710d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_scandv_complete);
31720d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_event_process);
31730d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_ioc_reset);
31746e3815baSMoore, Eric Dean EXPORT_SYMBOL(mptscsih_change_queue_depth);
31750d0c7974SMoore, Eric Dean  EXPORT_SYMBOL(mptscsih_timer_expired);
3176663e1aa1SJames Bottomley EXPORT_SYMBOL(mptscsih_TMHandler);
31771da177e4SLinus Torvalds 
31780d0c7974SMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3179