162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  linux/drivers/message/fusion/mptscsih.c
362306a36Sopenharmony_ci *      For use with LSI PCI chip/adapter(s)
462306a36Sopenharmony_ci *      running LSI Fusion MPT (Message Passing Technology) firmware.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Copyright (c) 1999-2008 LSI Corporation
762306a36Sopenharmony_ci *  (mailto:DL-MPTFusionLinux@lsi.com)
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci    This program is free software; you can redistribute it and/or modify
1362306a36Sopenharmony_ci    it under the terms of the GNU General Public License as published by
1462306a36Sopenharmony_ci    the Free Software Foundation; version 2 of the License.
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci    This program is distributed in the hope that it will be useful,
1762306a36Sopenharmony_ci    but WITHOUT ANY WARRANTY; without even the implied warranty of
1862306a36Sopenharmony_ci    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1962306a36Sopenharmony_ci    GNU General Public License for more details.
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci    NO WARRANTY
2262306a36Sopenharmony_ci    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
2362306a36Sopenharmony_ci    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
2462306a36Sopenharmony_ci    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
2562306a36Sopenharmony_ci    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
2662306a36Sopenharmony_ci    solely responsible for determining the appropriateness of using and
2762306a36Sopenharmony_ci    distributing the Program and assumes all risks associated with its
2862306a36Sopenharmony_ci    exercise of rights under this Agreement, including but not limited to
2962306a36Sopenharmony_ci    the risks and costs of program errors, damage to or loss of data,
3062306a36Sopenharmony_ci    programs or equipment, and unavailability or interruption of operations.
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci    DISCLAIMER OF LIABILITY
3362306a36Sopenharmony_ci    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
3462306a36Sopenharmony_ci    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3562306a36Sopenharmony_ci    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
3662306a36Sopenharmony_ci    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
3762306a36Sopenharmony_ci    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3862306a36Sopenharmony_ci    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
3962306a36Sopenharmony_ci    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci    You should have received a copy of the GNU General Public License
4262306a36Sopenharmony_ci    along with this program; if not, write to the Free Software
4362306a36Sopenharmony_ci    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
4462306a36Sopenharmony_ci*/
4562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#include <linux/module.h>
4862306a36Sopenharmony_ci#include <linux/kernel.h>
4962306a36Sopenharmony_ci#include <linux/slab.h>
5062306a36Sopenharmony_ci#include <linux/init.h>
5162306a36Sopenharmony_ci#include <linux/errno.h>
5262306a36Sopenharmony_ci#include <linux/kdev_t.h>
5362306a36Sopenharmony_ci#include <linux/blkdev.h>
5462306a36Sopenharmony_ci#include <linux/delay.h>	/* for mdelay */
5562306a36Sopenharmony_ci#include <linux/interrupt.h>
5662306a36Sopenharmony_ci#include <linux/reboot.h>	/* notifier code */
5762306a36Sopenharmony_ci#include <linux/workqueue.h>
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#include <scsi/scsi.h>
6062306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
6162306a36Sopenharmony_ci#include <scsi/scsi_device.h>
6262306a36Sopenharmony_ci#include <scsi/scsi_host.h>
6362306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
6462306a36Sopenharmony_ci#include <scsi/scsi_dbg.h>
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#include "mptbase.h"
6762306a36Sopenharmony_ci#include "mptscsih.h"
6862306a36Sopenharmony_ci#include "lsi/mpi_log_sas.h"
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7162306a36Sopenharmony_ci#define my_NAME		"Fusion MPT SCSI Host driver"
7262306a36Sopenharmony_ci#define my_VERSION	MPT_LINUX_VERSION_COMMON
7362306a36Sopenharmony_ci#define MYNAM		"mptscsih"
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ciMODULE_AUTHOR(MODULEAUTHOR);
7662306a36Sopenharmony_ciMODULE_DESCRIPTION(my_NAME);
7762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
7862306a36Sopenharmony_ciMODULE_VERSION(my_VERSION);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
8162306a36Sopenharmony_ci/*
8262306a36Sopenharmony_ci *  Other private/forward protos...
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_cistruct scsi_cmnd	*mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
8562306a36Sopenharmony_cistatic struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
8662306a36Sopenharmony_cistatic void	mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
8762306a36Sopenharmony_cistatic int	SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
8862306a36Sopenharmony_ciint		mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
8962306a36Sopenharmony_cistatic void	mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
9062306a36Sopenharmony_ciint		mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic int	mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
9362306a36Sopenharmony_ci				 SCSIIORequest_t *pReq, int req_idx);
9462306a36Sopenharmony_cistatic void	mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
9562306a36Sopenharmony_cistatic void	mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ciint	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
9862306a36Sopenharmony_ci		u64 lun, int ctx2abort, ulong timeout);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ciint		mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
10162306a36Sopenharmony_ciint		mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_civoid
10462306a36Sopenharmony_cimptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
10562306a36Sopenharmony_cistatic int	mptscsih_get_completion_code(MPT_ADAPTER *ioc,
10662306a36Sopenharmony_ci		MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
10762306a36Sopenharmony_ciint		mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
10862306a36Sopenharmony_cistatic int	mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
10962306a36Sopenharmony_cistatic void	mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int
11262306a36Sopenharmony_cimptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
11362306a36Sopenharmony_ci				SCSITaskMgmtReply_t *pScsiTmReply);
11462306a36Sopenharmony_civoid 		mptscsih_remove(struct pci_dev *);
11562306a36Sopenharmony_civoid 		mptscsih_shutdown(struct pci_dev *);
11662306a36Sopenharmony_ci#ifdef CONFIG_PM
11762306a36Sopenharmony_ciint 		mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
11862306a36Sopenharmony_ciint 		mptscsih_resume(struct pci_dev *pdev);
11962306a36Sopenharmony_ci#endif
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12362306a36Sopenharmony_ci/*
12462306a36Sopenharmony_ci *	mptscsih_getFreeChainBuffer - Function to get a free chain
12562306a36Sopenharmony_ci *	from the MPT_SCSI_HOST FreeChainQ.
12662306a36Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
12762306a36Sopenharmony_ci *	@req_idx: Index of the SCSI IO request frame. (output)
12862306a36Sopenharmony_ci *
12962306a36Sopenharmony_ci *	return SUCCESS or FAILED
13062306a36Sopenharmony_ci */
13162306a36Sopenharmony_cistatic inline int
13262306a36Sopenharmony_cimptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	MPT_FRAME_HDR *chainBuf;
13562306a36Sopenharmony_ci	unsigned long flags;
13662306a36Sopenharmony_ci	int rc;
13762306a36Sopenharmony_ci	int chain_idx;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
14062306a36Sopenharmony_ci	    ioc->name));
14162306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->FreeQlock, flags);
14262306a36Sopenharmony_ci	if (!list_empty(&ioc->FreeChainQ)) {
14362306a36Sopenharmony_ci		int offset;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci		chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
14662306a36Sopenharmony_ci				u.frame.linkage.list);
14762306a36Sopenharmony_ci		list_del(&chainBuf->u.frame.linkage.list);
14862306a36Sopenharmony_ci		offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
14962306a36Sopenharmony_ci		chain_idx = offset / ioc->req_sz;
15062306a36Sopenharmony_ci		rc = SUCCESS;
15162306a36Sopenharmony_ci		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
15262306a36Sopenharmony_ci		    "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
15362306a36Sopenharmony_ci		    ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
15462306a36Sopenharmony_ci	} else {
15562306a36Sopenharmony_ci		rc = FAILED;
15662306a36Sopenharmony_ci		chain_idx = MPT_HOST_NO_CHAIN;
15762306a36Sopenharmony_ci		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
15862306a36Sopenharmony_ci		    ioc->name));
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	*retIndex = chain_idx;
16362306a36Sopenharmony_ci	return rc;
16462306a36Sopenharmony_ci} /* mptscsih_getFreeChainBuffer() */
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
16762306a36Sopenharmony_ci/*
16862306a36Sopenharmony_ci *	mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
16962306a36Sopenharmony_ci *	SCSIIORequest_t Message Frame.
17062306a36Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
17162306a36Sopenharmony_ci *	@SCpnt: Pointer to scsi_cmnd structure
17262306a36Sopenharmony_ci *	@pReq: Pointer to SCSIIORequest_t structure
17362306a36Sopenharmony_ci *
17462306a36Sopenharmony_ci *	Returns ...
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_cistatic int
17762306a36Sopenharmony_cimptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
17862306a36Sopenharmony_ci		SCSIIORequest_t *pReq, int req_idx)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	char 	*psge;
18162306a36Sopenharmony_ci	char	*chainSge;
18262306a36Sopenharmony_ci	struct scatterlist *sg;
18362306a36Sopenharmony_ci	int	 frm_sz;
18462306a36Sopenharmony_ci	int	 sges_left, sg_done;
18562306a36Sopenharmony_ci	int	 chain_idx = MPT_HOST_NO_CHAIN;
18662306a36Sopenharmony_ci	int	 sgeOffset;
18762306a36Sopenharmony_ci	int	 numSgeSlots, numSgeThisFrame;
18862306a36Sopenharmony_ci	u32	 sgflags, sgdir, thisxfer = 0;
18962306a36Sopenharmony_ci	int	 chain_dma_off = 0;
19062306a36Sopenharmony_ci	int	 newIndex;
19162306a36Sopenharmony_ci	int	 ii;
19262306a36Sopenharmony_ci	dma_addr_t v2;
19362306a36Sopenharmony_ci	u32	RequestNB;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
19662306a36Sopenharmony_ci	if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {
19762306a36Sopenharmony_ci		sgdir = MPT_TRANSFER_HOST_TO_IOC;
19862306a36Sopenharmony_ci	} else {
19962306a36Sopenharmony_ci		sgdir = MPT_TRANSFER_IOC_TO_HOST;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	psge = (char *) &pReq->SGL;
20362306a36Sopenharmony_ci	frm_sz = ioc->req_sz;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/* Map the data portion, if any.
20662306a36Sopenharmony_ci	 * sges_left  = 0 if no data transfer.
20762306a36Sopenharmony_ci	 */
20862306a36Sopenharmony_ci	sges_left = scsi_dma_map(SCpnt);
20962306a36Sopenharmony_ci	if (sges_left < 0)
21062306a36Sopenharmony_ci		return FAILED;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* Handle the SG case.
21362306a36Sopenharmony_ci	 */
21462306a36Sopenharmony_ci	sg = scsi_sglist(SCpnt);
21562306a36Sopenharmony_ci	sg_done  = 0;
21662306a36Sopenharmony_ci	sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
21762306a36Sopenharmony_ci	chainSge = NULL;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* Prior to entering this loop - the following must be set
22062306a36Sopenharmony_ci	 * current MF:  sgeOffset (bytes)
22162306a36Sopenharmony_ci	 *              chainSge (Null if original MF is not a chain buffer)
22262306a36Sopenharmony_ci	 *              sg_done (num SGE done for this MF)
22362306a36Sopenharmony_ci	 */
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cinextSGEset:
22662306a36Sopenharmony_ci	numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
22762306a36Sopenharmony_ci	numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/* Get first (num - 1) SG elements
23262306a36Sopenharmony_ci	 * Skip any SG entries with a length of 0
23362306a36Sopenharmony_ci	 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
23462306a36Sopenharmony_ci	 */
23562306a36Sopenharmony_ci	for (ii=0; ii < (numSgeThisFrame-1); ii++) {
23662306a36Sopenharmony_ci		thisxfer = sg_dma_len(sg);
23762306a36Sopenharmony_ci		if (thisxfer == 0) {
23862306a36Sopenharmony_ci			/* Get next SG element from the OS */
23962306a36Sopenharmony_ci			sg = sg_next(sg);
24062306a36Sopenharmony_ci			sg_done++;
24162306a36Sopenharmony_ci			continue;
24262306a36Sopenharmony_ci		}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci		v2 = sg_dma_address(sg);
24562306a36Sopenharmony_ci		ioc->add_sge(psge, sgflags | thisxfer, v2);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci		/* Get next SG element from the OS */
24862306a36Sopenharmony_ci		sg = sg_next(sg);
24962306a36Sopenharmony_ci		psge += ioc->SGE_size;
25062306a36Sopenharmony_ci		sgeOffset += ioc->SGE_size;
25162306a36Sopenharmony_ci		sg_done++;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (numSgeThisFrame == sges_left) {
25562306a36Sopenharmony_ci		/* Add last element, end of buffer and end of list flags.
25662306a36Sopenharmony_ci		 */
25762306a36Sopenharmony_ci		sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
25862306a36Sopenharmony_ci				MPT_SGE_FLAGS_END_OF_BUFFER |
25962306a36Sopenharmony_ci				MPT_SGE_FLAGS_END_OF_LIST;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		/* Add last SGE and set termination flags.
26262306a36Sopenharmony_ci		 * Note: Last SGE may have a length of 0 - which should be ok.
26362306a36Sopenharmony_ci		 */
26462306a36Sopenharmony_ci		thisxfer = sg_dma_len(sg);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		v2 = sg_dma_address(sg);
26762306a36Sopenharmony_ci		ioc->add_sge(psge, sgflags | thisxfer, v2);
26862306a36Sopenharmony_ci		sgeOffset += ioc->SGE_size;
26962306a36Sopenharmony_ci		sg_done++;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci		if (chainSge) {
27262306a36Sopenharmony_ci			/* The current buffer is a chain buffer,
27362306a36Sopenharmony_ci			 * but there is not another one.
27462306a36Sopenharmony_ci			 * Update the chain element
27562306a36Sopenharmony_ci			 * Offset and Length fields.
27662306a36Sopenharmony_ci			 */
27762306a36Sopenharmony_ci			ioc->add_chain((char *)chainSge, 0, sgeOffset,
27862306a36Sopenharmony_ci				ioc->ChainBufferDMA + chain_dma_off);
27962306a36Sopenharmony_ci		} else {
28062306a36Sopenharmony_ci			/* The current buffer is the original MF
28162306a36Sopenharmony_ci			 * and there is no Chain buffer.
28262306a36Sopenharmony_ci			 */
28362306a36Sopenharmony_ci			pReq->ChainOffset = 0;
28462306a36Sopenharmony_ci			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;
28562306a36Sopenharmony_ci			dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
28662306a36Sopenharmony_ci			    "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
28762306a36Sopenharmony_ci			ioc->RequestNB[req_idx] = RequestNB;
28862306a36Sopenharmony_ci		}
28962306a36Sopenharmony_ci	} else {
29062306a36Sopenharmony_ci		/* At least one chain buffer is needed.
29162306a36Sopenharmony_ci		 * Complete the first MF
29262306a36Sopenharmony_ci		 *  - last SGE element, set the LastElement bit
29362306a36Sopenharmony_ci		 *  - set ChainOffset (words) for orig MF
29462306a36Sopenharmony_ci		 *             (OR finish previous MF chain buffer)
29562306a36Sopenharmony_ci		 *  - update MFStructPtr ChainIndex
29662306a36Sopenharmony_ci		 *  - Populate chain element
29762306a36Sopenharmony_ci		 * Also
29862306a36Sopenharmony_ci		 * Loop until done.
29962306a36Sopenharmony_ci		 */
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
30262306a36Sopenharmony_ci				ioc->name, sg_done));
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		/* Set LAST_ELEMENT flag for last non-chain element
30562306a36Sopenharmony_ci		 * in the buffer. Since psge points at the NEXT
30662306a36Sopenharmony_ci		 * SGE element, go back one SGE element, update the flags
30762306a36Sopenharmony_ci		 * and reset the pointer. (Note: sgflags & thisxfer are already
30862306a36Sopenharmony_ci		 * set properly).
30962306a36Sopenharmony_ci		 */
31062306a36Sopenharmony_ci		if (sg_done) {
31162306a36Sopenharmony_ci			u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
31262306a36Sopenharmony_ci			sgflags = le32_to_cpu(*ptmp);
31362306a36Sopenharmony_ci			sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
31462306a36Sopenharmony_ci			*ptmp = cpu_to_le32(sgflags);
31562306a36Sopenharmony_ci		}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		if (chainSge) {
31862306a36Sopenharmony_ci			/* The current buffer is a chain buffer.
31962306a36Sopenharmony_ci			 * chainSge points to the previous Chain Element.
32062306a36Sopenharmony_ci			 * Update its chain element Offset and Length (must
32162306a36Sopenharmony_ci			 * include chain element size) fields.
32262306a36Sopenharmony_ci			 * Old chain element is now complete.
32362306a36Sopenharmony_ci			 */
32462306a36Sopenharmony_ci			u8 nextChain = (u8) (sgeOffset >> 2);
32562306a36Sopenharmony_ci			sgeOffset += ioc->SGE_size;
32662306a36Sopenharmony_ci			ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
32762306a36Sopenharmony_ci					 ioc->ChainBufferDMA + chain_dma_off);
32862306a36Sopenharmony_ci		} else {
32962306a36Sopenharmony_ci			/* The original MF buffer requires a chain buffer -
33062306a36Sopenharmony_ci			 * set the offset.
33162306a36Sopenharmony_ci			 * Last element in this MF is a chain element.
33262306a36Sopenharmony_ci			 */
33362306a36Sopenharmony_ci			pReq->ChainOffset = (u8) (sgeOffset >> 2);
33462306a36Sopenharmony_ci			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;
33562306a36Sopenharmony_ci			dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
33662306a36Sopenharmony_ci			ioc->RequestNB[req_idx] = RequestNB;
33762306a36Sopenharmony_ci		}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		sges_left -= sg_done;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		/* NOTE: psge points to the beginning of the chain element
34362306a36Sopenharmony_ci		 * in current buffer. Get a chain buffer.
34462306a36Sopenharmony_ci		 */
34562306a36Sopenharmony_ci		if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
34662306a36Sopenharmony_ci			dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
34762306a36Sopenharmony_ci			    "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
34862306a36Sopenharmony_ci 			    ioc->name, pReq->CDB[0], SCpnt));
34962306a36Sopenharmony_ci			return FAILED;
35062306a36Sopenharmony_ci		}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci		/* Update the tracking arrays.
35362306a36Sopenharmony_ci		 * If chainSge == NULL, update ReqToChain, else ChainToChain
35462306a36Sopenharmony_ci		 */
35562306a36Sopenharmony_ci		if (chainSge) {
35662306a36Sopenharmony_ci			ioc->ChainToChain[chain_idx] = newIndex;
35762306a36Sopenharmony_ci		} else {
35862306a36Sopenharmony_ci			ioc->ReqToChain[req_idx] = newIndex;
35962306a36Sopenharmony_ci		}
36062306a36Sopenharmony_ci		chain_idx = newIndex;
36162306a36Sopenharmony_ci		chain_dma_off = ioc->req_sz * chain_idx;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		/* Populate the chainSGE for the current buffer.
36462306a36Sopenharmony_ci		 * - Set chain buffer pointer to psge and fill
36562306a36Sopenharmony_ci		 *   out the Address and Flags fields.
36662306a36Sopenharmony_ci		 */
36762306a36Sopenharmony_ci		chainSge = (char *) psge;
36862306a36Sopenharmony_ci		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Current buff @ %p (index 0x%x)",
36962306a36Sopenharmony_ci		    ioc->name, psge, req_idx));
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		/* Start the SGE for the next buffer
37262306a36Sopenharmony_ci		 */
37362306a36Sopenharmony_ci		psge = (char *) (ioc->ChainBuffer + chain_dma_off);
37462306a36Sopenharmony_ci		sgeOffset = 0;
37562306a36Sopenharmony_ci		sg_done = 0;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Chain buff @ %p (index 0x%x)\n",
37862306a36Sopenharmony_ci		    ioc->name, psge, chain_idx));
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		/* Start the SGE for the next buffer
38162306a36Sopenharmony_ci		 */
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		goto nextSGEset;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	return SUCCESS;
38762306a36Sopenharmony_ci} /* mptscsih_AddSGE() */
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic void
39062306a36Sopenharmony_cimptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
39162306a36Sopenharmony_ci    U32 SlotStatus)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	MPT_FRAME_HDR *mf;
39462306a36Sopenharmony_ci	SEPRequest_t 	 *SEPMsg;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (ioc->bus_type != SAS)
39762306a36Sopenharmony_ci		return;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Not supported for hidden raid components
40062306a36Sopenharmony_ci	 */
40162306a36Sopenharmony_ci	if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
40262306a36Sopenharmony_ci		return;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
40562306a36Sopenharmony_ci		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
40662306a36Sopenharmony_ci		    ioc->name,__func__));
40762306a36Sopenharmony_ci		return;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	SEPMsg = (SEPRequest_t *)mf;
41162306a36Sopenharmony_ci	SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
41262306a36Sopenharmony_ci	SEPMsg->Bus = vtarget->channel;
41362306a36Sopenharmony_ci	SEPMsg->TargetID = vtarget->id;
41462306a36Sopenharmony_ci	SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
41562306a36Sopenharmony_ci	SEPMsg->SlotStatus = SlotStatus;
41662306a36Sopenharmony_ci	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
41762306a36Sopenharmony_ci	    "Sending SEP cmd=%x channel=%d id=%d\n",
41862306a36Sopenharmony_ci	    ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
41962306a36Sopenharmony_ci	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci#ifdef CONFIG_FUSION_LOGGING
42362306a36Sopenharmony_ci/**
42462306a36Sopenharmony_ci *	mptscsih_info_scsiio - debug print info on reply frame
42562306a36Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
42662306a36Sopenharmony_ci *	@sc: original scsi cmnd pointer
42762306a36Sopenharmony_ci *	@pScsiReply: Pointer to MPT reply frame
42862306a36Sopenharmony_ci *
42962306a36Sopenharmony_ci *	MPT_DEBUG_REPLY needs to be enabled to obtain this info
43062306a36Sopenharmony_ci *
43162306a36Sopenharmony_ci *	Refer to lsi/mpi.h.
43262306a36Sopenharmony_ci **/
43362306a36Sopenharmony_cistatic void
43462306a36Sopenharmony_cimptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	char	*desc = NULL;
43762306a36Sopenharmony_ci	char	*desc1 = NULL;
43862306a36Sopenharmony_ci	u16	ioc_status;
43962306a36Sopenharmony_ci	u8	skey, asc, ascq;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	switch (ioc_status) {
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	case MPI_IOCSTATUS_SUCCESS:
44662306a36Sopenharmony_ci		desc = "success";
44762306a36Sopenharmony_ci		break;
44862306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_INVALID_BUS:
44962306a36Sopenharmony_ci		desc = "invalid bus";
45062306a36Sopenharmony_ci		break;
45162306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
45262306a36Sopenharmony_ci		desc = "invalid target_id";
45362306a36Sopenharmony_ci		break;
45462306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
45562306a36Sopenharmony_ci		desc = "device not there";
45662306a36Sopenharmony_ci		break;
45762306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
45862306a36Sopenharmony_ci		desc = "data overrun";
45962306a36Sopenharmony_ci		break;
46062306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
46162306a36Sopenharmony_ci		desc = "data underrun";
46262306a36Sopenharmony_ci		break;
46362306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
46462306a36Sopenharmony_ci		desc = "I/O data error";
46562306a36Sopenharmony_ci		break;
46662306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
46762306a36Sopenharmony_ci		desc = "protocol error";
46862306a36Sopenharmony_ci		break;
46962306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
47062306a36Sopenharmony_ci		desc = "task terminated";
47162306a36Sopenharmony_ci		break;
47262306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
47362306a36Sopenharmony_ci		desc = "residual mismatch";
47462306a36Sopenharmony_ci		break;
47562306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
47662306a36Sopenharmony_ci		desc = "task management failed";
47762306a36Sopenharmony_ci		break;
47862306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
47962306a36Sopenharmony_ci		desc = "IOC terminated";
48062306a36Sopenharmony_ci		break;
48162306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
48262306a36Sopenharmony_ci		desc = "ext terminated";
48362306a36Sopenharmony_ci		break;
48462306a36Sopenharmony_ci	default:
48562306a36Sopenharmony_ci		desc = "";
48662306a36Sopenharmony_ci		break;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	switch (pScsiReply->SCSIStatus)
49062306a36Sopenharmony_ci	{
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	case MPI_SCSI_STATUS_SUCCESS:
49362306a36Sopenharmony_ci		desc1 = "success";
49462306a36Sopenharmony_ci		break;
49562306a36Sopenharmony_ci	case MPI_SCSI_STATUS_CHECK_CONDITION:
49662306a36Sopenharmony_ci		desc1 = "check condition";
49762306a36Sopenharmony_ci		break;
49862306a36Sopenharmony_ci	case MPI_SCSI_STATUS_CONDITION_MET:
49962306a36Sopenharmony_ci		desc1 = "condition met";
50062306a36Sopenharmony_ci		break;
50162306a36Sopenharmony_ci	case MPI_SCSI_STATUS_BUSY:
50262306a36Sopenharmony_ci		desc1 = "busy";
50362306a36Sopenharmony_ci		break;
50462306a36Sopenharmony_ci	case MPI_SCSI_STATUS_INTERMEDIATE:
50562306a36Sopenharmony_ci		desc1 = "intermediate";
50662306a36Sopenharmony_ci		break;
50762306a36Sopenharmony_ci	case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
50862306a36Sopenharmony_ci		desc1 = "intermediate condmet";
50962306a36Sopenharmony_ci		break;
51062306a36Sopenharmony_ci	case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
51162306a36Sopenharmony_ci		desc1 = "reservation conflict";
51262306a36Sopenharmony_ci		break;
51362306a36Sopenharmony_ci	case MPI_SCSI_STATUS_COMMAND_TERMINATED:
51462306a36Sopenharmony_ci		desc1 = "command terminated";
51562306a36Sopenharmony_ci		break;
51662306a36Sopenharmony_ci	case MPI_SCSI_STATUS_TASK_SET_FULL:
51762306a36Sopenharmony_ci		desc1 = "task set full";
51862306a36Sopenharmony_ci		break;
51962306a36Sopenharmony_ci	case MPI_SCSI_STATUS_ACA_ACTIVE:
52062306a36Sopenharmony_ci		desc1 = "aca active";
52162306a36Sopenharmony_ci		break;
52262306a36Sopenharmony_ci	case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
52362306a36Sopenharmony_ci		desc1 = "fcpext device logged out";
52462306a36Sopenharmony_ci		break;
52562306a36Sopenharmony_ci	case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
52662306a36Sopenharmony_ci		desc1 = "fcpext no link";
52762306a36Sopenharmony_ci		break;
52862306a36Sopenharmony_ci	case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
52962306a36Sopenharmony_ci		desc1 = "fcpext unassigned";
53062306a36Sopenharmony_ci		break;
53162306a36Sopenharmony_ci	default:
53262306a36Sopenharmony_ci		desc1 = "";
53362306a36Sopenharmony_ci		break;
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	scsi_print_command(sc);
53762306a36Sopenharmony_ci	printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %llu\n",
53862306a36Sopenharmony_ci	    ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
53962306a36Sopenharmony_ci	printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
54062306a36Sopenharmony_ci	    "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
54162306a36Sopenharmony_ci	    scsi_get_resid(sc));
54262306a36Sopenharmony_ci	printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
54362306a36Sopenharmony_ci	    "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
54462306a36Sopenharmony_ci	    le32_to_cpu(pScsiReply->TransferCount), sc->result);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
54762306a36Sopenharmony_ci	    "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
54862306a36Sopenharmony_ci	    ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
54962306a36Sopenharmony_ci	    pScsiReply->SCSIState);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
55262306a36Sopenharmony_ci		skey = sc->sense_buffer[2] & 0x0F;
55362306a36Sopenharmony_ci		asc = sc->sense_buffer[12];
55462306a36Sopenharmony_ci		ascq = sc->sense_buffer[13];
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
55762306a36Sopenharmony_ci		    "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	/*
56162306a36Sopenharmony_ci	 *  Look for + dump FCP ResponseInfo[]!
56262306a36Sopenharmony_ci	 */
56362306a36Sopenharmony_ci	if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
56462306a36Sopenharmony_ci	    pScsiReply->ResponseInfo)
56562306a36Sopenharmony_ci		printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
56662306a36Sopenharmony_ci		    ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci#endif
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
57162306a36Sopenharmony_ci/*
57262306a36Sopenharmony_ci *	mptscsih_io_done - Main SCSI IO callback routine registered to
57362306a36Sopenharmony_ci *	Fusion MPT (base) driver
57462306a36Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
57562306a36Sopenharmony_ci *	@mf: Pointer to original MPT request frame
57662306a36Sopenharmony_ci *	@r: Pointer to MPT reply frame (NULL if TurboReply)
57762306a36Sopenharmony_ci *
57862306a36Sopenharmony_ci *	This routine is called from mpt.c::mpt_interrupt() at the completion
57962306a36Sopenharmony_ci *	of any SCSI IO request.
58062306a36Sopenharmony_ci *	This routine is registered with the Fusion MPT (base) driver at driver
58162306a36Sopenharmony_ci *	load/init time via the mpt_register() API call.
58262306a36Sopenharmony_ci *
58362306a36Sopenharmony_ci *	Returns 1 indicating alloc'd request frame ptr should be freed.
58462306a36Sopenharmony_ci */
58562306a36Sopenharmony_ciint
58662306a36Sopenharmony_cimptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct scsi_cmnd	*sc;
58962306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd;
59062306a36Sopenharmony_ci	SCSIIORequest_t	*pScsiReq;
59162306a36Sopenharmony_ci	SCSIIOReply_t	*pScsiReply;
59262306a36Sopenharmony_ci	u16		 req_idx, req_idx_MR;
59362306a36Sopenharmony_ci	VirtDevice	 *vdevice;
59462306a36Sopenharmony_ci	VirtTarget	 *vtarget;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	hd = shost_priv(ioc->sh);
59762306a36Sopenharmony_ci	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
59862306a36Sopenharmony_ci	req_idx_MR = (mr != NULL) ?
59962306a36Sopenharmony_ci	    le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* Special case, where already freed message frame is received from
60262306a36Sopenharmony_ci	 * Firmware. It happens with Resetting IOC.
60362306a36Sopenharmony_ci	 * Return immediately. Do not care
60462306a36Sopenharmony_ci	 */
60562306a36Sopenharmony_ci	if ((req_idx != req_idx_MR) ||
60662306a36Sopenharmony_ci	    (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))
60762306a36Sopenharmony_ci		return 0;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
61062306a36Sopenharmony_ci	if (sc == NULL) {
61162306a36Sopenharmony_ci		MPIHeader_t *hdr = (MPIHeader_t *)mf;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci		/* Remark: writeSDP1 will use the ScsiDoneCtx
61462306a36Sopenharmony_ci		 * If a SCSI I/O cmd, device disabled by OS and
61562306a36Sopenharmony_ci		 * completion done. Cannot touch sc struct. Just free mem.
61662306a36Sopenharmony_ci		 */
61762306a36Sopenharmony_ci		if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
61862306a36Sopenharmony_ci			printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
61962306a36Sopenharmony_ci			ioc->name);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		mptscsih_freeChainBuffers(ioc, req_idx);
62262306a36Sopenharmony_ci		return 1;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if ((unsigned char *)mf != sc->host_scribble) {
62662306a36Sopenharmony_ci		mptscsih_freeChainBuffers(ioc, req_idx);
62762306a36Sopenharmony_ci		return 1;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (ioc->bus_type == SAS) {
63162306a36Sopenharmony_ci		VirtDevice *vdevice = sc->device->hostdata;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci		if (!vdevice || !vdevice->vtarget ||
63462306a36Sopenharmony_ci		    vdevice->vtarget->deleted) {
63562306a36Sopenharmony_ci			sc->result = DID_NO_CONNECT << 16;
63662306a36Sopenharmony_ci			goto out;
63762306a36Sopenharmony_ci		}
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	sc->host_scribble = NULL;
64162306a36Sopenharmony_ci	sc->result = DID_OK << 16;		/* Set default reply as OK */
64262306a36Sopenharmony_ci	pScsiReq = (SCSIIORequest_t *) mf;
64362306a36Sopenharmony_ci	pScsiReply = (SCSIIOReply_t *) mr;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
64662306a36Sopenharmony_ci		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
64762306a36Sopenharmony_ci			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
64862306a36Sopenharmony_ci			ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
64962306a36Sopenharmony_ci	}else{
65062306a36Sopenharmony_ci		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
65162306a36Sopenharmony_ci			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
65262306a36Sopenharmony_ci			ioc->name, mf, mr, sc, req_idx));
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (pScsiReply == NULL) {
65662306a36Sopenharmony_ci		/* special context reply handling */
65762306a36Sopenharmony_ci		;
65862306a36Sopenharmony_ci	} else {
65962306a36Sopenharmony_ci		u32	 xfer_cnt;
66062306a36Sopenharmony_ci		u16	 status;
66162306a36Sopenharmony_ci		u8	 scsi_state, scsi_status;
66262306a36Sopenharmony_ci		u32	 log_info;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		scsi_state = pScsiReply->SCSIState;
66762306a36Sopenharmony_ci		scsi_status = pScsiReply->SCSIStatus;
66862306a36Sopenharmony_ci		xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
66962306a36Sopenharmony_ci		scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
67062306a36Sopenharmony_ci		log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci		/*
67362306a36Sopenharmony_ci		 *  if we get a data underrun indication, yet no data was
67462306a36Sopenharmony_ci		 *  transferred and the SCSI status indicates that the
67562306a36Sopenharmony_ci		 *  command was never started, change the data underrun
67662306a36Sopenharmony_ci		 *  to success
67762306a36Sopenharmony_ci		 */
67862306a36Sopenharmony_ci		if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
67962306a36Sopenharmony_ci		    (scsi_status == MPI_SCSI_STATUS_BUSY ||
68062306a36Sopenharmony_ci		     scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
68162306a36Sopenharmony_ci		     scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
68262306a36Sopenharmony_ci			status = MPI_IOCSTATUS_SUCCESS;
68362306a36Sopenharmony_ci		}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
68662306a36Sopenharmony_ci			mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		/*
68962306a36Sopenharmony_ci		 *  Look for + dump FCP ResponseInfo[]!
69062306a36Sopenharmony_ci		 */
69162306a36Sopenharmony_ci		if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
69262306a36Sopenharmony_ci		    pScsiReply->ResponseInfo) {
69362306a36Sopenharmony_ci			printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%llu] "
69462306a36Sopenharmony_ci			"FCP_ResponseInfo=%08xh\n", ioc->name,
69562306a36Sopenharmony_ci			sc->device->host->host_no, sc->device->channel,
69662306a36Sopenharmony_ci			sc->device->id, sc->device->lun,
69762306a36Sopenharmony_ci			le32_to_cpu(pScsiReply->ResponseInfo));
69862306a36Sopenharmony_ci		}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci		switch(status) {
70162306a36Sopenharmony_ci		case MPI_IOCSTATUS_BUSY:			/* 0x0002 */
70262306a36Sopenharmony_ci		case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:	/* 0x0006 */
70362306a36Sopenharmony_ci			/* CHECKME!
70462306a36Sopenharmony_ci			 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
70562306a36Sopenharmony_ci			 * But not: DID_BUS_BUSY lest one risk
70662306a36Sopenharmony_ci			 * killing interrupt handler:-(
70762306a36Sopenharmony_ci			 */
70862306a36Sopenharmony_ci			sc->result = SAM_STAT_BUSY;
70962306a36Sopenharmony_ci			break;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_INVALID_BUS:		/* 0x0041 */
71262306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:	/* 0x0042 */
71362306a36Sopenharmony_ci			sc->result = DID_BAD_TARGET << 16;
71462306a36Sopenharmony_ci			break;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
71762306a36Sopenharmony_ci			/* Spoof to SCSI Selection Timeout! */
71862306a36Sopenharmony_ci			if (ioc->bus_type != FC)
71962306a36Sopenharmony_ci				sc->result = DID_NO_CONNECT << 16;
72062306a36Sopenharmony_ci			/* else fibre, just stall until rescan event */
72162306a36Sopenharmony_ci			else
72262306a36Sopenharmony_ci				sc->result = DID_REQUEUE << 16;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci			if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
72562306a36Sopenharmony_ci				hd->sel_timeout[pScsiReq->TargetID]++;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci			vdevice = sc->device->hostdata;
72862306a36Sopenharmony_ci			if (!vdevice)
72962306a36Sopenharmony_ci				break;
73062306a36Sopenharmony_ci			vtarget = vdevice->vtarget;
73162306a36Sopenharmony_ci			if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
73262306a36Sopenharmony_ci				mptscsih_issue_sep_command(ioc, vtarget,
73362306a36Sopenharmony_ci				    MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
73462306a36Sopenharmony_ci				vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
73562306a36Sopenharmony_ci			}
73662306a36Sopenharmony_ci			break;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
73962306a36Sopenharmony_ci			if ( ioc->bus_type == SAS ) {
74062306a36Sopenharmony_ci				u16 ioc_status =
74162306a36Sopenharmony_ci				    le16_to_cpu(pScsiReply->IOCStatus);
74262306a36Sopenharmony_ci				if ((ioc_status &
74362306a36Sopenharmony_ci					MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
74462306a36Sopenharmony_ci					&&
74562306a36Sopenharmony_ci					((log_info & SAS_LOGINFO_MASK) ==
74662306a36Sopenharmony_ci					SAS_LOGINFO_NEXUS_LOSS)) {
74762306a36Sopenharmony_ci						VirtDevice *vdevice =
74862306a36Sopenharmony_ci						sc->device->hostdata;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci					    /* flag the device as being in
75162306a36Sopenharmony_ci					     * device removal delay so we can
75262306a36Sopenharmony_ci					     * notify the midlayer to hold off
75362306a36Sopenharmony_ci					     * on timeout eh */
75462306a36Sopenharmony_ci						if (vdevice && vdevice->
75562306a36Sopenharmony_ci							vtarget &&
75662306a36Sopenharmony_ci							vdevice->vtarget->
75762306a36Sopenharmony_ci							raidVolume)
75862306a36Sopenharmony_ci							printk(KERN_INFO
75962306a36Sopenharmony_ci							"Skipping Raid Volume"
76062306a36Sopenharmony_ci							"for inDMD\n");
76162306a36Sopenharmony_ci						else if (vdevice &&
76262306a36Sopenharmony_ci							vdevice->vtarget)
76362306a36Sopenharmony_ci							vdevice->vtarget->
76462306a36Sopenharmony_ci								inDMD = 1;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci					    sc->result =
76762306a36Sopenharmony_ci						    (DID_TRANSPORT_DISRUPTED
76862306a36Sopenharmony_ci						    << 16);
76962306a36Sopenharmony_ci					    break;
77062306a36Sopenharmony_ci				}
77162306a36Sopenharmony_ci			} else if (ioc->bus_type == FC) {
77262306a36Sopenharmony_ci				/*
77362306a36Sopenharmony_ci				 * The FC IOC may kill a request for variety of
77462306a36Sopenharmony_ci				 * reasons, some of which may be recovered by a
77562306a36Sopenharmony_ci				 * retry, some which are unlikely to be
77662306a36Sopenharmony_ci				 * recovered. Return DID_ERROR instead of
77762306a36Sopenharmony_ci				 * DID_RESET to permit retry of the command,
77862306a36Sopenharmony_ci				 * just not an infinite number of them
77962306a36Sopenharmony_ci				 */
78062306a36Sopenharmony_ci				sc->result = DID_ERROR << 16;
78162306a36Sopenharmony_ci				break;
78262306a36Sopenharmony_ci			}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci			/*
78562306a36Sopenharmony_ci			 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
78662306a36Sopenharmony_ci			 */
78762306a36Sopenharmony_ci			fallthrough;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
79062306a36Sopenharmony_ci			/* Linux handles an unsolicited DID_RESET better
79162306a36Sopenharmony_ci			 * than an unsolicited DID_ABORT.
79262306a36Sopenharmony_ci			 */
79362306a36Sopenharmony_ci			sc->result = DID_RESET << 16;
79462306a36Sopenharmony_ci			break;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
79762306a36Sopenharmony_ci			if (ioc->bus_type == FC)
79862306a36Sopenharmony_ci				sc->result = DID_ERROR << 16;
79962306a36Sopenharmony_ci			else
80062306a36Sopenharmony_ci				sc->result = DID_RESET << 16;
80162306a36Sopenharmony_ci			break;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
80462306a36Sopenharmony_ci			scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
80562306a36Sopenharmony_ci			if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
80662306a36Sopenharmony_ci				sc->result=DID_SOFT_ERROR << 16;
80762306a36Sopenharmony_ci			else /* Sufficient data transfer occurred */
80862306a36Sopenharmony_ci				sc->result = (DID_OK << 16) | scsi_status;
80962306a36Sopenharmony_ci			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
81062306a36Sopenharmony_ci			    "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
81162306a36Sopenharmony_ci			    ioc->name, sc->result, sc->device->channel, sc->device->id));
81262306a36Sopenharmony_ci			break;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
81562306a36Sopenharmony_ci			/*
81662306a36Sopenharmony_ci			 *  Do upfront check for valid SenseData and give it
81762306a36Sopenharmony_ci			 *  precedence!
81862306a36Sopenharmony_ci			 */
81962306a36Sopenharmony_ci			sc->result = (DID_OK << 16) | scsi_status;
82062306a36Sopenharmony_ci			if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci				/*
82362306a36Sopenharmony_ci				 * For an Errata on LSI53C1030
82462306a36Sopenharmony_ci				 * When the length of request data
82562306a36Sopenharmony_ci				 * and transfer data are different
82662306a36Sopenharmony_ci				 * with result of command (READ or VERIFY),
82762306a36Sopenharmony_ci				 * DID_SOFT_ERROR is set.
82862306a36Sopenharmony_ci				 */
82962306a36Sopenharmony_ci				if (ioc->bus_type == SPI) {
83062306a36Sopenharmony_ci					if ((pScsiReq->CDB[0] == READ_6  && ((pScsiReq->CDB[1] & 0x02) == 0)) ||
83162306a36Sopenharmony_ci					    pScsiReq->CDB[0] == READ_10 ||
83262306a36Sopenharmony_ci					    pScsiReq->CDB[0] == READ_12 ||
83362306a36Sopenharmony_ci						(pScsiReq->CDB[0] == READ_16 &&
83462306a36Sopenharmony_ci						((pScsiReq->CDB[1] & 0x02) == 0)) ||
83562306a36Sopenharmony_ci					    pScsiReq->CDB[0] == VERIFY  ||
83662306a36Sopenharmony_ci					    pScsiReq->CDB[0] == VERIFY_16) {
83762306a36Sopenharmony_ci						if (scsi_bufflen(sc) !=
83862306a36Sopenharmony_ci							xfer_cnt) {
83962306a36Sopenharmony_ci							sc->result =
84062306a36Sopenharmony_ci							DID_SOFT_ERROR << 16;
84162306a36Sopenharmony_ci						    printk(KERN_WARNING "Errata"
84262306a36Sopenharmony_ci						    "on LSI53C1030 occurred."
84362306a36Sopenharmony_ci						    "sc->req_bufflen=0x%02x,"
84462306a36Sopenharmony_ci						    "xfer_cnt=0x%02x\n",
84562306a36Sopenharmony_ci						    scsi_bufflen(sc),
84662306a36Sopenharmony_ci						    xfer_cnt);
84762306a36Sopenharmony_ci						}
84862306a36Sopenharmony_ci					}
84962306a36Sopenharmony_ci				}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci				if (xfer_cnt < sc->underflow) {
85262306a36Sopenharmony_ci					if (scsi_status == SAM_STAT_BUSY)
85362306a36Sopenharmony_ci						sc->result = SAM_STAT_BUSY;
85462306a36Sopenharmony_ci					else
85562306a36Sopenharmony_ci						sc->result = DID_SOFT_ERROR << 16;
85662306a36Sopenharmony_ci				}
85762306a36Sopenharmony_ci				if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
85862306a36Sopenharmony_ci					/* What to do?
85962306a36Sopenharmony_ci				 	*/
86062306a36Sopenharmony_ci					sc->result = DID_SOFT_ERROR << 16;
86162306a36Sopenharmony_ci				}
86262306a36Sopenharmony_ci				else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
86362306a36Sopenharmony_ci					/*  Not real sure here either...  */
86462306a36Sopenharmony_ci					sc->result = DID_RESET << 16;
86562306a36Sopenharmony_ci				}
86662306a36Sopenharmony_ci			}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
87062306a36Sopenharmony_ci			    "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
87162306a36Sopenharmony_ci			    ioc->name, sc->underflow));
87262306a36Sopenharmony_ci			dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
87362306a36Sopenharmony_ci			    "  ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci			/* Report Queue Full
87662306a36Sopenharmony_ci			 */
87762306a36Sopenharmony_ci			if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
87862306a36Sopenharmony_ci				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci			break;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:		/* 0x0044 */
88362306a36Sopenharmony_ci			scsi_set_resid(sc, 0);
88462306a36Sopenharmony_ci			fallthrough;
88562306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
88662306a36Sopenharmony_ci		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
88762306a36Sopenharmony_ci			sc->result = (DID_OK << 16) | scsi_status;
88862306a36Sopenharmony_ci			if (scsi_state == 0) {
88962306a36Sopenharmony_ci				;
89062306a36Sopenharmony_ci			} else if (scsi_state &
89162306a36Sopenharmony_ci			    MPI_SCSI_STATE_AUTOSENSE_VALID) {
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci				/*
89462306a36Sopenharmony_ci				 * For potential trouble on LSI53C1030.
89562306a36Sopenharmony_ci				 * (date:2007.xx.)
89662306a36Sopenharmony_ci				 * It is checked whether the length of
89762306a36Sopenharmony_ci				 * request data is equal to
89862306a36Sopenharmony_ci				 * the length of transfer and residual.
89962306a36Sopenharmony_ci				 * MEDIUM_ERROR is set by incorrect data.
90062306a36Sopenharmony_ci				 */
90162306a36Sopenharmony_ci				if ((ioc->bus_type == SPI) &&
90262306a36Sopenharmony_ci					(sc->sense_buffer[2] & 0x20)) {
90362306a36Sopenharmony_ci					u32	 difftransfer;
90462306a36Sopenharmony_ci					difftransfer =
90562306a36Sopenharmony_ci					sc->sense_buffer[3] << 24 |
90662306a36Sopenharmony_ci					sc->sense_buffer[4] << 16 |
90762306a36Sopenharmony_ci					sc->sense_buffer[5] << 8 |
90862306a36Sopenharmony_ci					sc->sense_buffer[6];
90962306a36Sopenharmony_ci					if (((sc->sense_buffer[3] & 0x80) ==
91062306a36Sopenharmony_ci						0x80) && (scsi_bufflen(sc)
91162306a36Sopenharmony_ci						!= xfer_cnt)) {
91262306a36Sopenharmony_ci						sc->sense_buffer[2] =
91362306a36Sopenharmony_ci						    MEDIUM_ERROR;
91462306a36Sopenharmony_ci						sc->sense_buffer[12] = 0xff;
91562306a36Sopenharmony_ci						sc->sense_buffer[13] = 0xff;
91662306a36Sopenharmony_ci						printk(KERN_WARNING"Errata"
91762306a36Sopenharmony_ci						"on LSI53C1030 occurred."
91862306a36Sopenharmony_ci						"sc->req_bufflen=0x%02x,"
91962306a36Sopenharmony_ci						"xfer_cnt=0x%02x\n" ,
92062306a36Sopenharmony_ci						scsi_bufflen(sc),
92162306a36Sopenharmony_ci						xfer_cnt);
92262306a36Sopenharmony_ci					}
92362306a36Sopenharmony_ci					if (((sc->sense_buffer[3] & 0x80)
92462306a36Sopenharmony_ci						!= 0x80) &&
92562306a36Sopenharmony_ci						(scsi_bufflen(sc) !=
92662306a36Sopenharmony_ci						xfer_cnt + difftransfer)) {
92762306a36Sopenharmony_ci						sc->sense_buffer[2] =
92862306a36Sopenharmony_ci							MEDIUM_ERROR;
92962306a36Sopenharmony_ci						sc->sense_buffer[12] = 0xff;
93062306a36Sopenharmony_ci						sc->sense_buffer[13] = 0xff;
93162306a36Sopenharmony_ci						printk(KERN_WARNING
93262306a36Sopenharmony_ci						"Errata on LSI53C1030 occurred"
93362306a36Sopenharmony_ci						"sc->req_bufflen=0x%02x,"
93462306a36Sopenharmony_ci						" xfer_cnt=0x%02x,"
93562306a36Sopenharmony_ci						"difftransfer=0x%02x\n",
93662306a36Sopenharmony_ci						scsi_bufflen(sc),
93762306a36Sopenharmony_ci						xfer_cnt,
93862306a36Sopenharmony_ci						difftransfer);
93962306a36Sopenharmony_ci					}
94062306a36Sopenharmony_ci				}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci				/*
94362306a36Sopenharmony_ci				 * If running against circa 200003dd 909 MPT f/w,
94462306a36Sopenharmony_ci				 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
94562306a36Sopenharmony_ci				 * (QUEUE_FULL) returned from device! --> get 0x0000?128
94662306a36Sopenharmony_ci				 * and with SenseBytes set to 0.
94762306a36Sopenharmony_ci				 */
94862306a36Sopenharmony_ci				if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
94962306a36Sopenharmony_ci					mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci			}
95262306a36Sopenharmony_ci			else if (scsi_state &
95362306a36Sopenharmony_ci			         (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
95462306a36Sopenharmony_ci			   ) {
95562306a36Sopenharmony_ci				/*
95662306a36Sopenharmony_ci				 * What to do?
95762306a36Sopenharmony_ci				 */
95862306a36Sopenharmony_ci				sc->result = DID_SOFT_ERROR << 16;
95962306a36Sopenharmony_ci			}
96062306a36Sopenharmony_ci			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
96162306a36Sopenharmony_ci				/*  Not real sure here either...  */
96262306a36Sopenharmony_ci				sc->result = DID_RESET << 16;
96362306a36Sopenharmony_ci			}
96462306a36Sopenharmony_ci			else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
96562306a36Sopenharmony_ci				/* Device Inq. data indicates that it supports
96662306a36Sopenharmony_ci				 * QTags, but rejects QTag messages.
96762306a36Sopenharmony_ci				 * This command completed OK.
96862306a36Sopenharmony_ci				 *
96962306a36Sopenharmony_ci				 * Not real sure here either so do nothing...  */
97062306a36Sopenharmony_ci			}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
97362306a36Sopenharmony_ci				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci			/* Add handling of:
97662306a36Sopenharmony_ci			 * Reservation Conflict, Busy,
97762306a36Sopenharmony_ci			 * Command Terminated, CHECK
97862306a36Sopenharmony_ci			 */
97962306a36Sopenharmony_ci			break;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
98262306a36Sopenharmony_ci			sc->result = DID_SOFT_ERROR << 16;
98362306a36Sopenharmony_ci			break;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci		case MPI_IOCSTATUS_INVALID_FUNCTION:		/* 0x0001 */
98662306a36Sopenharmony_ci		case MPI_IOCSTATUS_INVALID_SGL:			/* 0x0003 */
98762306a36Sopenharmony_ci		case MPI_IOCSTATUS_INTERNAL_ERROR:		/* 0x0004 */
98862306a36Sopenharmony_ci		case MPI_IOCSTATUS_RESERVED:			/* 0x0005 */
98962306a36Sopenharmony_ci		case MPI_IOCSTATUS_INVALID_FIELD:		/* 0x0007 */
99062306a36Sopenharmony_ci		case MPI_IOCSTATUS_INVALID_STATE:		/* 0x0008 */
99162306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
99262306a36Sopenharmony_ci		case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:	/* 0x004A */
99362306a36Sopenharmony_ci		default:
99462306a36Sopenharmony_ci			/*
99562306a36Sopenharmony_ci			 * What to do?
99662306a36Sopenharmony_ci			 */
99762306a36Sopenharmony_ci			sc->result = DID_SOFT_ERROR << 16;
99862306a36Sopenharmony_ci			break;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci		}	/* switch(status) */
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci#ifdef CONFIG_FUSION_LOGGING
100362306a36Sopenharmony_ci		if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
100462306a36Sopenharmony_ci			mptscsih_info_scsiio(ioc, sc, pScsiReply);
100562306a36Sopenharmony_ci#endif
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	} /* end of address reply case */
100862306a36Sopenharmony_ciout:
100962306a36Sopenharmony_ci	/* Unmap the DMA buffers, if any. */
101062306a36Sopenharmony_ci	scsi_dma_unmap(sc);
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	scsi_done(sc);			/* Issue the command callback */
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	/* Free Chain buffers */
101562306a36Sopenharmony_ci	mptscsih_freeChainBuffers(ioc, req_idx);
101662306a36Sopenharmony_ci	return 1;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci/*
102062306a36Sopenharmony_ci *	mptscsih_flush_running_cmds - For each command found, search
102162306a36Sopenharmony_ci *		Scsi_Host instance taskQ and reply to OS.
102262306a36Sopenharmony_ci *		Called only if recovering from a FW reload.
102362306a36Sopenharmony_ci *	@hd: Pointer to a SCSI HOST structure
102462306a36Sopenharmony_ci *
102562306a36Sopenharmony_ci *	Returns: None.
102662306a36Sopenharmony_ci *
102762306a36Sopenharmony_ci *	Must be called while new I/Os are being queued.
102862306a36Sopenharmony_ci */
102962306a36Sopenharmony_civoid
103062306a36Sopenharmony_cimptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
103362306a36Sopenharmony_ci	struct scsi_cmnd *sc;
103462306a36Sopenharmony_ci	SCSIIORequest_t	*mf = NULL;
103562306a36Sopenharmony_ci	int		 ii;
103662306a36Sopenharmony_ci	int		 channel, id;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	for (ii= 0; ii < ioc->req_depth; ii++) {
103962306a36Sopenharmony_ci		sc = mptscsih_getclear_scsi_lookup(ioc, ii);
104062306a36Sopenharmony_ci		if (!sc)
104162306a36Sopenharmony_ci			continue;
104262306a36Sopenharmony_ci		mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
104362306a36Sopenharmony_ci		if (!mf)
104462306a36Sopenharmony_ci			continue;
104562306a36Sopenharmony_ci		channel = mf->Bus;
104662306a36Sopenharmony_ci		id = mf->TargetID;
104762306a36Sopenharmony_ci		mptscsih_freeChainBuffers(ioc, ii);
104862306a36Sopenharmony_ci		mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
104962306a36Sopenharmony_ci		if ((unsigned char *)mf != sc->host_scribble)
105062306a36Sopenharmony_ci			continue;
105162306a36Sopenharmony_ci		scsi_dma_unmap(sc);
105262306a36Sopenharmony_ci		sc->result = DID_RESET << 16;
105362306a36Sopenharmony_ci		sc->host_scribble = NULL;
105462306a36Sopenharmony_ci		dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
105562306a36Sopenharmony_ci		    "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
105662306a36Sopenharmony_ci		    "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
105762306a36Sopenharmony_ci		scsi_done(sc);
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_flush_running_cmds);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci/*
106362306a36Sopenharmony_ci *	mptscsih_search_running_cmds - Delete any commands associated
106462306a36Sopenharmony_ci *		with the specified target and lun. Function called only
106562306a36Sopenharmony_ci *		when a lun is disable by mid-layer.
106662306a36Sopenharmony_ci *		Do NOT access the referenced scsi_cmnd structure or
106762306a36Sopenharmony_ci *		members. Will cause either a paging or NULL ptr error.
106862306a36Sopenharmony_ci *		(BUT, BUT, BUT, the code does reference it! - mdr)
106962306a36Sopenharmony_ci *      @hd: Pointer to a SCSI HOST structure
107062306a36Sopenharmony_ci *	@vdevice: per device private data
107162306a36Sopenharmony_ci *
107262306a36Sopenharmony_ci *	Returns: None.
107362306a36Sopenharmony_ci *
107462306a36Sopenharmony_ci *	Called from slave_destroy.
107562306a36Sopenharmony_ci */
107662306a36Sopenharmony_cistatic void
107762306a36Sopenharmony_cimptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
107862306a36Sopenharmony_ci{
107962306a36Sopenharmony_ci	SCSIIORequest_t	*mf = NULL;
108062306a36Sopenharmony_ci	int		 ii;
108162306a36Sopenharmony_ci	struct scsi_cmnd *sc;
108262306a36Sopenharmony_ci	struct scsi_lun  lun;
108362306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
108462306a36Sopenharmony_ci	unsigned long	flags;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
108762306a36Sopenharmony_ci	for (ii = 0; ii < ioc->req_depth; ii++) {
108862306a36Sopenharmony_ci		if ((sc = ioc->ScsiLookup[ii]) != NULL) {
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci			mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
109162306a36Sopenharmony_ci			if (mf == NULL)
109262306a36Sopenharmony_ci				continue;
109362306a36Sopenharmony_ci			/* If the device is a hidden raid component, then its
109462306a36Sopenharmony_ci			 * expected that the mf->function will be RAID_SCSI_IO
109562306a36Sopenharmony_ci			 */
109662306a36Sopenharmony_ci			if (vdevice->vtarget->tflags &
109762306a36Sopenharmony_ci			    MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
109862306a36Sopenharmony_ci			    MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
109962306a36Sopenharmony_ci				continue;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci			int_to_scsilun(vdevice->lun, &lun);
110262306a36Sopenharmony_ci			if ((mf->Bus != vdevice->vtarget->channel) ||
110362306a36Sopenharmony_ci			    (mf->TargetID != vdevice->vtarget->id) ||
110462306a36Sopenharmony_ci			    memcmp(lun.scsi_lun, mf->LUN, 8))
110562306a36Sopenharmony_ci				continue;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci			if ((unsigned char *)mf != sc->host_scribble)
110862306a36Sopenharmony_ci				continue;
110962306a36Sopenharmony_ci			ioc->ScsiLookup[ii] = NULL;
111062306a36Sopenharmony_ci			spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
111162306a36Sopenharmony_ci			mptscsih_freeChainBuffers(ioc, ii);
111262306a36Sopenharmony_ci			mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
111362306a36Sopenharmony_ci			scsi_dma_unmap(sc);
111462306a36Sopenharmony_ci			sc->host_scribble = NULL;
111562306a36Sopenharmony_ci			sc->result = DID_NO_CONNECT << 16;
111662306a36Sopenharmony_ci			dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
111762306a36Sopenharmony_ci			   MYIOC_s_FMT "completing cmds: fw_channel %d, "
111862306a36Sopenharmony_ci			   "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
111962306a36Sopenharmony_ci			   vdevice->vtarget->channel, vdevice->vtarget->id,
112062306a36Sopenharmony_ci			   sc, mf, ii));
112162306a36Sopenharmony_ci			scsi_done(sc);
112262306a36Sopenharmony_ci			spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
112362306a36Sopenharmony_ci		}
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
112662306a36Sopenharmony_ci	return;
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
113262306a36Sopenharmony_ci/*
113362306a36Sopenharmony_ci *	mptscsih_report_queue_full - Report QUEUE_FULL status returned
113462306a36Sopenharmony_ci *	from a SCSI target device.
113562306a36Sopenharmony_ci *	@sc: Pointer to scsi_cmnd structure
113662306a36Sopenharmony_ci *	@pScsiReply: Pointer to SCSIIOReply_t
113762306a36Sopenharmony_ci *	@pScsiReq: Pointer to original SCSI request
113862306a36Sopenharmony_ci *
113962306a36Sopenharmony_ci *	This routine periodically reports QUEUE_FULL status returned from a
114062306a36Sopenharmony_ci *	SCSI target device.  It reports this to the console via kernel
114162306a36Sopenharmony_ci *	printk() API call, not more than once every 10 seconds.
114262306a36Sopenharmony_ci */
114362306a36Sopenharmony_cistatic void
114462306a36Sopenharmony_cimptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
114562306a36Sopenharmony_ci{
114662306a36Sopenharmony_ci	long time = jiffies;
114762306a36Sopenharmony_ci	MPT_SCSI_HOST		*hd;
114862306a36Sopenharmony_ci	MPT_ADAPTER	*ioc;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	if (sc->device == NULL)
115162306a36Sopenharmony_ci		return;
115262306a36Sopenharmony_ci	if (sc->device->host == NULL)
115362306a36Sopenharmony_ci		return;
115462306a36Sopenharmony_ci	if ((hd = shost_priv(sc->device->host)) == NULL)
115562306a36Sopenharmony_ci		return;
115662306a36Sopenharmony_ci	ioc = hd->ioc;
115762306a36Sopenharmony_ci	if (time - hd->last_queue_full > 10 * HZ) {
115862306a36Sopenharmony_ci		dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%llu) reported QUEUE_FULL!\n",
115962306a36Sopenharmony_ci				ioc->name, 0, sc->device->id, sc->device->lun));
116062306a36Sopenharmony_ci		hd->last_queue_full = time;
116162306a36Sopenharmony_ci	}
116262306a36Sopenharmony_ci}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
116562306a36Sopenharmony_ci/*
116662306a36Sopenharmony_ci *	mptscsih_remove - Removed scsi devices
116762306a36Sopenharmony_ci *	@pdev: Pointer to pci_dev structure
116862306a36Sopenharmony_ci *
116962306a36Sopenharmony_ci *
117062306a36Sopenharmony_ci */
117162306a36Sopenharmony_civoid
117262306a36Sopenharmony_cimptscsih_remove(struct pci_dev *pdev)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
117562306a36Sopenharmony_ci	struct Scsi_Host 	*host = ioc->sh;
117662306a36Sopenharmony_ci	MPT_SCSI_HOST		*hd;
117762306a36Sopenharmony_ci	int sz1;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	if (host == NULL)
118062306a36Sopenharmony_ci		hd = NULL;
118162306a36Sopenharmony_ci	else
118262306a36Sopenharmony_ci		hd = shost_priv(host);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	mptscsih_shutdown(pdev);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	sz1=0;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	if (ioc->ScsiLookup != NULL) {
118962306a36Sopenharmony_ci		sz1 = ioc->req_depth * sizeof(void *);
119062306a36Sopenharmony_ci		kfree(ioc->ScsiLookup);
119162306a36Sopenharmony_ci		ioc->ScsiLookup = NULL;
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
119562306a36Sopenharmony_ci	    "Free'd ScsiLookup (%d) memory\n",
119662306a36Sopenharmony_ci	    ioc->name, sz1));
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	if (hd)
119962306a36Sopenharmony_ci		kfree(hd->info_kbuf);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	/* NULL the Scsi_Host pointer
120262306a36Sopenharmony_ci	 */
120362306a36Sopenharmony_ci	ioc->sh = NULL;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	if (host)
120662306a36Sopenharmony_ci		scsi_host_put(host);
120762306a36Sopenharmony_ci	mpt_detach(pdev);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
121262306a36Sopenharmony_ci/*
121362306a36Sopenharmony_ci *	mptscsih_shutdown - reboot notifier
121462306a36Sopenharmony_ci *
121562306a36Sopenharmony_ci */
121662306a36Sopenharmony_civoid
121762306a36Sopenharmony_cimptscsih_shutdown(struct pci_dev *pdev)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci#ifdef CONFIG_PM
122262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
122362306a36Sopenharmony_ci/*
122462306a36Sopenharmony_ci *	mptscsih_suspend - Fusion MPT scsi driver suspend routine.
122562306a36Sopenharmony_ci *
122662306a36Sopenharmony_ci *
122762306a36Sopenharmony_ci */
122862306a36Sopenharmony_ciint
122962306a36Sopenharmony_cimptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	scsi_block_requests(ioc->sh);
123462306a36Sopenharmony_ci	mptscsih_shutdown(pdev);
123562306a36Sopenharmony_ci	return mpt_suspend(pdev,state);
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
123962306a36Sopenharmony_ci/*
124062306a36Sopenharmony_ci *	mptscsih_resume - Fusion MPT scsi driver resume routine.
124162306a36Sopenharmony_ci *
124262306a36Sopenharmony_ci *
124362306a36Sopenharmony_ci */
124462306a36Sopenharmony_ciint
124562306a36Sopenharmony_cimptscsih_resume(struct pci_dev *pdev)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
124862306a36Sopenharmony_ci	int rc;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	rc = mpt_resume(pdev);
125162306a36Sopenharmony_ci	scsi_unblock_requests(ioc->sh);
125262306a36Sopenharmony_ci	return rc;
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci#endif
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125862306a36Sopenharmony_ci/**
125962306a36Sopenharmony_ci *	mptscsih_info - Return information about MPT adapter
126062306a36Sopenharmony_ci *	@SChost: Pointer to Scsi_Host structure
126162306a36Sopenharmony_ci *
126262306a36Sopenharmony_ci *	(linux scsi_host_template.info routine)
126362306a36Sopenharmony_ci *
126462306a36Sopenharmony_ci *	Returns pointer to buffer where information was written.
126562306a36Sopenharmony_ci */
126662306a36Sopenharmony_ciconst char *
126762306a36Sopenharmony_cimptscsih_info(struct Scsi_Host *SChost)
126862306a36Sopenharmony_ci{
126962306a36Sopenharmony_ci	MPT_SCSI_HOST *h;
127062306a36Sopenharmony_ci	int size = 0;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	h = shost_priv(SChost);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	if (h->info_kbuf == NULL)
127562306a36Sopenharmony_ci		if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
127662306a36Sopenharmony_ci			return h->info_kbuf;
127762306a36Sopenharmony_ci	h->info_kbuf[0] = '\0';
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
128062306a36Sopenharmony_ci	h->info_kbuf[size-1] = '\0';
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	return h->info_kbuf;
128362306a36Sopenharmony_ci}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ciint mptscsih_show_info(struct seq_file *m, struct Scsi_Host *host)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
128862306a36Sopenharmony_ci	MPT_ADAPTER	*ioc = hd->ioc;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	seq_printf(m, "%s: %s, ", ioc->name, ioc->prod_name);
129162306a36Sopenharmony_ci	seq_printf(m, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
129262306a36Sopenharmony_ci	seq_printf(m, "Ports=%d, ", ioc->facts.NumberOfPorts);
129362306a36Sopenharmony_ci	seq_printf(m, "MaxQ=%d\n", ioc->req_depth);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	return 0;
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
129962306a36Sopenharmony_ci#define ADD_INDEX_LOG(req_ent)	do { } while(0)
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
130262306a36Sopenharmony_ci/**
130362306a36Sopenharmony_ci *	mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
130462306a36Sopenharmony_ci *	@SCpnt: Pointer to scsi_cmnd structure
130562306a36Sopenharmony_ci *
130662306a36Sopenharmony_ci *	(linux scsi_host_template.queuecommand routine)
130762306a36Sopenharmony_ci *	This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
130862306a36Sopenharmony_ci *	from a linux scsi_cmnd request and send it to the IOC.
130962306a36Sopenharmony_ci *
131062306a36Sopenharmony_ci *	Returns 0. (rtn value discarded by linux scsi mid-layer)
131162306a36Sopenharmony_ci */
131262306a36Sopenharmony_ciint
131362306a36Sopenharmony_cimptscsih_qcmd(struct scsi_cmnd *SCpnt)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	MPT_SCSI_HOST		*hd;
131662306a36Sopenharmony_ci	MPT_FRAME_HDR		*mf;
131762306a36Sopenharmony_ci	SCSIIORequest_t		*pScsiReq;
131862306a36Sopenharmony_ci	VirtDevice		*vdevice = SCpnt->device->hostdata;
131962306a36Sopenharmony_ci	u32	 datalen;
132062306a36Sopenharmony_ci	u32	 scsictl;
132162306a36Sopenharmony_ci	u32	 scsidir;
132262306a36Sopenharmony_ci	u32	 cmd_len;
132362306a36Sopenharmony_ci	int	 my_idx;
132462306a36Sopenharmony_ci	int	 ii;
132562306a36Sopenharmony_ci	MPT_ADAPTER *ioc;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	hd = shost_priv(SCpnt->device->host);
132862306a36Sopenharmony_ci	ioc = hd->ioc;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p\n",
133162306a36Sopenharmony_ci		ioc->name, SCpnt));
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (ioc->taskmgmt_quiesce_io)
133462306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	/*
133762306a36Sopenharmony_ci	 *  Put together a MPT SCSI request...
133862306a36Sopenharmony_ci	 */
133962306a36Sopenharmony_ci	if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
134062306a36Sopenharmony_ci		dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
134162306a36Sopenharmony_ci				ioc->name));
134262306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
134362306a36Sopenharmony_ci	}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	pScsiReq = (SCSIIORequest_t *) mf;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	ADD_INDEX_LOG(my_idx);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	/*    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
135262306a36Sopenharmony_ci	 *    Seems we may receive a buffer (datalen>0) even when there
135362306a36Sopenharmony_ci	 *    will be no data transfer!  GRRRRR...
135462306a36Sopenharmony_ci	 */
135562306a36Sopenharmony_ci	if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
135662306a36Sopenharmony_ci		datalen = scsi_bufflen(SCpnt);
135762306a36Sopenharmony_ci		scsidir = MPI_SCSIIO_CONTROL_READ;	/* DATA IN  (host<--ioc<--dev) */
135862306a36Sopenharmony_ci	} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
135962306a36Sopenharmony_ci		datalen = scsi_bufflen(SCpnt);
136062306a36Sopenharmony_ci		scsidir = MPI_SCSIIO_CONTROL_WRITE;	/* DATA OUT (host-->ioc-->dev) */
136162306a36Sopenharmony_ci	} else {
136262306a36Sopenharmony_ci		datalen = 0;
136362306a36Sopenharmony_ci		scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	/* Default to untagged. Once a target structure has been allocated,
136762306a36Sopenharmony_ci	 * use the Inquiry data to determine if device supports tagged.
136862306a36Sopenharmony_ci	 */
136962306a36Sopenharmony_ci	if ((vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) &&
137062306a36Sopenharmony_ci	    SCpnt->device->tagged_supported)
137162306a36Sopenharmony_ci		scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
137262306a36Sopenharmony_ci	else
137362306a36Sopenharmony_ci		scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	/* Use the above information to set up the message frame
137762306a36Sopenharmony_ci	 */
137862306a36Sopenharmony_ci	pScsiReq->TargetID = (u8) vdevice->vtarget->id;
137962306a36Sopenharmony_ci	pScsiReq->Bus = vdevice->vtarget->channel;
138062306a36Sopenharmony_ci	pScsiReq->ChainOffset = 0;
138162306a36Sopenharmony_ci	if (vdevice->vtarget->tflags &  MPT_TARGET_FLAGS_RAID_COMPONENT)
138262306a36Sopenharmony_ci		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
138362306a36Sopenharmony_ci	else
138462306a36Sopenharmony_ci		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
138562306a36Sopenharmony_ci	pScsiReq->CDBLength = SCpnt->cmd_len;
138662306a36Sopenharmony_ci	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
138762306a36Sopenharmony_ci	pScsiReq->Reserved = 0;
138862306a36Sopenharmony_ci	pScsiReq->MsgFlags = mpt_msg_flags(ioc);
138962306a36Sopenharmony_ci	int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
139062306a36Sopenharmony_ci	pScsiReq->Control = cpu_to_le32(scsictl);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	/*
139362306a36Sopenharmony_ci	 *  Write SCSI CDB into the message
139462306a36Sopenharmony_ci	 */
139562306a36Sopenharmony_ci	cmd_len = SCpnt->cmd_len;
139662306a36Sopenharmony_ci	for (ii=0; ii < cmd_len; ii++)
139762306a36Sopenharmony_ci		pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	for (ii=cmd_len; ii < 16; ii++)
140062306a36Sopenharmony_ci		pScsiReq->CDB[ii] = 0;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	/* DataLength */
140362306a36Sopenharmony_ci	pScsiReq->DataLength = cpu_to_le32(datalen);
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	/* SenseBuffer low address */
140662306a36Sopenharmony_ci	pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
140762306a36Sopenharmony_ci					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/* Now add the SG list
141062306a36Sopenharmony_ci	 * Always have a SGE even if null length.
141162306a36Sopenharmony_ci	 */
141262306a36Sopenharmony_ci	if (datalen == 0) {
141362306a36Sopenharmony_ci		/* Add a NULL SGE */
141462306a36Sopenharmony_ci		ioc->add_sge((char *)&pScsiReq->SGL,
141562306a36Sopenharmony_ci			MPT_SGE_FLAGS_SSIMPLE_READ | 0,
141662306a36Sopenharmony_ci			(dma_addr_t) -1);
141762306a36Sopenharmony_ci	} else {
141862306a36Sopenharmony_ci		/* Add a 32 or 64 bit SGE */
141962306a36Sopenharmony_ci		if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
142062306a36Sopenharmony_ci			goto fail;
142162306a36Sopenharmony_ci	}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	SCpnt->host_scribble = (unsigned char *)mf;
142462306a36Sopenharmony_ci	mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
142762306a36Sopenharmony_ci	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
142862306a36Sopenharmony_ci			ioc->name, SCpnt, mf, my_idx));
142962306a36Sopenharmony_ci	DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
143062306a36Sopenharmony_ci	return 0;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci fail:
143362306a36Sopenharmony_ci	mptscsih_freeChainBuffers(ioc, my_idx);
143462306a36Sopenharmony_ci	mpt_free_msg_frame(ioc, mf);
143562306a36Sopenharmony_ci	return SCSI_MLQUEUE_HOST_BUSY;
143662306a36Sopenharmony_ci}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
143962306a36Sopenharmony_ci/*
144062306a36Sopenharmony_ci *	mptscsih_freeChainBuffers - Function to free chain buffers associated
144162306a36Sopenharmony_ci *	with a SCSI IO request
144262306a36Sopenharmony_ci *	@hd: Pointer to the MPT_SCSI_HOST instance
144362306a36Sopenharmony_ci *	@req_idx: Index of the SCSI IO request frame.
144462306a36Sopenharmony_ci *
144562306a36Sopenharmony_ci *	Called if SG chain buffer allocation fails and mptscsih callbacks.
144662306a36Sopenharmony_ci *	No return.
144762306a36Sopenharmony_ci */
144862306a36Sopenharmony_cistatic void
144962306a36Sopenharmony_cimptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
145062306a36Sopenharmony_ci{
145162306a36Sopenharmony_ci	MPT_FRAME_HDR *chain;
145262306a36Sopenharmony_ci	unsigned long flags;
145362306a36Sopenharmony_ci	int chain_idx;
145462306a36Sopenharmony_ci	int next;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	/* Get the first chain index and reset
145762306a36Sopenharmony_ci	 * tracker state.
145862306a36Sopenharmony_ci	 */
145962306a36Sopenharmony_ci	chain_idx = ioc->ReqToChain[req_idx];
146062306a36Sopenharmony_ci	ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	while (chain_idx != MPT_HOST_NO_CHAIN) {
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci		/* Save the next chain buffer index */
146562306a36Sopenharmony_ci		next = ioc->ChainToChain[chain_idx];
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci		/* Free this chain buffer and reset
146862306a36Sopenharmony_ci		 * tracker
146962306a36Sopenharmony_ci		 */
147062306a36Sopenharmony_ci		ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci		chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
147362306a36Sopenharmony_ci					+ (chain_idx * ioc->req_sz));
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci		spin_lock_irqsave(&ioc->FreeQlock, flags);
147662306a36Sopenharmony_ci		list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
147762306a36Sopenharmony_ci		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
148062306a36Sopenharmony_ci				ioc->name, chain_idx));
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci		/* handle next */
148362306a36Sopenharmony_ci		chain_idx = next;
148462306a36Sopenharmony_ci	}
148562306a36Sopenharmony_ci	return;
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
148962306a36Sopenharmony_ci/*
149062306a36Sopenharmony_ci *	Reset Handling
149162306a36Sopenharmony_ci */
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
149462306a36Sopenharmony_ci/**
149562306a36Sopenharmony_ci *	mptscsih_IssueTaskMgmt - Generic send Task Management function.
149662306a36Sopenharmony_ci *	@hd: Pointer to MPT_SCSI_HOST structure
149762306a36Sopenharmony_ci *	@type: Task Management type
149862306a36Sopenharmony_ci *	@channel: channel number for task management
149962306a36Sopenharmony_ci *	@id: Logical Target ID for reset (if appropriate)
150062306a36Sopenharmony_ci *	@lun: Logical Unit for reset (if appropriate)
150162306a36Sopenharmony_ci *	@ctx2abort: Context for the task to be aborted (if appropriate)
150262306a36Sopenharmony_ci *	@timeout: timeout for task management control
150362306a36Sopenharmony_ci *
150462306a36Sopenharmony_ci *	Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
150562306a36Sopenharmony_ci *	or a non-interrupt thread.  In the former, must not call schedule().
150662306a36Sopenharmony_ci *
150762306a36Sopenharmony_ci *	Not all fields are meaningfull for all task types.
150862306a36Sopenharmony_ci *
150962306a36Sopenharmony_ci *	Returns 0 for SUCCESS, or FAILED.
151062306a36Sopenharmony_ci *
151162306a36Sopenharmony_ci **/
151262306a36Sopenharmony_ciint
151362306a36Sopenharmony_cimptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, u64 lun,
151462306a36Sopenharmony_ci	int ctx2abort, ulong timeout)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	MPT_FRAME_HDR	*mf;
151762306a36Sopenharmony_ci	SCSITaskMgmt_t	*pScsiTm;
151862306a36Sopenharmony_ci	int		 ii;
151962306a36Sopenharmony_ci	int		 retval;
152062306a36Sopenharmony_ci	MPT_ADAPTER 	*ioc = hd->ioc;
152162306a36Sopenharmony_ci	u8		 issue_hard_reset;
152262306a36Sopenharmony_ci	u32		 ioc_raw_state;
152362306a36Sopenharmony_ci	unsigned long	 time_count;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	issue_hard_reset = 0;
152662306a36Sopenharmony_ci	ioc_raw_state = mpt_GetIocState(ioc, 0);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
152962306a36Sopenharmony_ci		printk(MYIOC_s_WARN_FMT
153062306a36Sopenharmony_ci			"TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
153162306a36Sopenharmony_ci			ioc->name, type, ioc_raw_state);
153262306a36Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
153362306a36Sopenharmony_ci		    ioc->name, __func__);
153462306a36Sopenharmony_ci		if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
153562306a36Sopenharmony_ci			printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
153662306a36Sopenharmony_ci			    "FAILED!!\n", ioc->name);
153762306a36Sopenharmony_ci		return 0;
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	/* DOORBELL ACTIVE check is not required if
154162306a36Sopenharmony_ci	*  MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q is supported.
154262306a36Sopenharmony_ci	*/
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	if (!((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q)
154562306a36Sopenharmony_ci		 && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) &&
154662306a36Sopenharmony_ci		(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
154762306a36Sopenharmony_ci		printk(MYIOC_s_WARN_FMT
154862306a36Sopenharmony_ci			"TaskMgmt type=%x: ioc_state: "
154962306a36Sopenharmony_ci			"DOORBELL_ACTIVE (0x%x)!\n",
155062306a36Sopenharmony_ci			ioc->name, type, ioc_raw_state);
155162306a36Sopenharmony_ci		return FAILED;
155262306a36Sopenharmony_ci	}
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	mutex_lock(&ioc->taskmgmt_cmds.mutex);
155562306a36Sopenharmony_ci	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
155662306a36Sopenharmony_ci		mf = NULL;
155762306a36Sopenharmony_ci		retval = FAILED;
155862306a36Sopenharmony_ci		goto out;
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	/* Return Fail to calling function if no message frames available.
156262306a36Sopenharmony_ci	 */
156362306a36Sopenharmony_ci	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
156462306a36Sopenharmony_ci		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
156562306a36Sopenharmony_ci			"TaskMgmt no msg frames!!\n", ioc->name));
156662306a36Sopenharmony_ci		retval = FAILED;
156762306a36Sopenharmony_ci		mpt_clear_taskmgmt_in_progress_flag(ioc);
156862306a36Sopenharmony_ci		goto out;
156962306a36Sopenharmony_ci	}
157062306a36Sopenharmony_ci	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
157162306a36Sopenharmony_ci			ioc->name, mf));
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	/* Format the Request
157462306a36Sopenharmony_ci	 */
157562306a36Sopenharmony_ci	pScsiTm = (SCSITaskMgmt_t *) mf;
157662306a36Sopenharmony_ci	pScsiTm->TargetID = id;
157762306a36Sopenharmony_ci	pScsiTm->Bus = channel;
157862306a36Sopenharmony_ci	pScsiTm->ChainOffset = 0;
157962306a36Sopenharmony_ci	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	pScsiTm->Reserved = 0;
158262306a36Sopenharmony_ci	pScsiTm->TaskType = type;
158362306a36Sopenharmony_ci	pScsiTm->Reserved1 = 0;
158462306a36Sopenharmony_ci	pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
158562306a36Sopenharmony_ci                    ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	for (ii=0; ii < 7; ii++)
159062306a36Sopenharmony_ci		pScsiTm->Reserved2[ii] = 0;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	pScsiTm->TaskMsgContext = ctx2abort;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
159562306a36Sopenharmony_ci		"task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
159662306a36Sopenharmony_ci		type, timeout));
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
160162306a36Sopenharmony_ci	time_count = jiffies;
160262306a36Sopenharmony_ci	if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
160362306a36Sopenharmony_ci	    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
160462306a36Sopenharmony_ci		mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
160562306a36Sopenharmony_ci	else {
160662306a36Sopenharmony_ci		retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
160762306a36Sopenharmony_ci			sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
160862306a36Sopenharmony_ci		if (retval) {
160962306a36Sopenharmony_ci			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
161062306a36Sopenharmony_ci				"TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
161162306a36Sopenharmony_ci				ioc->name, mf, retval));
161262306a36Sopenharmony_ci			mpt_free_msg_frame(ioc, mf);
161362306a36Sopenharmony_ci			mpt_clear_taskmgmt_in_progress_flag(ioc);
161462306a36Sopenharmony_ci			goto out;
161562306a36Sopenharmony_ci		}
161662306a36Sopenharmony_ci	}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
161962306a36Sopenharmony_ci		timeout*HZ);
162062306a36Sopenharmony_ci	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
162162306a36Sopenharmony_ci		retval = FAILED;
162262306a36Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
162362306a36Sopenharmony_ci		    "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
162462306a36Sopenharmony_ci		mpt_clear_taskmgmt_in_progress_flag(ioc);
162562306a36Sopenharmony_ci		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
162662306a36Sopenharmony_ci			goto out;
162762306a36Sopenharmony_ci		issue_hard_reset = 1;
162862306a36Sopenharmony_ci		goto out;
162962306a36Sopenharmony_ci	}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	retval = mptscsih_taskmgmt_reply(ioc, type,
163262306a36Sopenharmony_ci	    (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
163562306a36Sopenharmony_ci	    "TaskMgmt completed (%d seconds)\n",
163662306a36Sopenharmony_ci	    ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci out:
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
164162306a36Sopenharmony_ci	if (issue_hard_reset) {
164262306a36Sopenharmony_ci		printk(MYIOC_s_WARN_FMT
164362306a36Sopenharmony_ci		       "Issuing Reset from %s!! doorbell=0x%08x\n",
164462306a36Sopenharmony_ci		       ioc->name, __func__, mpt_GetIocState(ioc, 0));
164562306a36Sopenharmony_ci		retval = (ioc->bus_type == SAS) ?
164662306a36Sopenharmony_ci			mpt_HardResetHandler(ioc, CAN_SLEEP) :
164762306a36Sopenharmony_ci			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
164862306a36Sopenharmony_ci		mpt_free_msg_frame(ioc, mf);
164962306a36Sopenharmony_ci	}
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	retval = (retval == 0) ? 0 : FAILED;
165262306a36Sopenharmony_ci	mutex_unlock(&ioc->taskmgmt_cmds.mutex);
165362306a36Sopenharmony_ci	return retval;
165462306a36Sopenharmony_ci}
165562306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_cistatic int
165862306a36Sopenharmony_cimptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
165962306a36Sopenharmony_ci{
166062306a36Sopenharmony_ci	switch (ioc->bus_type) {
166162306a36Sopenharmony_ci	case FC:
166262306a36Sopenharmony_ci		return 40;
166362306a36Sopenharmony_ci	case SAS:
166462306a36Sopenharmony_ci		return 30;
166562306a36Sopenharmony_ci	case SPI:
166662306a36Sopenharmony_ci	default:
166762306a36Sopenharmony_ci		return 10;
166862306a36Sopenharmony_ci	}
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
167262306a36Sopenharmony_ci/**
167362306a36Sopenharmony_ci *	mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
167462306a36Sopenharmony_ci *	@SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
167562306a36Sopenharmony_ci *
167662306a36Sopenharmony_ci *	(linux scsi_host_template.eh_abort_handler routine)
167762306a36Sopenharmony_ci *
167862306a36Sopenharmony_ci *	Returns SUCCESS or FAILED.
167962306a36Sopenharmony_ci **/
168062306a36Sopenharmony_ciint
168162306a36Sopenharmony_cimptscsih_abort(struct scsi_cmnd * SCpnt)
168262306a36Sopenharmony_ci{
168362306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd;
168462306a36Sopenharmony_ci	MPT_FRAME_HDR	*mf;
168562306a36Sopenharmony_ci	u32		 ctx2abort;
168662306a36Sopenharmony_ci	int		 scpnt_idx;
168762306a36Sopenharmony_ci	int		 retval;
168862306a36Sopenharmony_ci	VirtDevice	 *vdevice;
168962306a36Sopenharmony_ci	MPT_ADAPTER	*ioc;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	/* If we can't locate our host adapter structure, return FAILED status.
169262306a36Sopenharmony_ci	 */
169362306a36Sopenharmony_ci	if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
169462306a36Sopenharmony_ci		SCpnt->result = DID_RESET << 16;
169562306a36Sopenharmony_ci		scsi_done(SCpnt);
169662306a36Sopenharmony_ci		printk(KERN_ERR MYNAM ": task abort: "
169762306a36Sopenharmony_ci		    "can't locate host! (sc=%p)\n", SCpnt);
169862306a36Sopenharmony_ci		return FAILED;
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	ioc = hd->ioc;
170262306a36Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
170362306a36Sopenharmony_ci	       ioc->name, SCpnt);
170462306a36Sopenharmony_ci	scsi_print_command(SCpnt);
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	vdevice = SCpnt->device->hostdata;
170762306a36Sopenharmony_ci	if (!vdevice || !vdevice->vtarget) {
170862306a36Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
170962306a36Sopenharmony_ci		    "task abort: device has been deleted (sc=%p)\n",
171062306a36Sopenharmony_ci		    ioc->name, SCpnt));
171162306a36Sopenharmony_ci		SCpnt->result = DID_NO_CONNECT << 16;
171262306a36Sopenharmony_ci		scsi_done(SCpnt);
171362306a36Sopenharmony_ci		retval = SUCCESS;
171462306a36Sopenharmony_ci		goto out;
171562306a36Sopenharmony_ci	}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	/* Task aborts are not supported for hidden raid components.
171862306a36Sopenharmony_ci	 */
171962306a36Sopenharmony_ci	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
172062306a36Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
172162306a36Sopenharmony_ci		    "task abort: hidden raid component (sc=%p)\n",
172262306a36Sopenharmony_ci		    ioc->name, SCpnt));
172362306a36Sopenharmony_ci		SCpnt->result = DID_RESET << 16;
172462306a36Sopenharmony_ci		retval = FAILED;
172562306a36Sopenharmony_ci		goto out;
172662306a36Sopenharmony_ci	}
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	/* Task aborts are not supported for volumes.
172962306a36Sopenharmony_ci	 */
173062306a36Sopenharmony_ci	if (vdevice->vtarget->raidVolume) {
173162306a36Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
173262306a36Sopenharmony_ci		    "task abort: raid volume (sc=%p)\n",
173362306a36Sopenharmony_ci		    ioc->name, SCpnt));
173462306a36Sopenharmony_ci		SCpnt->result = DID_RESET << 16;
173562306a36Sopenharmony_ci		retval = FAILED;
173662306a36Sopenharmony_ci		goto out;
173762306a36Sopenharmony_ci	}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	/* Find this command
174062306a36Sopenharmony_ci	 */
174162306a36Sopenharmony_ci	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
174262306a36Sopenharmony_ci		/* Cmd not found in ScsiLookup.
174362306a36Sopenharmony_ci		 * Do OS callback.
174462306a36Sopenharmony_ci		 */
174562306a36Sopenharmony_ci		SCpnt->result = DID_RESET << 16;
174662306a36Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
174762306a36Sopenharmony_ci		   "Command not in the active list! (sc=%p)\n", ioc->name,
174862306a36Sopenharmony_ci		   SCpnt));
174962306a36Sopenharmony_ci		retval = SUCCESS;
175062306a36Sopenharmony_ci		goto out;
175162306a36Sopenharmony_ci	}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	if (ioc->timeouts < -1)
175462306a36Sopenharmony_ci		ioc->timeouts++;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	if (mpt_fwfault_debug)
175762306a36Sopenharmony_ci		mpt_halt_firmware(ioc);
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
176062306a36Sopenharmony_ci	 * (the IO to be ABORT'd)
176162306a36Sopenharmony_ci	 *
176262306a36Sopenharmony_ci	 * NOTE: Since we do not byteswap MsgContext, we do not
176362306a36Sopenharmony_ci	 *	 swap it here either.  It is an opaque cookie to
176462306a36Sopenharmony_ci	 *	 the controller, so it does not matter. -DaveM
176562306a36Sopenharmony_ci	 */
176662306a36Sopenharmony_ci	mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
176762306a36Sopenharmony_ci	ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
176862306a36Sopenharmony_ci	retval = mptscsih_IssueTaskMgmt(hd,
176962306a36Sopenharmony_ci			 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
177062306a36Sopenharmony_ci			 vdevice->vtarget->channel,
177162306a36Sopenharmony_ci			 vdevice->vtarget->id, vdevice->lun,
177262306a36Sopenharmony_ci			 ctx2abort, mptscsih_get_tm_timeout(ioc));
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) {
177562306a36Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
177662306a36Sopenharmony_ci		    "task abort: command still in active list! (sc=%p)\n",
177762306a36Sopenharmony_ci		    ioc->name, SCpnt));
177862306a36Sopenharmony_ci		retval = FAILED;
177962306a36Sopenharmony_ci	} else {
178062306a36Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
178162306a36Sopenharmony_ci		    "task abort: command cleared from active list! (sc=%p)\n",
178262306a36Sopenharmony_ci		    ioc->name, SCpnt));
178362306a36Sopenharmony_ci		retval = SUCCESS;
178462306a36Sopenharmony_ci	}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci out:
178762306a36Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n",
178862306a36Sopenharmony_ci	    ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,
178962306a36Sopenharmony_ci	    SCpnt);
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	return retval;
179262306a36Sopenharmony_ci}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
179562306a36Sopenharmony_ci/**
179662306a36Sopenharmony_ci *	mptscsih_dev_reset - Perform a SCSI TARGET_RESET!  new_eh variant
179762306a36Sopenharmony_ci *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
179862306a36Sopenharmony_ci *
179962306a36Sopenharmony_ci *	(linux scsi_host_template.eh_dev_reset_handler routine)
180062306a36Sopenharmony_ci *
180162306a36Sopenharmony_ci *	Returns SUCCESS or FAILED.
180262306a36Sopenharmony_ci **/
180362306a36Sopenharmony_ciint
180462306a36Sopenharmony_cimptscsih_dev_reset(struct scsi_cmnd * SCpnt)
180562306a36Sopenharmony_ci{
180662306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd;
180762306a36Sopenharmony_ci	int		 retval;
180862306a36Sopenharmony_ci	VirtDevice	 *vdevice;
180962306a36Sopenharmony_ci	MPT_ADAPTER	*ioc;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	/* If we can't locate our host adapter structure, return FAILED status.
181262306a36Sopenharmony_ci	 */
181362306a36Sopenharmony_ci	if ((hd = shost_priv(SCpnt->device->host)) == NULL){
181462306a36Sopenharmony_ci		printk(KERN_ERR MYNAM ": target reset: "
181562306a36Sopenharmony_ci		   "Can't locate host! (sc=%p)\n", SCpnt);
181662306a36Sopenharmony_ci		return FAILED;
181762306a36Sopenharmony_ci	}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	ioc = hd->ioc;
182062306a36Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
182162306a36Sopenharmony_ci	       ioc->name, SCpnt);
182262306a36Sopenharmony_ci	scsi_print_command(SCpnt);
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	vdevice = SCpnt->device->hostdata;
182562306a36Sopenharmony_ci	if (!vdevice || !vdevice->vtarget) {
182662306a36Sopenharmony_ci		retval = 0;
182762306a36Sopenharmony_ci		goto out;
182862306a36Sopenharmony_ci	}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	/* Target reset to hidden raid component is not supported
183162306a36Sopenharmony_ci	 */
183262306a36Sopenharmony_ci	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
183362306a36Sopenharmony_ci		retval = FAILED;
183462306a36Sopenharmony_ci		goto out;
183562306a36Sopenharmony_ci	}
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	retval = mptscsih_IssueTaskMgmt(hd,
183862306a36Sopenharmony_ci				MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
183962306a36Sopenharmony_ci				vdevice->vtarget->channel,
184062306a36Sopenharmony_ci				vdevice->vtarget->id, 0, 0,
184162306a36Sopenharmony_ci				mptscsih_get_tm_timeout(ioc));
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci out:
184462306a36Sopenharmony_ci	printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
184562306a36Sopenharmony_ci	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	if (retval == 0)
184862306a36Sopenharmony_ci		return SUCCESS;
184962306a36Sopenharmony_ci	else
185062306a36Sopenharmony_ci		return FAILED;
185162306a36Sopenharmony_ci}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
185562306a36Sopenharmony_ci/**
185662306a36Sopenharmony_ci *	mptscsih_bus_reset - Perform a SCSI BUS_RESET!	new_eh variant
185762306a36Sopenharmony_ci *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
185862306a36Sopenharmony_ci *
185962306a36Sopenharmony_ci *	(linux scsi_host_template.eh_bus_reset_handler routine)
186062306a36Sopenharmony_ci *
186162306a36Sopenharmony_ci *	Returns SUCCESS or FAILED.
186262306a36Sopenharmony_ci **/
186362306a36Sopenharmony_ciint
186462306a36Sopenharmony_cimptscsih_bus_reset(struct scsi_cmnd * SCpnt)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd;
186762306a36Sopenharmony_ci	int		 retval;
186862306a36Sopenharmony_ci	VirtDevice	 *vdevice;
186962306a36Sopenharmony_ci	MPT_ADAPTER	*ioc;
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	/* If we can't locate our host adapter structure, return FAILED status.
187262306a36Sopenharmony_ci	 */
187362306a36Sopenharmony_ci	if ((hd = shost_priv(SCpnt->device->host)) == NULL){
187462306a36Sopenharmony_ci		printk(KERN_ERR MYNAM ": bus reset: "
187562306a36Sopenharmony_ci		   "Can't locate host! (sc=%p)\n", SCpnt);
187662306a36Sopenharmony_ci		return FAILED;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	ioc = hd->ioc;
188062306a36Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
188162306a36Sopenharmony_ci	       ioc->name, SCpnt);
188262306a36Sopenharmony_ci	scsi_print_command(SCpnt);
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	if (ioc->timeouts < -1)
188562306a36Sopenharmony_ci		ioc->timeouts++;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	vdevice = SCpnt->device->hostdata;
188862306a36Sopenharmony_ci	if (!vdevice || !vdevice->vtarget)
188962306a36Sopenharmony_ci		return SUCCESS;
189062306a36Sopenharmony_ci	retval = mptscsih_IssueTaskMgmt(hd,
189162306a36Sopenharmony_ci					MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
189262306a36Sopenharmony_ci					vdevice->vtarget->channel, 0, 0, 0,
189362306a36Sopenharmony_ci					mptscsih_get_tm_timeout(ioc));
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
189662306a36Sopenharmony_ci	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	if (retval == 0)
189962306a36Sopenharmony_ci		return SUCCESS;
190062306a36Sopenharmony_ci	else
190162306a36Sopenharmony_ci		return FAILED;
190262306a36Sopenharmony_ci}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
190562306a36Sopenharmony_ci/**
190662306a36Sopenharmony_ci *	mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
190762306a36Sopenharmony_ci *	@SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
190862306a36Sopenharmony_ci *
190962306a36Sopenharmony_ci *	(linux scsi_host_template.eh_host_reset_handler routine)
191062306a36Sopenharmony_ci *
191162306a36Sopenharmony_ci *	Returns SUCCESS or FAILED.
191262306a36Sopenharmony_ci */
191362306a36Sopenharmony_ciint
191462306a36Sopenharmony_cimptscsih_host_reset(struct scsi_cmnd *SCpnt)
191562306a36Sopenharmony_ci{
191662306a36Sopenharmony_ci	MPT_SCSI_HOST *  hd;
191762306a36Sopenharmony_ci	int              status = SUCCESS;
191862306a36Sopenharmony_ci	MPT_ADAPTER	*ioc;
191962306a36Sopenharmony_ci	int		retval;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	/*  If we can't locate the host to reset, then we failed. */
192262306a36Sopenharmony_ci	if ((hd = shost_priv(SCpnt->device->host)) == NULL){
192362306a36Sopenharmony_ci		printk(KERN_ERR MYNAM ": host reset: "
192462306a36Sopenharmony_ci		    "Can't locate host! (sc=%p)\n", SCpnt);
192562306a36Sopenharmony_ci		return FAILED;
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	/* make sure we have no outstanding commands at this stage */
192962306a36Sopenharmony_ci	mptscsih_flush_running_cmds(hd);
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	ioc = hd->ioc;
193262306a36Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
193362306a36Sopenharmony_ci	    ioc->name, SCpnt);
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	/*  If our attempts to reset the host failed, then return a failed
193662306a36Sopenharmony_ci	 *  status.  The host will be taken off line by the SCSI mid-layer.
193762306a36Sopenharmony_ci	 */
193862306a36Sopenharmony_ci	retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
193962306a36Sopenharmony_ci	if (retval < 0)
194062306a36Sopenharmony_ci		status = FAILED;
194162306a36Sopenharmony_ci	else
194262306a36Sopenharmony_ci		status = SUCCESS;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
194562306a36Sopenharmony_ci	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	return status;
194862306a36Sopenharmony_ci}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_cistatic int
195162306a36Sopenharmony_cimptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
195262306a36Sopenharmony_ci	SCSITaskMgmtReply_t *pScsiTmReply)
195362306a36Sopenharmony_ci{
195462306a36Sopenharmony_ci	u16			 iocstatus;
195562306a36Sopenharmony_ci	u32			 termination_count;
195662306a36Sopenharmony_ci	int			 retval;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
195962306a36Sopenharmony_ci		retval = FAILED;
196062306a36Sopenharmony_ci		goto out;
196162306a36Sopenharmony_ci	}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
196662306a36Sopenharmony_ci	termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
196962306a36Sopenharmony_ci	    "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
197062306a36Sopenharmony_ci	    "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
197162306a36Sopenharmony_ci	    "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
197262306a36Sopenharmony_ci	    pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
197362306a36Sopenharmony_ci	    le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
197462306a36Sopenharmony_ci	    termination_count));
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
197762306a36Sopenharmony_ci	    pScsiTmReply->ResponseCode)
197862306a36Sopenharmony_ci		mptscsih_taskmgmt_response_code(ioc,
197962306a36Sopenharmony_ci		    pScsiTmReply->ResponseCode);
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
198262306a36Sopenharmony_ci		retval = 0;
198362306a36Sopenharmony_ci		goto out;
198462306a36Sopenharmony_ci	}
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	retval = FAILED;
198762306a36Sopenharmony_ci	if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
198862306a36Sopenharmony_ci		if (termination_count == 1)
198962306a36Sopenharmony_ci			retval = 0;
199062306a36Sopenharmony_ci		goto out;
199162306a36Sopenharmony_ci	}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
199462306a36Sopenharmony_ci	   iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
199562306a36Sopenharmony_ci		retval = 0;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci out:
199862306a36Sopenharmony_ci	return retval;
199962306a36Sopenharmony_ci}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
200262306a36Sopenharmony_civoid
200362306a36Sopenharmony_cimptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
200462306a36Sopenharmony_ci{
200562306a36Sopenharmony_ci	char *desc;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	switch (response_code) {
200862306a36Sopenharmony_ci	case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
200962306a36Sopenharmony_ci		desc = "The task completed.";
201062306a36Sopenharmony_ci		break;
201162306a36Sopenharmony_ci	case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
201262306a36Sopenharmony_ci		desc = "The IOC received an invalid frame status.";
201362306a36Sopenharmony_ci		break;
201462306a36Sopenharmony_ci	case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
201562306a36Sopenharmony_ci		desc = "The task type is not supported.";
201662306a36Sopenharmony_ci		break;
201762306a36Sopenharmony_ci	case MPI_SCSITASKMGMT_RSP_TM_FAILED:
201862306a36Sopenharmony_ci		desc = "The requested task failed.";
201962306a36Sopenharmony_ci		break;
202062306a36Sopenharmony_ci	case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
202162306a36Sopenharmony_ci		desc = "The task completed successfully.";
202262306a36Sopenharmony_ci		break;
202362306a36Sopenharmony_ci	case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
202462306a36Sopenharmony_ci		desc = "The LUN request is invalid.";
202562306a36Sopenharmony_ci		break;
202662306a36Sopenharmony_ci	case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
202762306a36Sopenharmony_ci		desc = "The task is in the IOC queue and has not been sent to target.";
202862306a36Sopenharmony_ci		break;
202962306a36Sopenharmony_ci	default:
203062306a36Sopenharmony_ci		desc = "unknown";
203162306a36Sopenharmony_ci		break;
203262306a36Sopenharmony_ci	}
203362306a36Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
203462306a36Sopenharmony_ci		ioc->name, response_code, desc);
203562306a36Sopenharmony_ci}
203662306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
203962306a36Sopenharmony_ci/**
204062306a36Sopenharmony_ci *	mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
204162306a36Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
204262306a36Sopenharmony_ci *	@mf: Pointer to SCSI task mgmt request frame
204362306a36Sopenharmony_ci *	@mr: Pointer to SCSI task mgmt reply frame
204462306a36Sopenharmony_ci *
204562306a36Sopenharmony_ci *	This routine is called from mptbase.c::mpt_interrupt() at the completion
204662306a36Sopenharmony_ci *	of any SCSI task management request.
204762306a36Sopenharmony_ci *	This routine is registered with the MPT (base) driver at driver
204862306a36Sopenharmony_ci *	load/init time via the mpt_register() API call.
204962306a36Sopenharmony_ci *
205062306a36Sopenharmony_ci *	Returns 1 indicating alloc'd request frame ptr should be freed.
205162306a36Sopenharmony_ci **/
205262306a36Sopenharmony_ciint
205362306a36Sopenharmony_cimptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
205462306a36Sopenharmony_ci	MPT_FRAME_HDR *mr)
205562306a36Sopenharmony_ci{
205662306a36Sopenharmony_ci	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
205762306a36Sopenharmony_ci		"TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	if (!mr)
206262306a36Sopenharmony_ci		goto out;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
206562306a36Sopenharmony_ci	memcpy(ioc->taskmgmt_cmds.reply, mr,
206662306a36Sopenharmony_ci	    min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
206762306a36Sopenharmony_ci out:
206862306a36Sopenharmony_ci	if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
206962306a36Sopenharmony_ci		mpt_clear_taskmgmt_in_progress_flag(ioc);
207062306a36Sopenharmony_ci		ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
207162306a36Sopenharmony_ci		complete(&ioc->taskmgmt_cmds.done);
207262306a36Sopenharmony_ci		if (ioc->bus_type == SAS)
207362306a36Sopenharmony_ci			ioc->schedule_target_reset(ioc);
207462306a36Sopenharmony_ci		return 1;
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci	return 0;
207762306a36Sopenharmony_ci}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
208062306a36Sopenharmony_ci/*
208162306a36Sopenharmony_ci *	This is anyones guess quite frankly.
208262306a36Sopenharmony_ci */
208362306a36Sopenharmony_ciint
208462306a36Sopenharmony_cimptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
208562306a36Sopenharmony_ci		sector_t capacity, int geom[])
208662306a36Sopenharmony_ci{
208762306a36Sopenharmony_ci	int		heads;
208862306a36Sopenharmony_ci	int		sectors;
208962306a36Sopenharmony_ci	sector_t	cylinders;
209062306a36Sopenharmony_ci	ulong 		dummy;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	heads = 64;
209362306a36Sopenharmony_ci	sectors = 32;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	dummy = heads * sectors;
209662306a36Sopenharmony_ci	cylinders = capacity;
209762306a36Sopenharmony_ci	sector_div(cylinders,dummy);
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	/*
210062306a36Sopenharmony_ci	 * Handle extended translation size for logical drives
210162306a36Sopenharmony_ci	 * > 1Gb
210262306a36Sopenharmony_ci	 */
210362306a36Sopenharmony_ci	if ((ulong)capacity >= 0x200000) {
210462306a36Sopenharmony_ci		heads = 255;
210562306a36Sopenharmony_ci		sectors = 63;
210662306a36Sopenharmony_ci		dummy = heads * sectors;
210762306a36Sopenharmony_ci		cylinders = capacity;
210862306a36Sopenharmony_ci		sector_div(cylinders,dummy);
210962306a36Sopenharmony_ci	}
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	/* return result */
211262306a36Sopenharmony_ci	geom[0] = heads;
211362306a36Sopenharmony_ci	geom[1] = sectors;
211462306a36Sopenharmony_ci	geom[2] = cylinders;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	return 0;
211762306a36Sopenharmony_ci}
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci/* Search IOC page 3 to determine if this is hidden physical disk
212062306a36Sopenharmony_ci *
212162306a36Sopenharmony_ci */
212262306a36Sopenharmony_ciint
212362306a36Sopenharmony_cimptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
212462306a36Sopenharmony_ci{
212562306a36Sopenharmony_ci	struct inactive_raid_component_info *component_info;
212662306a36Sopenharmony_ci	int i, j;
212762306a36Sopenharmony_ci	RaidPhysDiskPage1_t *phys_disk;
212862306a36Sopenharmony_ci	int rc = 0;
212962306a36Sopenharmony_ci	int num_paths;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	if (!ioc->raid_data.pIocPg3)
213262306a36Sopenharmony_ci		goto out;
213362306a36Sopenharmony_ci	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
213462306a36Sopenharmony_ci		if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
213562306a36Sopenharmony_ci		    (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
213662306a36Sopenharmony_ci			rc = 1;
213762306a36Sopenharmony_ci			goto out;
213862306a36Sopenharmony_ci		}
213962306a36Sopenharmony_ci	}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	if (ioc->bus_type != SAS)
214262306a36Sopenharmony_ci		goto out;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	/*
214562306a36Sopenharmony_ci	 * Check if dual path
214662306a36Sopenharmony_ci	 */
214762306a36Sopenharmony_ci	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
214862306a36Sopenharmony_ci		num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
214962306a36Sopenharmony_ci		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
215062306a36Sopenharmony_ci		if (num_paths < 2)
215162306a36Sopenharmony_ci			continue;
215262306a36Sopenharmony_ci		phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
215362306a36Sopenharmony_ci		   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
215462306a36Sopenharmony_ci		if (!phys_disk)
215562306a36Sopenharmony_ci			continue;
215662306a36Sopenharmony_ci		if ((mpt_raid_phys_disk_pg1(ioc,
215762306a36Sopenharmony_ci		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
215862306a36Sopenharmony_ci		    phys_disk))) {
215962306a36Sopenharmony_ci			kfree(phys_disk);
216062306a36Sopenharmony_ci			continue;
216162306a36Sopenharmony_ci		}
216262306a36Sopenharmony_ci		for (j = 0; j < num_paths; j++) {
216362306a36Sopenharmony_ci			if ((phys_disk->Path[j].Flags &
216462306a36Sopenharmony_ci			    MPI_RAID_PHYSDISK1_FLAG_INVALID))
216562306a36Sopenharmony_ci				continue;
216662306a36Sopenharmony_ci			if ((phys_disk->Path[j].Flags &
216762306a36Sopenharmony_ci			    MPI_RAID_PHYSDISK1_FLAG_BROKEN))
216862306a36Sopenharmony_ci				continue;
216962306a36Sopenharmony_ci			if ((id == phys_disk->Path[j].PhysDiskID) &&
217062306a36Sopenharmony_ci			    (channel == phys_disk->Path[j].PhysDiskBus)) {
217162306a36Sopenharmony_ci				rc = 1;
217262306a36Sopenharmony_ci				kfree(phys_disk);
217362306a36Sopenharmony_ci				goto out;
217462306a36Sopenharmony_ci			}
217562306a36Sopenharmony_ci		}
217662306a36Sopenharmony_ci		kfree(phys_disk);
217762306a36Sopenharmony_ci	}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	/*
218162306a36Sopenharmony_ci	 * Check inactive list for matching phys disks
218262306a36Sopenharmony_ci	 */
218362306a36Sopenharmony_ci	if (list_empty(&ioc->raid_data.inactive_list))
218462306a36Sopenharmony_ci		goto out;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	mutex_lock(&ioc->raid_data.inactive_list_mutex);
218762306a36Sopenharmony_ci	list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
218862306a36Sopenharmony_ci	    list) {
218962306a36Sopenharmony_ci		if ((component_info->d.PhysDiskID == id) &&
219062306a36Sopenharmony_ci		    (component_info->d.PhysDiskBus == channel))
219162306a36Sopenharmony_ci			rc = 1;
219262306a36Sopenharmony_ci	}
219362306a36Sopenharmony_ci	mutex_unlock(&ioc->raid_data.inactive_list_mutex);
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci out:
219662306a36Sopenharmony_ci	return rc;
219762306a36Sopenharmony_ci}
219862306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_is_phys_disk);
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ciu8
220162306a36Sopenharmony_cimptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
220262306a36Sopenharmony_ci{
220362306a36Sopenharmony_ci	struct inactive_raid_component_info *component_info;
220462306a36Sopenharmony_ci	int i, j;
220562306a36Sopenharmony_ci	RaidPhysDiskPage1_t *phys_disk;
220662306a36Sopenharmony_ci	int rc = -ENXIO;
220762306a36Sopenharmony_ci	int num_paths;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	if (!ioc->raid_data.pIocPg3)
221062306a36Sopenharmony_ci		goto out;
221162306a36Sopenharmony_ci	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
221262306a36Sopenharmony_ci		if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
221362306a36Sopenharmony_ci		    (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
221462306a36Sopenharmony_ci			rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
221562306a36Sopenharmony_ci			goto out;
221662306a36Sopenharmony_ci		}
221762306a36Sopenharmony_ci	}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	if (ioc->bus_type != SAS)
222062306a36Sopenharmony_ci		goto out;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	/*
222362306a36Sopenharmony_ci	 * Check if dual path
222462306a36Sopenharmony_ci	 */
222562306a36Sopenharmony_ci	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
222662306a36Sopenharmony_ci		num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
222762306a36Sopenharmony_ci		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
222862306a36Sopenharmony_ci		if (num_paths < 2)
222962306a36Sopenharmony_ci			continue;
223062306a36Sopenharmony_ci		phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
223162306a36Sopenharmony_ci		   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
223262306a36Sopenharmony_ci		if (!phys_disk)
223362306a36Sopenharmony_ci			continue;
223462306a36Sopenharmony_ci		if ((mpt_raid_phys_disk_pg1(ioc,
223562306a36Sopenharmony_ci		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
223662306a36Sopenharmony_ci		    phys_disk))) {
223762306a36Sopenharmony_ci			kfree(phys_disk);
223862306a36Sopenharmony_ci			continue;
223962306a36Sopenharmony_ci		}
224062306a36Sopenharmony_ci		for (j = 0; j < num_paths; j++) {
224162306a36Sopenharmony_ci			if ((phys_disk->Path[j].Flags &
224262306a36Sopenharmony_ci			    MPI_RAID_PHYSDISK1_FLAG_INVALID))
224362306a36Sopenharmony_ci				continue;
224462306a36Sopenharmony_ci			if ((phys_disk->Path[j].Flags &
224562306a36Sopenharmony_ci			    MPI_RAID_PHYSDISK1_FLAG_BROKEN))
224662306a36Sopenharmony_ci				continue;
224762306a36Sopenharmony_ci			if ((id == phys_disk->Path[j].PhysDiskID) &&
224862306a36Sopenharmony_ci			    (channel == phys_disk->Path[j].PhysDiskBus)) {
224962306a36Sopenharmony_ci				rc = phys_disk->PhysDiskNum;
225062306a36Sopenharmony_ci				kfree(phys_disk);
225162306a36Sopenharmony_ci				goto out;
225262306a36Sopenharmony_ci			}
225362306a36Sopenharmony_ci		}
225462306a36Sopenharmony_ci		kfree(phys_disk);
225562306a36Sopenharmony_ci	}
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	/*
225862306a36Sopenharmony_ci	 * Check inactive list for matching phys disks
225962306a36Sopenharmony_ci	 */
226062306a36Sopenharmony_ci	if (list_empty(&ioc->raid_data.inactive_list))
226162306a36Sopenharmony_ci		goto out;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	mutex_lock(&ioc->raid_data.inactive_list_mutex);
226462306a36Sopenharmony_ci	list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
226562306a36Sopenharmony_ci	    list) {
226662306a36Sopenharmony_ci		if ((component_info->d.PhysDiskID == id) &&
226762306a36Sopenharmony_ci		    (component_info->d.PhysDiskBus == channel))
226862306a36Sopenharmony_ci			rc = component_info->d.PhysDiskNum;
226962306a36Sopenharmony_ci	}
227062306a36Sopenharmony_ci	mutex_unlock(&ioc->raid_data.inactive_list_mutex);
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci out:
227362306a36Sopenharmony_ci	return rc;
227462306a36Sopenharmony_ci}
227562306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_raid_id_to_num);
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci/*
227862306a36Sopenharmony_ci *	OS entry point to allow for host driver to free allocated memory
227962306a36Sopenharmony_ci *	Called if no device present or device being unloaded
228062306a36Sopenharmony_ci */
228162306a36Sopenharmony_civoid
228262306a36Sopenharmony_cimptscsih_slave_destroy(struct scsi_device *sdev)
228362306a36Sopenharmony_ci{
228462306a36Sopenharmony_ci	struct Scsi_Host	*host = sdev->host;
228562306a36Sopenharmony_ci	MPT_SCSI_HOST		*hd = shost_priv(host);
228662306a36Sopenharmony_ci	VirtTarget		*vtarget;
228762306a36Sopenharmony_ci	VirtDevice		*vdevice;
228862306a36Sopenharmony_ci	struct scsi_target 	*starget;
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	starget = scsi_target(sdev);
229162306a36Sopenharmony_ci	vtarget = starget->hostdata;
229262306a36Sopenharmony_ci	vdevice = sdev->hostdata;
229362306a36Sopenharmony_ci	if (!vdevice)
229462306a36Sopenharmony_ci		return;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	mptscsih_search_running_cmds(hd, vdevice);
229762306a36Sopenharmony_ci	vtarget->num_luns--;
229862306a36Sopenharmony_ci	mptscsih_synchronize_cache(hd, vdevice);
229962306a36Sopenharmony_ci	kfree(vdevice);
230062306a36Sopenharmony_ci	sdev->hostdata = NULL;
230162306a36Sopenharmony_ci}
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
230462306a36Sopenharmony_ci/*
230562306a36Sopenharmony_ci *	mptscsih_change_queue_depth - This function will set a devices queue depth
230662306a36Sopenharmony_ci *	@sdev: per scsi_device pointer
230762306a36Sopenharmony_ci *	@qdepth: requested queue depth
230862306a36Sopenharmony_ci *
230962306a36Sopenharmony_ci *	Adding support for new 'change_queue_depth' api.
231062306a36Sopenharmony_ci*/
231162306a36Sopenharmony_ciint
231262306a36Sopenharmony_cimptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
231362306a36Sopenharmony_ci{
231462306a36Sopenharmony_ci	MPT_SCSI_HOST		*hd = shost_priv(sdev->host);
231562306a36Sopenharmony_ci	VirtTarget 		*vtarget;
231662306a36Sopenharmony_ci	struct scsi_target 	*starget;
231762306a36Sopenharmony_ci	int			max_depth;
231862306a36Sopenharmony_ci	MPT_ADAPTER		*ioc = hd->ioc;
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci	starget = scsi_target(sdev);
232162306a36Sopenharmony_ci	vtarget = starget->hostdata;
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	if (ioc->bus_type == SPI) {
232462306a36Sopenharmony_ci		if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
232562306a36Sopenharmony_ci			max_depth = 1;
232662306a36Sopenharmony_ci		else if (sdev->type == TYPE_DISK &&
232762306a36Sopenharmony_ci			 vtarget->minSyncFactor <= MPT_ULTRA160)
232862306a36Sopenharmony_ci			max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
232962306a36Sopenharmony_ci		else
233062306a36Sopenharmony_ci			max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
233162306a36Sopenharmony_ci	} else
233262306a36Sopenharmony_ci		 max_depth = ioc->sh->can_queue;
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	if (!sdev->tagged_supported)
233562306a36Sopenharmony_ci		max_depth = 1;
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	if (qdepth > max_depth)
233862306a36Sopenharmony_ci		qdepth = max_depth;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	return scsi_change_queue_depth(sdev, qdepth);
234162306a36Sopenharmony_ci}
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci/*
234462306a36Sopenharmony_ci *	OS entry point to adjust the queue_depths on a per-device basis.
234562306a36Sopenharmony_ci *	Called once per device the bus scan. Use it to force the queue_depth
234662306a36Sopenharmony_ci *	member to 1 if a device does not support Q tags.
234762306a36Sopenharmony_ci *	Return non-zero if fails.
234862306a36Sopenharmony_ci */
234962306a36Sopenharmony_ciint
235062306a36Sopenharmony_cimptscsih_slave_configure(struct scsi_device *sdev)
235162306a36Sopenharmony_ci{
235262306a36Sopenharmony_ci	struct Scsi_Host	*sh = sdev->host;
235362306a36Sopenharmony_ci	VirtTarget		*vtarget;
235462306a36Sopenharmony_ci	VirtDevice		*vdevice;
235562306a36Sopenharmony_ci	struct scsi_target 	*starget;
235662306a36Sopenharmony_ci	MPT_SCSI_HOST		*hd = shost_priv(sh);
235762306a36Sopenharmony_ci	MPT_ADAPTER		*ioc = hd->ioc;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	starget = scsi_target(sdev);
236062306a36Sopenharmony_ci	vtarget = starget->hostdata;
236162306a36Sopenharmony_ci	vdevice = sdev->hostdata;
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
236462306a36Sopenharmony_ci		"device @ %p, channel=%d, id=%d, lun=%llu\n",
236562306a36Sopenharmony_ci		ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
236662306a36Sopenharmony_ci	if (ioc->bus_type == SPI)
236762306a36Sopenharmony_ci		dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
236862306a36Sopenharmony_ci		    "sdtr %d wdtr %d ppr %d inq length=%d\n",
236962306a36Sopenharmony_ci		    ioc->name, sdev->sdtr, sdev->wdtr,
237062306a36Sopenharmony_ci		    sdev->ppr, sdev->inquiry_len));
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	vdevice->configured_lun = 1;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
237562306a36Sopenharmony_ci		"Queue depth=%d, tflags=%x\n",
237662306a36Sopenharmony_ci		ioc->name, sdev->queue_depth, vtarget->tflags));
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	if (ioc->bus_type == SPI)
237962306a36Sopenharmony_ci		dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
238062306a36Sopenharmony_ci		    "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
238162306a36Sopenharmony_ci		    ioc->name, vtarget->negoFlags, vtarget->maxOffset,
238262306a36Sopenharmony_ci		    vtarget->minSyncFactor));
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
238562306a36Sopenharmony_ci	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
238662306a36Sopenharmony_ci		"tagged %d, simple %d\n",
238762306a36Sopenharmony_ci		ioc->name,sdev->tagged_supported, sdev->simple_tags));
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci	blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	return 0;
239262306a36Sopenharmony_ci}
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
239562306a36Sopenharmony_ci/*
239662306a36Sopenharmony_ci *  Private routines...
239762306a36Sopenharmony_ci */
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
240062306a36Sopenharmony_ci/* Utility function to copy sense data from the scsi_cmnd buffer
240162306a36Sopenharmony_ci * to the FC and SCSI target structures.
240262306a36Sopenharmony_ci *
240362306a36Sopenharmony_ci */
240462306a36Sopenharmony_cistatic void
240562306a36Sopenharmony_cimptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
240662306a36Sopenharmony_ci{
240762306a36Sopenharmony_ci	VirtDevice	*vdevice;
240862306a36Sopenharmony_ci	SCSIIORequest_t	*pReq;
240962306a36Sopenharmony_ci	u32		 sense_count = le32_to_cpu(pScsiReply->SenseCount);
241062306a36Sopenharmony_ci	MPT_ADAPTER 	*ioc = hd->ioc;
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	/* Get target structure
241362306a36Sopenharmony_ci	 */
241462306a36Sopenharmony_ci	pReq = (SCSIIORequest_t *) mf;
241562306a36Sopenharmony_ci	vdevice = sc->device->hostdata;
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	if (sense_count) {
241862306a36Sopenharmony_ci		u8 *sense_data;
241962306a36Sopenharmony_ci		int req_index;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci		/* Copy the sense received into the scsi command block. */
242262306a36Sopenharmony_ci		req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
242362306a36Sopenharmony_ci		sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
242462306a36Sopenharmony_ci		memcpy(sc->sense_buffer, sense_data, MPT_SENSE_BUFFER_ALLOC);
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci		/* Log SMART data (asc = 0x5D, non-IM case only) if required.
242762306a36Sopenharmony_ci		 */
242862306a36Sopenharmony_ci		if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
242962306a36Sopenharmony_ci			if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
243062306a36Sopenharmony_ci				int idx;
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci				idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
243362306a36Sopenharmony_ci				ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
243462306a36Sopenharmony_ci				ioc->events[idx].eventContext = ioc->eventContext;
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci				ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
243762306a36Sopenharmony_ci					(MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
243862306a36Sopenharmony_ci					(sc->device->channel << 8) | sc->device->id;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci				ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci				ioc->eventContext++;
244362306a36Sopenharmony_ci				if (ioc->pcidev->vendor ==
244462306a36Sopenharmony_ci				    PCI_VENDOR_ID_IBM) {
244562306a36Sopenharmony_ci					mptscsih_issue_sep_command(ioc,
244662306a36Sopenharmony_ci					    vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
244762306a36Sopenharmony_ci					vdevice->vtarget->tflags |=
244862306a36Sopenharmony_ci					    MPT_TARGET_FLAGS_LED_ON;
244962306a36Sopenharmony_ci				}
245062306a36Sopenharmony_ci			}
245162306a36Sopenharmony_ci		}
245262306a36Sopenharmony_ci	} else {
245362306a36Sopenharmony_ci		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
245462306a36Sopenharmony_ci				ioc->name));
245562306a36Sopenharmony_ci	}
245662306a36Sopenharmony_ci}
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci/**
245962306a36Sopenharmony_ci * mptscsih_get_scsi_lookup - retrieves scmd entry
246062306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure
246162306a36Sopenharmony_ci * @i: index into the array
246262306a36Sopenharmony_ci *
246362306a36Sopenharmony_ci * Returns the scsi_cmd pointer
246462306a36Sopenharmony_ci */
246562306a36Sopenharmony_cistruct scsi_cmnd *
246662306a36Sopenharmony_cimptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
246762306a36Sopenharmony_ci{
246862306a36Sopenharmony_ci	unsigned long	flags;
246962306a36Sopenharmony_ci	struct scsi_cmnd *scmd;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
247262306a36Sopenharmony_ci	scmd = ioc->ScsiLookup[i];
247362306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	return scmd;
247662306a36Sopenharmony_ci}
247762306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_get_scsi_lookup);
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci/**
248062306a36Sopenharmony_ci * mptscsih_getclear_scsi_lookup -  retrieves and clears scmd entry from ScsiLookup[] array list
248162306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure
248262306a36Sopenharmony_ci * @i: index into the array
248362306a36Sopenharmony_ci *
248462306a36Sopenharmony_ci * Returns the scsi_cmd pointer
248562306a36Sopenharmony_ci *
248662306a36Sopenharmony_ci **/
248762306a36Sopenharmony_cistatic struct scsi_cmnd *
248862306a36Sopenharmony_cimptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
248962306a36Sopenharmony_ci{
249062306a36Sopenharmony_ci	unsigned long	flags;
249162306a36Sopenharmony_ci	struct scsi_cmnd *scmd;
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
249462306a36Sopenharmony_ci	scmd = ioc->ScsiLookup[i];
249562306a36Sopenharmony_ci	ioc->ScsiLookup[i] = NULL;
249662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	return scmd;
249962306a36Sopenharmony_ci}
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci/**
250262306a36Sopenharmony_ci * mptscsih_set_scsi_lookup - write a scmd entry into the ScsiLookup[] array list
250362306a36Sopenharmony_ci *
250462306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure
250562306a36Sopenharmony_ci * @i: index into the array
250662306a36Sopenharmony_ci * @scmd: scsi_cmnd pointer
250762306a36Sopenharmony_ci *
250862306a36Sopenharmony_ci **/
250962306a36Sopenharmony_cistatic void
251062306a36Sopenharmony_cimptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
251162306a36Sopenharmony_ci{
251262306a36Sopenharmony_ci	unsigned long	flags;
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
251562306a36Sopenharmony_ci	ioc->ScsiLookup[i] = scmd;
251662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
251762306a36Sopenharmony_ci}
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci/**
252062306a36Sopenharmony_ci * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
252162306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure
252262306a36Sopenharmony_ci * @sc: scsi_cmnd pointer
252362306a36Sopenharmony_ci */
252462306a36Sopenharmony_cistatic int
252562306a36Sopenharmony_ciSCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
252662306a36Sopenharmony_ci{
252762306a36Sopenharmony_ci	unsigned long	flags;
252862306a36Sopenharmony_ci	int i, index=-1;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
253162306a36Sopenharmony_ci	for (i = 0; i < ioc->req_depth; i++) {
253262306a36Sopenharmony_ci		if (ioc->ScsiLookup[i] == sc) {
253362306a36Sopenharmony_ci			index = i;
253462306a36Sopenharmony_ci			goto out;
253562306a36Sopenharmony_ci		}
253662306a36Sopenharmony_ci	}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci out:
253962306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
254062306a36Sopenharmony_ci	return index;
254162306a36Sopenharmony_ci}
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
254462306a36Sopenharmony_ciint
254562306a36Sopenharmony_cimptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
254662306a36Sopenharmony_ci{
254762306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd;
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
255062306a36Sopenharmony_ci		return 0;
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_ci	hd = shost_priv(ioc->sh);
255362306a36Sopenharmony_ci	switch (reset_phase) {
255462306a36Sopenharmony_ci	case MPT_IOC_SETUP_RESET:
255562306a36Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
255662306a36Sopenharmony_ci		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
255762306a36Sopenharmony_ci		break;
255862306a36Sopenharmony_ci	case MPT_IOC_PRE_RESET:
255962306a36Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
256062306a36Sopenharmony_ci		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
256162306a36Sopenharmony_ci		mptscsih_flush_running_cmds(hd);
256262306a36Sopenharmony_ci		break;
256362306a36Sopenharmony_ci	case MPT_IOC_POST_RESET:
256462306a36Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
256562306a36Sopenharmony_ci		    "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
256662306a36Sopenharmony_ci		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
256762306a36Sopenharmony_ci			ioc->internal_cmds.status |=
256862306a36Sopenharmony_ci				MPT_MGMT_STATUS_DID_IOCRESET;
256962306a36Sopenharmony_ci			complete(&ioc->internal_cmds.done);
257062306a36Sopenharmony_ci		}
257162306a36Sopenharmony_ci		break;
257262306a36Sopenharmony_ci	default:
257362306a36Sopenharmony_ci		break;
257462306a36Sopenharmony_ci	}
257562306a36Sopenharmony_ci	return 1;		/* currently means nothing really */
257662306a36Sopenharmony_ci}
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
257962306a36Sopenharmony_ciint
258062306a36Sopenharmony_cimptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
258162306a36Sopenharmony_ci{
258262306a36Sopenharmony_ci	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
258562306a36Sopenharmony_ci		"MPT event (=%02Xh) routed to SCSI host driver!\n",
258662306a36Sopenharmony_ci		ioc->name, event));
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	if ((event == MPI_EVENT_IOC_BUS_RESET ||
258962306a36Sopenharmony_ci	    event == MPI_EVENT_EXT_BUS_RESET) &&
259062306a36Sopenharmony_ci	    (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
259162306a36Sopenharmony_ci			ioc->soft_resets++;
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	return 1;		/* currently means nothing really */
259462306a36Sopenharmony_ci}
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
259762306a36Sopenharmony_ci/*
259862306a36Sopenharmony_ci *  Bus Scan and Domain Validation functionality ...
259962306a36Sopenharmony_ci */
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
260262306a36Sopenharmony_ci/*
260362306a36Sopenharmony_ci *	mptscsih_scandv_complete - Scan and DV callback routine registered
260462306a36Sopenharmony_ci *	to Fustion MPT (base) driver.
260562306a36Sopenharmony_ci *
260662306a36Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
260762306a36Sopenharmony_ci *	@mf: Pointer to original MPT request frame
260862306a36Sopenharmony_ci *	@mr: Pointer to MPT reply frame (NULL if TurboReply)
260962306a36Sopenharmony_ci *
261062306a36Sopenharmony_ci *	This routine is called from mpt.c::mpt_interrupt() at the completion
261162306a36Sopenharmony_ci *	of any SCSI IO request.
261262306a36Sopenharmony_ci *	This routine is registered with the Fusion MPT (base) driver at driver
261362306a36Sopenharmony_ci *	load/init time via the mpt_register() API call.
261462306a36Sopenharmony_ci *
261562306a36Sopenharmony_ci *	Returns 1 indicating alloc'd request frame ptr should be freed.
261662306a36Sopenharmony_ci *
261762306a36Sopenharmony_ci *	Remark: Sets a completion code and (possibly) saves sense data
261862306a36Sopenharmony_ci *	in the IOC member localReply structure.
261962306a36Sopenharmony_ci *	Used ONLY for DV and other internal commands.
262062306a36Sopenharmony_ci */
262162306a36Sopenharmony_ciint
262262306a36Sopenharmony_cimptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
262362306a36Sopenharmony_ci				MPT_FRAME_HDR *reply)
262462306a36Sopenharmony_ci{
262562306a36Sopenharmony_ci	SCSIIORequest_t *pReq;
262662306a36Sopenharmony_ci	SCSIIOReply_t	*pReply;
262762306a36Sopenharmony_ci	u8		 cmd;
262862306a36Sopenharmony_ci	u16		 req_idx;
262962306a36Sopenharmony_ci	u8	*sense_data;
263062306a36Sopenharmony_ci	int		 sz;
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci	ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
263362306a36Sopenharmony_ci	ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
263462306a36Sopenharmony_ci	if (!reply)
263562306a36Sopenharmony_ci		goto out;
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci	pReply = (SCSIIOReply_t *) reply;
263862306a36Sopenharmony_ci	pReq = (SCSIIORequest_t *) req;
263962306a36Sopenharmony_ci	ioc->internal_cmds.completion_code =
264062306a36Sopenharmony_ci	    mptscsih_get_completion_code(ioc, req, reply);
264162306a36Sopenharmony_ci	ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
264262306a36Sopenharmony_ci	memcpy(ioc->internal_cmds.reply, reply,
264362306a36Sopenharmony_ci	    min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
264462306a36Sopenharmony_ci	cmd = reply->u.hdr.Function;
264562306a36Sopenharmony_ci	if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
264662306a36Sopenharmony_ci	    (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
264762306a36Sopenharmony_ci	    (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
264862306a36Sopenharmony_ci		req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
264962306a36Sopenharmony_ci		sense_data = ((u8 *)ioc->sense_buf_pool +
265062306a36Sopenharmony_ci		    (req_idx * MPT_SENSE_BUFFER_ALLOC));
265162306a36Sopenharmony_ci		sz = min_t(int, pReq->SenseBufferLength,
265262306a36Sopenharmony_ci		    MPT_SENSE_BUFFER_ALLOC);
265362306a36Sopenharmony_ci		memcpy(ioc->internal_cmds.sense, sense_data, sz);
265462306a36Sopenharmony_ci	}
265562306a36Sopenharmony_ci out:
265662306a36Sopenharmony_ci	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
265762306a36Sopenharmony_ci		return 0;
265862306a36Sopenharmony_ci	ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
265962306a36Sopenharmony_ci	complete(&ioc->internal_cmds.done);
266062306a36Sopenharmony_ci	return 1;
266162306a36Sopenharmony_ci}
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci/**
266562306a36Sopenharmony_ci *	mptscsih_get_completion_code - get completion code from MPT request
266662306a36Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
266762306a36Sopenharmony_ci *	@req: Pointer to original MPT request frame
266862306a36Sopenharmony_ci *	@reply: Pointer to MPT reply frame (NULL if TurboReply)
266962306a36Sopenharmony_ci *
267062306a36Sopenharmony_ci **/
267162306a36Sopenharmony_cistatic int
267262306a36Sopenharmony_cimptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
267362306a36Sopenharmony_ci				MPT_FRAME_HDR *reply)
267462306a36Sopenharmony_ci{
267562306a36Sopenharmony_ci	SCSIIOReply_t	*pReply;
267662306a36Sopenharmony_ci	MpiRaidActionReply_t *pr;
267762306a36Sopenharmony_ci	u8		 scsi_status;
267862306a36Sopenharmony_ci	u16		 status;
267962306a36Sopenharmony_ci	int		 completion_code;
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	pReply = (SCSIIOReply_t *)reply;
268262306a36Sopenharmony_ci	status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
268362306a36Sopenharmony_ci	scsi_status = pReply->SCSIStatus;
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
268662306a36Sopenharmony_ci	    "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
268762306a36Sopenharmony_ci	    "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
268862306a36Sopenharmony_ci	    scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	switch (status) {
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
269362306a36Sopenharmony_ci		completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
269462306a36Sopenharmony_ci		break;
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
269762306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
269862306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
269962306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
270062306a36Sopenharmony_ci		completion_code = MPT_SCANDV_DID_RESET;
270162306a36Sopenharmony_ci		break;
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	case MPI_IOCSTATUS_BUSY:
270462306a36Sopenharmony_ci	case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
270562306a36Sopenharmony_ci		completion_code = MPT_SCANDV_BUSY;
270662306a36Sopenharmony_ci		break;
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
270962306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
271062306a36Sopenharmony_ci	case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
271162306a36Sopenharmony_ci		if (pReply->Function == MPI_FUNCTION_CONFIG) {
271262306a36Sopenharmony_ci			completion_code = MPT_SCANDV_GOOD;
271362306a36Sopenharmony_ci		} else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
271462306a36Sopenharmony_ci			pr = (MpiRaidActionReply_t *)reply;
271562306a36Sopenharmony_ci			if (le16_to_cpu(pr->ActionStatus) ==
271662306a36Sopenharmony_ci				MPI_RAID_ACTION_ASTATUS_SUCCESS)
271762306a36Sopenharmony_ci				completion_code = MPT_SCANDV_GOOD;
271862306a36Sopenharmony_ci			else
271962306a36Sopenharmony_ci				completion_code = MPT_SCANDV_SOME_ERROR;
272062306a36Sopenharmony_ci		} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
272162306a36Sopenharmony_ci			completion_code = MPT_SCANDV_SENSE;
272262306a36Sopenharmony_ci		else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
272362306a36Sopenharmony_ci			if (req->u.scsireq.CDB[0] == INQUIRY)
272462306a36Sopenharmony_ci				completion_code = MPT_SCANDV_ISSUE_SENSE;
272562306a36Sopenharmony_ci			else
272662306a36Sopenharmony_ci				completion_code = MPT_SCANDV_DID_RESET;
272762306a36Sopenharmony_ci		} else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
272862306a36Sopenharmony_ci			completion_code = MPT_SCANDV_DID_RESET;
272962306a36Sopenharmony_ci		else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
273062306a36Sopenharmony_ci			completion_code = MPT_SCANDV_DID_RESET;
273162306a36Sopenharmony_ci		else if (scsi_status == MPI_SCSI_STATUS_BUSY)
273262306a36Sopenharmony_ci			completion_code = MPT_SCANDV_BUSY;
273362306a36Sopenharmony_ci		else
273462306a36Sopenharmony_ci			completion_code = MPT_SCANDV_GOOD;
273562306a36Sopenharmony_ci		break;
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
273862306a36Sopenharmony_ci		if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
273962306a36Sopenharmony_ci			completion_code = MPT_SCANDV_DID_RESET;
274062306a36Sopenharmony_ci		else
274162306a36Sopenharmony_ci			completion_code = MPT_SCANDV_SOME_ERROR;
274262306a36Sopenharmony_ci		break;
274362306a36Sopenharmony_ci	default:
274462306a36Sopenharmony_ci		completion_code = MPT_SCANDV_SOME_ERROR;
274562306a36Sopenharmony_ci		break;
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	}	/* switch(status) */
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
275062306a36Sopenharmony_ci	    "  completionCode set to %08xh\n", ioc->name, completion_code));
275162306a36Sopenharmony_ci	return completion_code;
275262306a36Sopenharmony_ci}
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
275562306a36Sopenharmony_ci/**
275662306a36Sopenharmony_ci *	mptscsih_do_cmd - Do internal command.
275762306a36Sopenharmony_ci *	@hd: MPT_SCSI_HOST pointer
275862306a36Sopenharmony_ci *	@io: INTERNAL_CMD pointer.
275962306a36Sopenharmony_ci *
276062306a36Sopenharmony_ci *	Issue the specified internally generated command and do command
276162306a36Sopenharmony_ci *	specific cleanup. For bus scan / DV only.
276262306a36Sopenharmony_ci *	NOTES: If command is Inquiry and status is good,
276362306a36Sopenharmony_ci *	initialize a target structure, save the data
276462306a36Sopenharmony_ci *
276562306a36Sopenharmony_ci *	Remark: Single threaded access only.
276662306a36Sopenharmony_ci *
276762306a36Sopenharmony_ci *	Return:
276862306a36Sopenharmony_ci *		< 0 if an illegal command or no resources
276962306a36Sopenharmony_ci *
277062306a36Sopenharmony_ci *		   0 if good
277162306a36Sopenharmony_ci *
277262306a36Sopenharmony_ci *		 > 0 if command complete but some type of completion error.
277362306a36Sopenharmony_ci */
277462306a36Sopenharmony_cistatic int
277562306a36Sopenharmony_cimptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
277662306a36Sopenharmony_ci{
277762306a36Sopenharmony_ci	MPT_FRAME_HDR	*mf;
277862306a36Sopenharmony_ci	SCSIIORequest_t	*pScsiReq;
277962306a36Sopenharmony_ci	int		 my_idx, ii, dir;
278062306a36Sopenharmony_ci	int		 timeout;
278162306a36Sopenharmony_ci	char		 cmdLen;
278262306a36Sopenharmony_ci	char		 CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
278362306a36Sopenharmony_ci	u8		 cmd = io->cmd;
278462306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
278562306a36Sopenharmony_ci	int		 ret = 0;
278662306a36Sopenharmony_ci	unsigned long	 timeleft;
278762306a36Sopenharmony_ci	unsigned long	 flags;
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_ci	/* don't send internal command during diag reset */
279062306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
279162306a36Sopenharmony_ci	if (ioc->ioc_reset_in_progress) {
279262306a36Sopenharmony_ci		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
279362306a36Sopenharmony_ci		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
279462306a36Sopenharmony_ci			"%s: busy with host reset\n", ioc->name, __func__));
279562306a36Sopenharmony_ci		return MPT_SCANDV_BUSY;
279662306a36Sopenharmony_ci	}
279762306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	mutex_lock(&ioc->internal_cmds.mutex);
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci	/* Set command specific information
280262306a36Sopenharmony_ci	 */
280362306a36Sopenharmony_ci	switch (cmd) {
280462306a36Sopenharmony_ci	case INQUIRY:
280562306a36Sopenharmony_ci		cmdLen = 6;
280662306a36Sopenharmony_ci		dir = MPI_SCSIIO_CONTROL_READ;
280762306a36Sopenharmony_ci		CDB[0] = cmd;
280862306a36Sopenharmony_ci		CDB[4] = io->size;
280962306a36Sopenharmony_ci		timeout = 10;
281062306a36Sopenharmony_ci		break;
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	case TEST_UNIT_READY:
281362306a36Sopenharmony_ci		cmdLen = 6;
281462306a36Sopenharmony_ci		dir = MPI_SCSIIO_CONTROL_READ;
281562306a36Sopenharmony_ci		timeout = 10;
281662306a36Sopenharmony_ci		break;
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci	case START_STOP:
281962306a36Sopenharmony_ci		cmdLen = 6;
282062306a36Sopenharmony_ci		dir = MPI_SCSIIO_CONTROL_READ;
282162306a36Sopenharmony_ci		CDB[0] = cmd;
282262306a36Sopenharmony_ci		CDB[4] = 1;	/*Spin up the disk */
282362306a36Sopenharmony_ci		timeout = 15;
282462306a36Sopenharmony_ci		break;
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	case REQUEST_SENSE:
282762306a36Sopenharmony_ci		cmdLen = 6;
282862306a36Sopenharmony_ci		CDB[0] = cmd;
282962306a36Sopenharmony_ci		CDB[4] = io->size;
283062306a36Sopenharmony_ci		dir = MPI_SCSIIO_CONTROL_READ;
283162306a36Sopenharmony_ci		timeout = 10;
283262306a36Sopenharmony_ci		break;
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	case READ_BUFFER:
283562306a36Sopenharmony_ci		cmdLen = 10;
283662306a36Sopenharmony_ci		dir = MPI_SCSIIO_CONTROL_READ;
283762306a36Sopenharmony_ci		CDB[0] = cmd;
283862306a36Sopenharmony_ci		if (io->flags & MPT_ICFLAG_ECHO) {
283962306a36Sopenharmony_ci			CDB[1] = 0x0A;
284062306a36Sopenharmony_ci		} else {
284162306a36Sopenharmony_ci			CDB[1] = 0x02;
284262306a36Sopenharmony_ci		}
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci		if (io->flags & MPT_ICFLAG_BUF_CAP) {
284562306a36Sopenharmony_ci			CDB[1] |= 0x01;
284662306a36Sopenharmony_ci		}
284762306a36Sopenharmony_ci		CDB[6] = (io->size >> 16) & 0xFF;
284862306a36Sopenharmony_ci		CDB[7] = (io->size >>  8) & 0xFF;
284962306a36Sopenharmony_ci		CDB[8] = io->size & 0xFF;
285062306a36Sopenharmony_ci		timeout = 10;
285162306a36Sopenharmony_ci		break;
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	case WRITE_BUFFER:
285462306a36Sopenharmony_ci		cmdLen = 10;
285562306a36Sopenharmony_ci		dir = MPI_SCSIIO_CONTROL_WRITE;
285662306a36Sopenharmony_ci		CDB[0] = cmd;
285762306a36Sopenharmony_ci		if (io->flags & MPT_ICFLAG_ECHO) {
285862306a36Sopenharmony_ci			CDB[1] = 0x0A;
285962306a36Sopenharmony_ci		} else {
286062306a36Sopenharmony_ci			CDB[1] = 0x02;
286162306a36Sopenharmony_ci		}
286262306a36Sopenharmony_ci		CDB[6] = (io->size >> 16) & 0xFF;
286362306a36Sopenharmony_ci		CDB[7] = (io->size >>  8) & 0xFF;
286462306a36Sopenharmony_ci		CDB[8] = io->size & 0xFF;
286562306a36Sopenharmony_ci		timeout = 10;
286662306a36Sopenharmony_ci		break;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	case RESERVE:
286962306a36Sopenharmony_ci		cmdLen = 6;
287062306a36Sopenharmony_ci		dir = MPI_SCSIIO_CONTROL_READ;
287162306a36Sopenharmony_ci		CDB[0] = cmd;
287262306a36Sopenharmony_ci		timeout = 10;
287362306a36Sopenharmony_ci		break;
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci	case RELEASE:
287662306a36Sopenharmony_ci		cmdLen = 6;
287762306a36Sopenharmony_ci		dir = MPI_SCSIIO_CONTROL_READ;
287862306a36Sopenharmony_ci		CDB[0] = cmd;
287962306a36Sopenharmony_ci		timeout = 10;
288062306a36Sopenharmony_ci		break;
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	case SYNCHRONIZE_CACHE:
288362306a36Sopenharmony_ci		cmdLen = 10;
288462306a36Sopenharmony_ci		dir = MPI_SCSIIO_CONTROL_READ;
288562306a36Sopenharmony_ci		CDB[0] = cmd;
288662306a36Sopenharmony_ci//		CDB[1] = 0x02;	/* set immediate bit */
288762306a36Sopenharmony_ci		timeout = 10;
288862306a36Sopenharmony_ci		break;
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	default:
289162306a36Sopenharmony_ci		/* Error Case */
289262306a36Sopenharmony_ci		ret = -EFAULT;
289362306a36Sopenharmony_ci		goto out;
289462306a36Sopenharmony_ci	}
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci	/* Get and Populate a free Frame
289762306a36Sopenharmony_ci	 * MsgContext set in mpt_get_msg_frame call
289862306a36Sopenharmony_ci	 */
289962306a36Sopenharmony_ci	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
290062306a36Sopenharmony_ci		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
290162306a36Sopenharmony_ci		    ioc->name, __func__));
290262306a36Sopenharmony_ci		ret = MPT_SCANDV_BUSY;
290362306a36Sopenharmony_ci		goto out;
290462306a36Sopenharmony_ci	}
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	pScsiReq = (SCSIIORequest_t *) mf;
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci	/* Get the request index */
290962306a36Sopenharmony_ci	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
291062306a36Sopenharmony_ci	ADD_INDEX_LOG(my_idx); /* for debug */
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	if (io->flags & MPT_ICFLAG_PHYS_DISK) {
291362306a36Sopenharmony_ci		pScsiReq->TargetID = io->physDiskNum;
291462306a36Sopenharmony_ci		pScsiReq->Bus = 0;
291562306a36Sopenharmony_ci		pScsiReq->ChainOffset = 0;
291662306a36Sopenharmony_ci		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
291762306a36Sopenharmony_ci	} else {
291862306a36Sopenharmony_ci		pScsiReq->TargetID = io->id;
291962306a36Sopenharmony_ci		pScsiReq->Bus = io->channel;
292062306a36Sopenharmony_ci		pScsiReq->ChainOffset = 0;
292162306a36Sopenharmony_ci		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
292262306a36Sopenharmony_ci	}
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci	pScsiReq->CDBLength = cmdLen;
292562306a36Sopenharmony_ci	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci	pScsiReq->Reserved = 0;
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	pScsiReq->MsgFlags = mpt_msg_flags(ioc);
293062306a36Sopenharmony_ci	/* MsgContext set in mpt_get_msg_fram call  */
293162306a36Sopenharmony_ci
293262306a36Sopenharmony_ci	int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	if (io->flags & MPT_ICFLAG_TAGGED_CMD)
293562306a36Sopenharmony_ci		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
293662306a36Sopenharmony_ci	else
293762306a36Sopenharmony_ci		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
293862306a36Sopenharmony_ci
293962306a36Sopenharmony_ci	if (cmd == REQUEST_SENSE) {
294062306a36Sopenharmony_ci		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
294162306a36Sopenharmony_ci		devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
294262306a36Sopenharmony_ci		    "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
294362306a36Sopenharmony_ci	}
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_ci	for (ii = 0; ii < 16; ii++)
294662306a36Sopenharmony_ci		pScsiReq->CDB[ii] = CDB[ii];
294762306a36Sopenharmony_ci
294862306a36Sopenharmony_ci	pScsiReq->DataLength = cpu_to_le32(io->size);
294962306a36Sopenharmony_ci	pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
295062306a36Sopenharmony_ci					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_ci	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
295362306a36Sopenharmony_ci	    "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%llu\n",
295462306a36Sopenharmony_ci	    ioc->name, __func__, cmd, io->channel, io->id, io->lun));
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci	if (dir == MPI_SCSIIO_CONTROL_READ)
295762306a36Sopenharmony_ci		ioc->add_sge((char *) &pScsiReq->SGL,
295862306a36Sopenharmony_ci		    MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
295962306a36Sopenharmony_ci	else
296062306a36Sopenharmony_ci		ioc->add_sge((char *) &pScsiReq->SGL,
296162306a36Sopenharmony_ci		    MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci	INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
296462306a36Sopenharmony_ci	mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
296562306a36Sopenharmony_ci	timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
296662306a36Sopenharmony_ci	    timeout*HZ);
296762306a36Sopenharmony_ci	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
296862306a36Sopenharmony_ci		ret = MPT_SCANDV_DID_RESET;
296962306a36Sopenharmony_ci		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
297062306a36Sopenharmony_ci		    "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
297162306a36Sopenharmony_ci		    cmd));
297262306a36Sopenharmony_ci		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
297362306a36Sopenharmony_ci			mpt_free_msg_frame(ioc, mf);
297462306a36Sopenharmony_ci			goto out;
297562306a36Sopenharmony_ci		}
297662306a36Sopenharmony_ci		if (!timeleft) {
297762306a36Sopenharmony_ci			printk(MYIOC_s_WARN_FMT
297862306a36Sopenharmony_ci			       "Issuing Reset from %s!! doorbell=0x%08xh"
297962306a36Sopenharmony_ci			       " cmd=0x%02x\n",
298062306a36Sopenharmony_ci			       ioc->name, __func__, mpt_GetIocState(ioc, 0),
298162306a36Sopenharmony_ci			       cmd);
298262306a36Sopenharmony_ci			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
298362306a36Sopenharmony_ci			mpt_free_msg_frame(ioc, mf);
298462306a36Sopenharmony_ci		}
298562306a36Sopenharmony_ci		goto out;
298662306a36Sopenharmony_ci	}
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci	ret = ioc->internal_cmds.completion_code;
298962306a36Sopenharmony_ci	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
299062306a36Sopenharmony_ci			ioc->name, __func__, ret));
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci out:
299362306a36Sopenharmony_ci	CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
299462306a36Sopenharmony_ci	mutex_unlock(&ioc->internal_cmds.mutex);
299562306a36Sopenharmony_ci	return ret;
299662306a36Sopenharmony_ci}
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
299962306a36Sopenharmony_ci/**
300062306a36Sopenharmony_ci *	mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
300162306a36Sopenharmony_ci *	@hd: Pointer to a SCSI HOST structure
300262306a36Sopenharmony_ci *	@vdevice: virtual target device
300362306a36Sopenharmony_ci *
300462306a36Sopenharmony_ci *	Uses the ISR, but with special processing.
300562306a36Sopenharmony_ci *	MUST be single-threaded.
300662306a36Sopenharmony_ci *
300762306a36Sopenharmony_ci */
300862306a36Sopenharmony_cistatic void
300962306a36Sopenharmony_cimptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
301062306a36Sopenharmony_ci{
301162306a36Sopenharmony_ci	INTERNAL_CMD		 iocmd;
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	/* Ignore hidden raid components, this is handled when the command
301462306a36Sopenharmony_ci	 * is sent to the volume
301562306a36Sopenharmony_ci	 */
301662306a36Sopenharmony_ci	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
301762306a36Sopenharmony_ci		return;
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ci	if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
302062306a36Sopenharmony_ci	    !vdevice->configured_lun)
302162306a36Sopenharmony_ci		return;
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci	/* Following parameters will not change
302462306a36Sopenharmony_ci	 * in this routine.
302562306a36Sopenharmony_ci	 */
302662306a36Sopenharmony_ci	iocmd.cmd = SYNCHRONIZE_CACHE;
302762306a36Sopenharmony_ci	iocmd.flags = 0;
302862306a36Sopenharmony_ci	iocmd.physDiskNum = -1;
302962306a36Sopenharmony_ci	iocmd.data = NULL;
303062306a36Sopenharmony_ci	iocmd.data_dma = -1;
303162306a36Sopenharmony_ci	iocmd.size = 0;
303262306a36Sopenharmony_ci	iocmd.rsvd = iocmd.rsvd2 = 0;
303362306a36Sopenharmony_ci	iocmd.channel = vdevice->vtarget->channel;
303462306a36Sopenharmony_ci	iocmd.id = vdevice->vtarget->id;
303562306a36Sopenharmony_ci	iocmd.lun = vdevice->lun;
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci	mptscsih_do_cmd(hd, &iocmd);
303862306a36Sopenharmony_ci}
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_cistatic ssize_t
304162306a36Sopenharmony_cimptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
304262306a36Sopenharmony_ci			 char *buf)
304362306a36Sopenharmony_ci{
304462306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
304562306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
304662306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
304962306a36Sopenharmony_ci	    (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
305062306a36Sopenharmony_ci	    (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
305162306a36Sopenharmony_ci	    (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
305262306a36Sopenharmony_ci	    ioc->facts.FWVersion.Word & 0x000000FF);
305362306a36Sopenharmony_ci}
305462306a36Sopenharmony_cistatic DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_cistatic ssize_t
305762306a36Sopenharmony_cimptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
305862306a36Sopenharmony_ci			   char *buf)
305962306a36Sopenharmony_ci{
306062306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
306162306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
306262306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
306562306a36Sopenharmony_ci	    (ioc->biosVersion & 0xFF000000) >> 24,
306662306a36Sopenharmony_ci	    (ioc->biosVersion & 0x00FF0000) >> 16,
306762306a36Sopenharmony_ci	    (ioc->biosVersion & 0x0000FF00) >> 8,
306862306a36Sopenharmony_ci	    ioc->biosVersion & 0x000000FF);
306962306a36Sopenharmony_ci}
307062306a36Sopenharmony_cistatic DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_cistatic ssize_t
307362306a36Sopenharmony_cimptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
307462306a36Sopenharmony_ci			  char *buf)
307562306a36Sopenharmony_ci{
307662306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
307762306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
307862306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
308162306a36Sopenharmony_ci}
308262306a36Sopenharmony_cistatic DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_cistatic ssize_t
308562306a36Sopenharmony_cimptscsih_version_product_show(struct device *dev,
308662306a36Sopenharmony_ci			      struct device_attribute *attr,
308762306a36Sopenharmony_cichar *buf)
308862306a36Sopenharmony_ci{
308962306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
309062306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
309162306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
309462306a36Sopenharmony_ci}
309562306a36Sopenharmony_cistatic DEVICE_ATTR(version_product, S_IRUGO,
309662306a36Sopenharmony_ci    mptscsih_version_product_show, NULL);
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_cistatic ssize_t
309962306a36Sopenharmony_cimptscsih_version_nvdata_persistent_show(struct device *dev,
310062306a36Sopenharmony_ci					struct device_attribute *attr,
310162306a36Sopenharmony_ci					char *buf)
310262306a36Sopenharmony_ci{
310362306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
310462306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
310562306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%02xh\n",
310862306a36Sopenharmony_ci	    ioc->nvdata_version_persistent);
310962306a36Sopenharmony_ci}
311062306a36Sopenharmony_cistatic DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
311162306a36Sopenharmony_ci    mptscsih_version_nvdata_persistent_show, NULL);
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_cistatic ssize_t
311462306a36Sopenharmony_cimptscsih_version_nvdata_default_show(struct device *dev,
311562306a36Sopenharmony_ci				     struct device_attribute *attr, char *buf)
311662306a36Sopenharmony_ci{
311762306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
311862306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
311962306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
312062306a36Sopenharmony_ci
312162306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
312262306a36Sopenharmony_ci}
312362306a36Sopenharmony_cistatic DEVICE_ATTR(version_nvdata_default, S_IRUGO,
312462306a36Sopenharmony_ci    mptscsih_version_nvdata_default_show, NULL);
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_cistatic ssize_t
312762306a36Sopenharmony_cimptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
312862306a36Sopenharmony_ci			 char *buf)
312962306a36Sopenharmony_ci{
313062306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
313162306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
313262306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
313562306a36Sopenharmony_ci}
313662306a36Sopenharmony_cistatic DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_cistatic ssize_t
313962306a36Sopenharmony_cimptscsih_board_assembly_show(struct device *dev,
314062306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
314162306a36Sopenharmony_ci{
314262306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
314362306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
314462306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
314762306a36Sopenharmony_ci}
314862306a36Sopenharmony_cistatic DEVICE_ATTR(board_assembly, S_IRUGO,
314962306a36Sopenharmony_ci    mptscsih_board_assembly_show, NULL);
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_cistatic ssize_t
315262306a36Sopenharmony_cimptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
315362306a36Sopenharmony_ci			   char *buf)
315462306a36Sopenharmony_ci{
315562306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
315662306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
315762306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
316062306a36Sopenharmony_ci}
316162306a36Sopenharmony_cistatic DEVICE_ATTR(board_tracer, S_IRUGO,
316262306a36Sopenharmony_ci    mptscsih_board_tracer_show, NULL);
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_cistatic ssize_t
316562306a36Sopenharmony_cimptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
316662306a36Sopenharmony_ci		       char *buf)
316762306a36Sopenharmony_ci{
316862306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
316962306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
317062306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
317362306a36Sopenharmony_ci}
317462306a36Sopenharmony_cistatic DEVICE_ATTR(io_delay, S_IRUGO,
317562306a36Sopenharmony_ci    mptscsih_io_delay_show, NULL);
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_cistatic ssize_t
317862306a36Sopenharmony_cimptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
317962306a36Sopenharmony_ci			   char *buf)
318062306a36Sopenharmony_ci{
318162306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
318262306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
318362306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
318662306a36Sopenharmony_ci}
318762306a36Sopenharmony_cistatic DEVICE_ATTR(device_delay, S_IRUGO,
318862306a36Sopenharmony_ci    mptscsih_device_delay_show, NULL);
318962306a36Sopenharmony_ci
319062306a36Sopenharmony_cistatic ssize_t
319162306a36Sopenharmony_cimptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
319262306a36Sopenharmony_ci			  char *buf)
319362306a36Sopenharmony_ci{
319462306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
319562306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
319662306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
319762306a36Sopenharmony_ci
319862306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
319962306a36Sopenharmony_ci}
320062306a36Sopenharmony_cistatic ssize_t
320162306a36Sopenharmony_cimptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
320262306a36Sopenharmony_ci			   const char *buf, size_t count)
320362306a36Sopenharmony_ci{
320462306a36Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
320562306a36Sopenharmony_ci	MPT_SCSI_HOST	*hd = shost_priv(host);
320662306a36Sopenharmony_ci	MPT_ADAPTER *ioc = hd->ioc;
320762306a36Sopenharmony_ci	int val = 0;
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	if (sscanf(buf, "%x", &val) != 1)
321062306a36Sopenharmony_ci		return -EINVAL;
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci	ioc->debug_level = val;
321362306a36Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
321462306a36Sopenharmony_ci				ioc->name, ioc->debug_level);
321562306a36Sopenharmony_ci	return strlen(buf);
321662306a36Sopenharmony_ci}
321762306a36Sopenharmony_cistatic DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
321862306a36Sopenharmony_ci	mptscsih_debug_level_show, mptscsih_debug_level_store);
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_cistatic struct attribute *mptscsih_host_attrs[] = {
322162306a36Sopenharmony_ci	&dev_attr_version_fw.attr,
322262306a36Sopenharmony_ci	&dev_attr_version_bios.attr,
322362306a36Sopenharmony_ci	&dev_attr_version_mpi.attr,
322462306a36Sopenharmony_ci	&dev_attr_version_product.attr,
322562306a36Sopenharmony_ci	&dev_attr_version_nvdata_persistent.attr,
322662306a36Sopenharmony_ci	&dev_attr_version_nvdata_default.attr,
322762306a36Sopenharmony_ci	&dev_attr_board_name.attr,
322862306a36Sopenharmony_ci	&dev_attr_board_assembly.attr,
322962306a36Sopenharmony_ci	&dev_attr_board_tracer.attr,
323062306a36Sopenharmony_ci	&dev_attr_io_delay.attr,
323162306a36Sopenharmony_ci	&dev_attr_device_delay.attr,
323262306a36Sopenharmony_ci	&dev_attr_debug_level.attr,
323362306a36Sopenharmony_ci	NULL,
323462306a36Sopenharmony_ci};
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_cistatic const struct attribute_group mptscsih_host_attr_group = {
323762306a36Sopenharmony_ci	.attrs = mptscsih_host_attrs
323862306a36Sopenharmony_ci};
323962306a36Sopenharmony_ci
324062306a36Sopenharmony_ciconst struct attribute_group *mptscsih_host_attr_groups[] = {
324162306a36Sopenharmony_ci	&mptscsih_host_attr_group,
324262306a36Sopenharmony_ci	NULL
324362306a36Sopenharmony_ci};
324462306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_host_attr_groups);
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_remove);
324762306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_shutdown);
324862306a36Sopenharmony_ci#ifdef CONFIG_PM
324962306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_suspend);
325062306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_resume);
325162306a36Sopenharmony_ci#endif
325262306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_show_info);
325362306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_info);
325462306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_qcmd);
325562306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_slave_destroy);
325662306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_slave_configure);
325762306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_abort);
325862306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_dev_reset);
325962306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_bus_reset);
326062306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_host_reset);
326162306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_bios_param);
326262306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_io_done);
326362306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_taskmgmt_complete);
326462306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_scandv_complete);
326562306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_event_process);
326662306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_ioc_reset);
326762306a36Sopenharmony_ciEXPORT_SYMBOL(mptscsih_change_queue_depth);
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3270