xref: /openbmc/linux/drivers/message/fusion/mptspi.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1243eabcfSMoore, Eric Dean  /*
2243eabcfSMoore, Eric Dean   *  linux/drivers/message/fusion/mptspi.c
3f36789e2SPrakash, Sathya  *      For use with LSI PCI chip/adapter(s)
4f36789e2SPrakash, Sathya  *      running LSI Fusion MPT (Message Passing Technology) firmware.
5243eabcfSMoore, Eric Dean   *
6cddc0ab7SPrakash, Sathya  *  Copyright (c) 1999-2008 LSI Corporation
716d20101SEric Moore  *  (mailto:DL-MPTFusionLinux@lsi.com)
8243eabcfSMoore, Eric Dean   *
9243eabcfSMoore, Eric Dean   */
10243eabcfSMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11243eabcfSMoore, Eric Dean  /*
12243eabcfSMoore, Eric Dean      This program is free software; you can redistribute it and/or modify
13243eabcfSMoore, Eric Dean      it under the terms of the GNU General Public License as published by
14243eabcfSMoore, Eric Dean      the Free Software Foundation; version 2 of the License.
15243eabcfSMoore, Eric Dean  
16243eabcfSMoore, Eric Dean      This program is distributed in the hope that it will be useful,
17243eabcfSMoore, Eric Dean      but WITHOUT ANY WARRANTY; without even the implied warranty of
18243eabcfSMoore, Eric Dean      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19243eabcfSMoore, Eric Dean      GNU General Public License for more details.
20243eabcfSMoore, Eric Dean  
21243eabcfSMoore, Eric Dean      NO WARRANTY
22243eabcfSMoore, Eric Dean      THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23243eabcfSMoore, Eric Dean      CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24243eabcfSMoore, Eric Dean      LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25243eabcfSMoore, Eric Dean      MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26243eabcfSMoore, Eric Dean      solely responsible for determining the appropriateness of using and
27243eabcfSMoore, Eric Dean      distributing the Program and assumes all risks associated with its
28243eabcfSMoore, Eric Dean      exercise of rights under this Agreement, including but not limited to
29243eabcfSMoore, Eric Dean      the risks and costs of program errors, damage to or loss of data,
30243eabcfSMoore, Eric Dean      programs or equipment, and unavailability or interruption of operations.
31243eabcfSMoore, Eric Dean  
32243eabcfSMoore, Eric Dean      DISCLAIMER OF LIABILITY
33243eabcfSMoore, Eric Dean      NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34243eabcfSMoore, Eric Dean      DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35243eabcfSMoore, Eric Dean      DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36243eabcfSMoore, Eric Dean      ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37243eabcfSMoore, Eric Dean      TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38243eabcfSMoore, Eric Dean      USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39243eabcfSMoore, Eric Dean      HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40243eabcfSMoore, Eric Dean  
41243eabcfSMoore, Eric Dean      You should have received a copy of the GNU General Public License
42243eabcfSMoore, Eric Dean      along with this program; if not, write to the Free Software
43243eabcfSMoore, Eric Dean      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
44243eabcfSMoore, Eric Dean  */
45243eabcfSMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46243eabcfSMoore, Eric Dean  
47243eabcfSMoore, Eric Dean  #include <linux/module.h>
48243eabcfSMoore, Eric Dean  #include <linux/kernel.h>
495a0e3ad6STejun Heo #include <linux/slab.h>
50243eabcfSMoore, Eric Dean  #include <linux/init.h>
51243eabcfSMoore, Eric Dean  #include <linux/errno.h>
52243eabcfSMoore, Eric Dean  #include <linux/kdev_t.h>
53243eabcfSMoore, Eric Dean  #include <linux/blkdev.h>
54243eabcfSMoore, Eric Dean  #include <linux/delay.h>	/* for mdelay */
55b8a51443SThomas Gleixner #include <linux/interrupt.h>
56243eabcfSMoore, Eric Dean  #include <linux/reboot.h>	/* notifier code */
57243eabcfSMoore, Eric Dean  #include <linux/workqueue.h>
58c92f222eSJames Bottomley #include <linux/raid_class.h>
59243eabcfSMoore, Eric Dean  
60243eabcfSMoore, Eric Dean  #include <scsi/scsi.h>
61243eabcfSMoore, Eric Dean  #include <scsi/scsi_cmnd.h>
62243eabcfSMoore, Eric Dean  #include <scsi/scsi_device.h>
63243eabcfSMoore, Eric Dean  #include <scsi/scsi_host.h>
64243eabcfSMoore, Eric Dean  #include <scsi/scsi_tcq.h>
65c92f222eSJames Bottomley #include <scsi/scsi_transport.h>
66c92f222eSJames Bottomley #include <scsi/scsi_transport_spi.h>
67873c82edSEric Moore #include <scsi/scsi_dbg.h>
68243eabcfSMoore, Eric Dean  
69243eabcfSMoore, Eric Dean  #include "mptbase.h"
70243eabcfSMoore, Eric Dean  #include "mptscsih.h"
71243eabcfSMoore, Eric Dean  
72243eabcfSMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
73243eabcfSMoore, Eric Dean  #define my_NAME		"Fusion MPT SPI Host driver"
74243eabcfSMoore, Eric Dean  #define my_VERSION	MPT_LINUX_VERSION_COMMON
75243eabcfSMoore, Eric Dean  #define MYNAM		"mptspi"
76243eabcfSMoore, Eric Dean  
77243eabcfSMoore, Eric Dean  MODULE_AUTHOR(MODULEAUTHOR);
78243eabcfSMoore, Eric Dean  MODULE_DESCRIPTION(my_NAME);
79243eabcfSMoore, Eric Dean  MODULE_LICENSE("GPL");
809f4203b3SEric Moore MODULE_VERSION(my_VERSION);
81243eabcfSMoore, Eric Dean  
82243eabcfSMoore, Eric Dean  /* Command line args */
83243eabcfSMoore, Eric Dean  static int mpt_saf_te = MPTSCSIH_SAF_TE;
84243eabcfSMoore, Eric Dean  module_param(mpt_saf_te, int, 0);
85243eabcfSMoore, Eric Dean  MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1  (default=MPTSCSIH_SAF_TE=0)");
86243eabcfSMoore, Eric Dean  
87c92f222eSJames Bottomley static void mptspi_write_offset(struct scsi_target *, int);
88c92f222eSJames Bottomley static void mptspi_write_width(struct scsi_target *, int);
89c92f222eSJames Bottomley static int mptspi_write_spi_device_pg1(struct scsi_target *,
90c92f222eSJames Bottomley 				       struct _CONFIG_PAGE_SCSI_DEVICE_1 *);
91c92f222eSJames Bottomley 
92c92f222eSJames Bottomley static struct scsi_transport_template *mptspi_transport_template = NULL;
93c92f222eSJames Bottomley 
94f606f571SPrakash, Sathya static u8	mptspiDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
95f606f571SPrakash, Sathya static u8	mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
96f606f571SPrakash, Sathya static u8	mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
97243eabcfSMoore, Eric Dean  
985a9c47b1SEric Moore /**
991544d677SRandy Dunlap  * 	mptspi_setTargetNegoParms  - Update the target negotiation parameters
1005a9c47b1SEric Moore  *	@hd: Pointer to a SCSI Host Structure
1011544d677SRandy Dunlap  *	@target: per target private data
1025a9c47b1SEric Moore  *	@sdev: SCSI device
1035a9c47b1SEric Moore  *
104950d2867SJiang Jian  *	Update the target negotiation parameters based on the Inquiry
1051544d677SRandy Dunlap  *	data, adapter capabilities, and NVRAM settings.
1065a9c47b1SEric Moore  **/
1075a9c47b1SEric Moore static void
mptspi_setTargetNegoParms(MPT_SCSI_HOST * hd,VirtTarget * target,struct scsi_device * sdev)1085a9c47b1SEric Moore mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
1095a9c47b1SEric Moore 			    struct scsi_device *sdev)
1105a9c47b1SEric Moore {
111e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
112e80b002bSEric Moore 	SpiCfgData *pspi_data = &ioc->spi_data;
1135a9c47b1SEric Moore 	int  id = (int) target->id;
1145a9c47b1SEric Moore 	int  nvram;
1155a9c47b1SEric Moore 	u8 width = MPT_NARROW;
1165a9c47b1SEric Moore 	u8 factor = MPT_ASYNC;
1175a9c47b1SEric Moore 	u8 offset = 0;
1185a9c47b1SEric Moore 	u8 nfactor;
1195a9c47b1SEric Moore 	u8 noQas = 1;
1205a9c47b1SEric Moore 
1215a9c47b1SEric Moore 	target->negoFlags = pspi_data->noQas;
1225a9c47b1SEric Moore 
1235a9c47b1SEric Moore 	if (sdev->scsi_level < SCSI_2) {
1245a9c47b1SEric Moore 		width = 0;
1255a9c47b1SEric Moore 		factor = MPT_ULTRA2;
1265a9c47b1SEric Moore 		offset = pspi_data->maxSyncOffset;
1275a9c47b1SEric Moore 		target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
1285a9c47b1SEric Moore 	} else {
1295a9c47b1SEric Moore 		if (scsi_device_wide(sdev))
1305a9c47b1SEric Moore 			width = 1;
1315a9c47b1SEric Moore 
1325a9c47b1SEric Moore 		if (scsi_device_sync(sdev)) {
1335a9c47b1SEric Moore 			factor = pspi_data->minSyncFactor;
1345a9c47b1SEric Moore 			if (!scsi_device_dt(sdev))
1355a9c47b1SEric Moore 					factor = MPT_ULTRA2;
1365a9c47b1SEric Moore 			else {
1375a9c47b1SEric Moore 				if (!scsi_device_ius(sdev) &&
1385a9c47b1SEric Moore 				    !scsi_device_qas(sdev))
1395a9c47b1SEric Moore 					factor = MPT_ULTRA160;
1405a9c47b1SEric Moore 				else {
1415a9c47b1SEric Moore 					factor = MPT_ULTRA320;
1425a9c47b1SEric Moore 					if (scsi_device_qas(sdev)) {
143e80b002bSEric Moore 						ddvprintk(ioc,
14429dd3609SEric Moore 						printk(MYIOC_s_DEBUG_FMT "Enabling QAS due to "
145e80b002bSEric Moore 						"byte56=%02x on id=%d!\n", ioc->name,
14629dd3609SEric Moore 						scsi_device_qas(sdev), id));
1475a9c47b1SEric Moore 						noQas = 0;
1485a9c47b1SEric Moore 					}
1495a9c47b1SEric Moore 					if (sdev->type == TYPE_TAPE &&
1505a9c47b1SEric Moore 					    scsi_device_ius(sdev))
1515a9c47b1SEric Moore 						target->negoFlags |= MPT_TAPE_NEGO_IDP;
1525a9c47b1SEric Moore 				}
1535a9c47b1SEric Moore 			}
1545a9c47b1SEric Moore 			offset = pspi_data->maxSyncOffset;
1555a9c47b1SEric Moore 
1565a9c47b1SEric Moore 			/* If RAID, never disable QAS
1575a9c47b1SEric Moore 			 * else if non RAID, do not disable
1585a9c47b1SEric Moore 			 *   QAS if bit 1 is set
1595a9c47b1SEric Moore 			 * bit 1 QAS support, non-raid only
1605a9c47b1SEric Moore 			 * bit 0 IU support
1615a9c47b1SEric Moore 			 */
1625a9c47b1SEric Moore 			if (target->raidVolume == 1)
1635a9c47b1SEric Moore 				noQas = 0;
1645a9c47b1SEric Moore 		} else {
1655a9c47b1SEric Moore 			factor = MPT_ASYNC;
1665a9c47b1SEric Moore 			offset = 0;
1675a9c47b1SEric Moore 		}
1685a9c47b1SEric Moore 	}
1695a9c47b1SEric Moore 
1705a9c47b1SEric Moore 	if (!sdev->tagged_supported)
1715a9c47b1SEric Moore 		target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
1725a9c47b1SEric Moore 
1735a9c47b1SEric Moore 	/* Update tflags based on NVRAM settings. (SCSI only)
1745a9c47b1SEric Moore 	 */
1755a9c47b1SEric Moore 	if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
1765a9c47b1SEric Moore 		nvram = pspi_data->nvram[id];
1775a9c47b1SEric Moore 		nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
1785a9c47b1SEric Moore 
1795a9c47b1SEric Moore 		if (width)
1805a9c47b1SEric Moore 			width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
1815a9c47b1SEric Moore 
1825a9c47b1SEric Moore 		if (offset > 0) {
1835a9c47b1SEric Moore 			/* Ensure factor is set to the
1845a9c47b1SEric Moore 			 * maximum of: adapter, nvram, inquiry
1855a9c47b1SEric Moore 			 */
1865a9c47b1SEric Moore 			if (nfactor) {
1875a9c47b1SEric Moore 				if (nfactor < pspi_data->minSyncFactor )
1885a9c47b1SEric Moore 					nfactor = pspi_data->minSyncFactor;
1895a9c47b1SEric Moore 
1905a9c47b1SEric Moore 				factor = max(factor, nfactor);
1915a9c47b1SEric Moore 				if (factor == MPT_ASYNC)
1925a9c47b1SEric Moore 					offset = 0;
1935a9c47b1SEric Moore 			} else {
1945a9c47b1SEric Moore 				offset = 0;
1955a9c47b1SEric Moore 				factor = MPT_ASYNC;
1965a9c47b1SEric Moore 		}
1975a9c47b1SEric Moore 		} else {
1985a9c47b1SEric Moore 			factor = MPT_ASYNC;
1995a9c47b1SEric Moore 		}
2005a9c47b1SEric Moore 	}
2015a9c47b1SEric Moore 
2025a9c47b1SEric Moore 	/* Make sure data is consistent
2035a9c47b1SEric Moore 	 */
2045a9c47b1SEric Moore 	if ((!width) && (factor < MPT_ULTRA2))
2055a9c47b1SEric Moore 		factor = MPT_ULTRA2;
2065a9c47b1SEric Moore 
2075a9c47b1SEric Moore 	/* Save the data to the target structure.
2085a9c47b1SEric Moore 	 */
2095a9c47b1SEric Moore 	target->minSyncFactor = factor;
2105a9c47b1SEric Moore 	target->maxOffset = offset;
2115a9c47b1SEric Moore 	target->maxWidth = width;
2125a9c47b1SEric Moore 
213f8c23bdeSKashyap, Desai 	spi_min_period(scsi_target(sdev)) = factor;
214f8c23bdeSKashyap, Desai 	spi_max_offset(scsi_target(sdev)) = offset;
215f8c23bdeSKashyap, Desai 	spi_max_width(scsi_target(sdev)) = width;
216f8c23bdeSKashyap, Desai 
2175a9c47b1SEric Moore 	target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2185a9c47b1SEric Moore 
2195a9c47b1SEric Moore 	/* Disable unused features.
2205a9c47b1SEric Moore 	 */
2215a9c47b1SEric Moore 	if (!width)
2225a9c47b1SEric Moore 		target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2235a9c47b1SEric Moore 
2245a9c47b1SEric Moore 	if (!offset)
2255a9c47b1SEric Moore 		target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2265a9c47b1SEric Moore 
2275a9c47b1SEric Moore 	if ( factor > MPT_ULTRA320 )
2285a9c47b1SEric Moore 		noQas = 0;
2295a9c47b1SEric Moore 
2305a9c47b1SEric Moore 	if (noQas && (pspi_data->noQas == 0)) {
2315a9c47b1SEric Moore 		pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2325a9c47b1SEric Moore 		target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2335a9c47b1SEric Moore 
2345a9c47b1SEric Moore 		/* Disable QAS in a mixed configuration case
2355a9c47b1SEric Moore 		 */
2365a9c47b1SEric Moore 
237e80b002bSEric Moore 		ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
238e80b002bSEric Moore 			"Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
2395a9c47b1SEric Moore 	}
2405a9c47b1SEric Moore }
2415a9c47b1SEric Moore 
2425a9c47b1SEric Moore /**
2435a9c47b1SEric Moore  * 	mptspi_writeIOCPage4  - write IOC Page 4
2445a9c47b1SEric Moore  *	@hd: Pointer to a SCSI Host Structure
2451544d677SRandy Dunlap  *	@channel: channel number
2465a9c47b1SEric Moore  *	@id: write IOC Page4 for this ID & Bus
2475a9c47b1SEric Moore  *
2485a9c47b1SEric Moore  *	Return: -EAGAIN if unable to obtain a Message Frame
2495a9c47b1SEric Moore  *		or 0 if success.
2505a9c47b1SEric Moore  *
2515a9c47b1SEric Moore  *	Remark: We do not wait for a return, write pages sequentially.
2525a9c47b1SEric Moore  **/
2535a9c47b1SEric Moore static int
mptspi_writeIOCPage4(MPT_SCSI_HOST * hd,u8 channel,u8 id)2545a9c47b1SEric Moore mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
2555a9c47b1SEric Moore {
2565a9c47b1SEric Moore 	MPT_ADAPTER		*ioc = hd->ioc;
2575a9c47b1SEric Moore 	Config_t		*pReq;
2585a9c47b1SEric Moore 	IOCPage4_t		*IOCPage4Ptr;
2595a9c47b1SEric Moore 	MPT_FRAME_HDR		*mf;
2605a9c47b1SEric Moore 	dma_addr_t		 dataDma;
2615a9c47b1SEric Moore 	u32			 flagsLength;
2625a9c47b1SEric Moore 	int			 ii;
2635a9c47b1SEric Moore 
2645a9c47b1SEric Moore 	/* Get a MF for this command.
2655a9c47b1SEric Moore 	 */
2665a9c47b1SEric Moore 	if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
267d6ecdd63SPrakash, Sathya 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
268d6ecdd63SPrakash, Sathya 				"writeIOCPage4 : no msg frames!\n",ioc->name));
2695a9c47b1SEric Moore 		return -EAGAIN;
2705a9c47b1SEric Moore 	}
2715a9c47b1SEric Moore 
2725a9c47b1SEric Moore 	/* Set the request and the data pointers.
2735a9c47b1SEric Moore 	 * Place data at end of MF.
2745a9c47b1SEric Moore 	 */
2755a9c47b1SEric Moore 	pReq = (Config_t *)mf;
2765a9c47b1SEric Moore 
2775a9c47b1SEric Moore 	/* Complete the request frame (same for all requests).
2785a9c47b1SEric Moore 	 */
2795a9c47b1SEric Moore 	pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
2805a9c47b1SEric Moore 	pReq->Reserved = 0;
2815a9c47b1SEric Moore 	pReq->ChainOffset = 0;
2825a9c47b1SEric Moore 	pReq->Function = MPI_FUNCTION_CONFIG;
2835a9c47b1SEric Moore 	pReq->ExtPageLength = 0;
2845a9c47b1SEric Moore 	pReq->ExtPageType = 0;
2855a9c47b1SEric Moore 	pReq->MsgFlags = 0;
2865a9c47b1SEric Moore 	for (ii=0; ii < 8; ii++) {
2875a9c47b1SEric Moore 		pReq->Reserved2[ii] = 0;
2885a9c47b1SEric Moore 	}
2895a9c47b1SEric Moore 
2905a9c47b1SEric Moore 	IOCPage4Ptr = ioc->spi_data.pIocPg4;
2915a9c47b1SEric Moore 	dataDma = ioc->spi_data.IocPg4_dma;
2925a9c47b1SEric Moore 	ii = IOCPage4Ptr->ActiveSEP++;
2935a9c47b1SEric Moore 	IOCPage4Ptr->SEP[ii].SEPTargetID = id;
2945a9c47b1SEric Moore 	IOCPage4Ptr->SEP[ii].SEPBus = channel;
2955a9c47b1SEric Moore 	pReq->Header = IOCPage4Ptr->Header;
2965a9c47b1SEric Moore 	pReq->PageAddress = cpu_to_le32(id | (channel << 8 ));
2975a9c47b1SEric Moore 
2985a9c47b1SEric Moore 	/* Add a SGE to the config request.
2995a9c47b1SEric Moore 	 */
3005a9c47b1SEric Moore 	flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3015a9c47b1SEric Moore 		(IOCPage4Ptr->Header.PageLength + ii) * 4;
3025a9c47b1SEric Moore 
30314d0f0b0SKashyap, Desai 	ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3045a9c47b1SEric Moore 
305d6ecdd63SPrakash, Sathya 	ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3065a9c47b1SEric Moore 		"writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3075a9c47b1SEric Moore 		ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
3085a9c47b1SEric Moore 
3095a9c47b1SEric Moore 	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
3105a9c47b1SEric Moore 
3115a9c47b1SEric Moore 	return 0;
3125a9c47b1SEric Moore }
3135a9c47b1SEric Moore 
3145a9c47b1SEric Moore /**
3155a9c47b1SEric Moore  *	mptspi_initTarget - Target, LUN alloc/free functionality.
3165a9c47b1SEric Moore  *	@hd: Pointer to MPT_SCSI_HOST structure
3175a9c47b1SEric Moore  *	@vtarget: per target private data
3185a9c47b1SEric Moore  *	@sdev: SCSI device
3195a9c47b1SEric Moore  *
3205a9c47b1SEric Moore  *	NOTE: It's only SAFE to call this routine if data points to
3215a9c47b1SEric Moore  *	sane & valid STANDARD INQUIRY data!
3225a9c47b1SEric Moore  *
3235a9c47b1SEric Moore  *	Allocate and initialize memory for this target.
3245a9c47b1SEric Moore  *	Save inquiry data.
3255a9c47b1SEric Moore  *
3265a9c47b1SEric Moore  **/
3275a9c47b1SEric Moore static void
mptspi_initTarget(MPT_SCSI_HOST * hd,VirtTarget * vtarget,struct scsi_device * sdev)3285a9c47b1SEric Moore mptspi_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
3295a9c47b1SEric Moore 		    struct scsi_device *sdev)
3305a9c47b1SEric Moore {
3315a9c47b1SEric Moore 
3325a9c47b1SEric Moore 	/* Is LUN supported? If so, upper 2 bits will be 0
3335a9c47b1SEric Moore 	* in first byte of inquiry data.
3345a9c47b1SEric Moore 	*/
3355a9c47b1SEric Moore 	if (sdev->inq_periph_qual != 0)
3365a9c47b1SEric Moore 		return;
3375a9c47b1SEric Moore 
3385a9c47b1SEric Moore 	if (vtarget == NULL)
3395a9c47b1SEric Moore 		return;
3405a9c47b1SEric Moore 
3415a9c47b1SEric Moore 	vtarget->type = sdev->type;
3425a9c47b1SEric Moore 
3435a9c47b1SEric Moore 	if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
3445a9c47b1SEric Moore 		/* Treat all Processors as SAF-TE if
3455a9c47b1SEric Moore 		 * command line option is set */
3465a9c47b1SEric Moore 		vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
3475a9c47b1SEric Moore 		mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id);
3485a9c47b1SEric Moore 	}else if ((sdev->type == TYPE_PROCESSOR) &&
3495a9c47b1SEric Moore 		!(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
3505a9c47b1SEric Moore 		if (sdev->inquiry_len > 49 ) {
3515a9c47b1SEric Moore 			if (sdev->inquiry[44] == 'S' &&
3525a9c47b1SEric Moore 			    sdev->inquiry[45] == 'A' &&
3535a9c47b1SEric Moore 			    sdev->inquiry[46] == 'F' &&
3545a9c47b1SEric Moore 			    sdev->inquiry[47] == '-' &&
3555a9c47b1SEric Moore 			    sdev->inquiry[48] == 'T' &&
3565a9c47b1SEric Moore 			    sdev->inquiry[49] == 'E' ) {
3575a9c47b1SEric Moore 				vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
3585a9c47b1SEric Moore 				mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id);
3595a9c47b1SEric Moore 			}
3605a9c47b1SEric Moore 		}
3615a9c47b1SEric Moore 	}
3625a9c47b1SEric Moore 	mptspi_setTargetNegoParms(hd, vtarget, sdev);
3635a9c47b1SEric Moore }
364793955f5SEric Moore 
365793955f5SEric Moore /**
366793955f5SEric Moore  *	mptspi_is_raid - Determines whether target is belonging to volume
367793955f5SEric Moore  *	@hd: Pointer to a SCSI HOST structure
368793955f5SEric Moore  *	@id: target device id
369793955f5SEric Moore  *
370793955f5SEric Moore  *	Return:
371793955f5SEric Moore  *		non-zero = true
372793955f5SEric Moore  *		zero = false
373793955f5SEric Moore  *
374793955f5SEric Moore  */
375793955f5SEric Moore static int
mptspi_is_raid(struct _MPT_SCSI_HOST * hd,u32 id)376793955f5SEric Moore mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
377793955f5SEric Moore {
378793955f5SEric Moore 	int i, rc = 0;
379e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
380793955f5SEric Moore 
381e80b002bSEric Moore 	if (!ioc->raid_data.pIocPg2)
382793955f5SEric Moore 		goto out;
383793955f5SEric Moore 
384e80b002bSEric Moore 	if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
385793955f5SEric Moore 		goto out;
386e80b002bSEric Moore 	for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
387e80b002bSEric Moore 		if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
388793955f5SEric Moore 			rc = 1;
389793955f5SEric Moore 			goto out;
390793955f5SEric Moore 		}
391793955f5SEric Moore 	}
392793955f5SEric Moore 
393793955f5SEric Moore  out:
394793955f5SEric Moore 	return rc;
395793955f5SEric Moore }
396793955f5SEric Moore 
mptspi_target_alloc(struct scsi_target * starget)397c92f222eSJames Bottomley static int mptspi_target_alloc(struct scsi_target *starget)
398c92f222eSJames Bottomley {
399c92f222eSJames Bottomley 	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
400e7eae9f6SEric Moore 	struct _MPT_SCSI_HOST *hd = shost_priv(shost);
401793955f5SEric Moore 	VirtTarget		*vtarget;
402e80b002bSEric Moore 	MPT_ADAPTER *ioc;
403c92f222eSJames Bottomley 
404c92f222eSJames Bottomley 	if (hd == NULL)
405c92f222eSJames Bottomley 		return -ENODEV;
406c92f222eSJames Bottomley 
407e80b002bSEric Moore 	ioc = hd->ioc;
408793955f5SEric Moore 	vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
409793955f5SEric Moore 	if (!vtarget)
410793955f5SEric Moore 		return -ENOMEM;
411c92f222eSJames Bottomley 
412e80b002bSEric Moore 	vtarget->ioc_id = ioc->id;
413793955f5SEric Moore 	vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
414793955f5SEric Moore 	vtarget->id = (u8)starget->id;
415793955f5SEric Moore 	vtarget->channel = (u8)starget->channel;
416793955f5SEric Moore 	vtarget->starget = starget;
417793955f5SEric Moore 	starget->hostdata = vtarget;
418793955f5SEric Moore 
419793955f5SEric Moore 	if (starget->channel == 1) {
420e80b002bSEric Moore 		if (mptscsih_is_phys_disk(ioc, 0, starget->id) == 0)
421c92f222eSJames Bottomley 			return 0;
422793955f5SEric Moore 		vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
423793955f5SEric Moore 		/* The real channel for this device is zero */
424793955f5SEric Moore 		vtarget->channel = 0;
425793955f5SEric Moore 		/* The actual physdisknum (for RAID passthrough) */
426e80b002bSEric Moore 		vtarget->id = mptscsih_raid_id_to_num(ioc, 0,
427793955f5SEric Moore 		    starget->id);
428793955f5SEric Moore 	}
429793955f5SEric Moore 
430793955f5SEric Moore 	if (starget->channel == 0 &&
431793955f5SEric Moore 	    mptspi_is_raid(hd, starget->id)) {
432793955f5SEric Moore 		vtarget->raidVolume = 1;
433e80b002bSEric Moore 		ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
434e80b002bSEric Moore 		    "RAID Volume @ channel=%d id=%d\n", ioc->name, starget->channel,
435793955f5SEric Moore 		    starget->id));
436793955f5SEric Moore 	}
437c92f222eSJames Bottomley 
438e80b002bSEric Moore 	if (ioc->spi_data.nvram &&
439e80b002bSEric Moore 	    ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
440e80b002bSEric Moore 		u32 nvram = ioc->spi_data.nvram[starget->id];
441c92f222eSJames Bottomley 		spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
442c92f222eSJames Bottomley 		spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
443c92f222eSJames Bottomley 	} else {
444e80b002bSEric Moore 		spi_min_period(starget) = ioc->spi_data.minSyncFactor;
445e80b002bSEric Moore 		spi_max_width(starget) = ioc->spi_data.maxBusWidth;
446c92f222eSJames Bottomley 	}
447e80b002bSEric Moore 	spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
448c92f222eSJames Bottomley 
449c92f222eSJames Bottomley 	spi_offset(starget) = 0;
450cc472449SPrakash, Sathya 	spi_period(starget) = 0xFF;
451c92f222eSJames Bottomley 	mptspi_write_width(starget, 0);
452c92f222eSJames Bottomley 
453c92f222eSJames Bottomley 	return 0;
454c92f222eSJames Bottomley }
455c92f222eSJames Bottomley 
456301b01aaSAdrian Bunk static void
mptspi_target_destroy(struct scsi_target * starget)457793955f5SEric Moore mptspi_target_destroy(struct scsi_target *starget)
458793955f5SEric Moore {
459793955f5SEric Moore 	kfree(starget->hostdata);
460793955f5SEric Moore 	starget->hostdata = NULL;
461793955f5SEric Moore }
462793955f5SEric Moore 
463873c82edSEric Moore /**
464873c82edSEric Moore  *	mptspi_print_write_nego - negotiation parameters debug info that is being sent
465873c82edSEric Moore  *	@hd: Pointer to a SCSI HOST structure
466873c82edSEric Moore  *	@starget: SCSI target
467873c82edSEric Moore  *	@ii: negotiation parameters
468873c82edSEric Moore  *
469873c82edSEric Moore  */
470873c82edSEric Moore static void
mptspi_print_write_nego(struct _MPT_SCSI_HOST * hd,struct scsi_target * starget,u32 ii)471873c82edSEric Moore mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
472873c82edSEric Moore {
473d6ecdd63SPrakash, Sathya 	ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x"
474873c82edSEric Moore 	    " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
475873c82edSEric Moore 	    hd->ioc->name, starget->id, ii,
476873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
477873c82edSEric Moore 	    ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
478873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
479873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "",
480873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "",
481873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "",
482873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
483873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
484873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
485873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
486873c82edSEric Moore }
487873c82edSEric Moore 
488873c82edSEric Moore /**
489873c82edSEric Moore  *	mptspi_print_read_nego - negotiation parameters debug info that is being read
490873c82edSEric Moore  *	@hd: Pointer to a SCSI HOST structure
491873c82edSEric Moore  *	@starget: SCSI target
492873c82edSEric Moore  *	@ii: negotiation parameters
493873c82edSEric Moore  *
494873c82edSEric Moore  */
495873c82edSEric Moore static void
mptspi_print_read_nego(struct _MPT_SCSI_HOST * hd,struct scsi_target * starget,u32 ii)496873c82edSEric Moore mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
497873c82edSEric Moore {
498d6ecdd63SPrakash, Sathya 	ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x"
499873c82edSEric Moore 	    " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
500873c82edSEric Moore 	    hd->ioc->name, starget->id, ii,
501873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
502873c82edSEric Moore 	    ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
503873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
504873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "",
505873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "",
506873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "",
507873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
508873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
509873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
510873c82edSEric Moore 	    ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
511873c82edSEric Moore }
512873c82edSEric Moore 
mptspi_read_spi_device_pg0(struct scsi_target * starget,struct _CONFIG_PAGE_SCSI_DEVICE_0 * pass_pg0)513c92f222eSJames Bottomley static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
514c92f222eSJames Bottomley 			     struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0)
515c92f222eSJames Bottomley {
516c92f222eSJames Bottomley 	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
517e7eae9f6SEric Moore 	struct _MPT_SCSI_HOST *hd = shost_priv(shost);
518c92f222eSJames Bottomley 	struct _MPT_ADAPTER *ioc = hd->ioc;
519bc6e089aSEric Moore 	struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0;
520bc6e089aSEric Moore 	dma_addr_t spi_dev_pg0_dma;
521c92f222eSJames Bottomley 	int size;
522c92f222eSJames Bottomley 	struct _x_config_parms cfg;
523c92f222eSJames Bottomley 	struct _CONFIG_PAGE_HEADER hdr;
524c92f222eSJames Bottomley 	int err = -EBUSY;
525c92f222eSJames Bottomley 
526c92f222eSJames Bottomley 	/* No SPI parameters for RAID devices */
527c92f222eSJames Bottomley 	if (starget->channel == 0 &&
528793955f5SEric Moore 	    mptspi_is_raid(hd, starget->id))
529c92f222eSJames Bottomley 		return -1;
530c92f222eSJames Bottomley 
531c92f222eSJames Bottomley 	size = ioc->spi_data.sdp0length * 4;
532c92f222eSJames Bottomley 	/*
533c92f222eSJames Bottomley 	if (ioc->spi_data.sdp0length & 1)
534c92f222eSJames Bottomley 		size += size + 4;
535c92f222eSJames Bottomley 	size += 2048;
536c92f222eSJames Bottomley 	*/
537c92f222eSJames Bottomley 
538bc6e089aSEric Moore 	spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL);
539bc6e089aSEric Moore 	if (spi_dev_pg0 == NULL) {
540c51d0beaSEric Moore 		starget_printk(KERN_ERR, starget, MYIOC_s_FMT
54129dd3609SEric Moore 		    "dma_alloc_coherent for parameters failed\n", ioc->name);
542c92f222eSJames Bottomley 		return -EINVAL;
543c92f222eSJames Bottomley 	}
544c92f222eSJames Bottomley 
545c92f222eSJames Bottomley 	memset(&hdr, 0, sizeof(hdr));
546c92f222eSJames Bottomley 
547c92f222eSJames Bottomley 	hdr.PageVersion = ioc->spi_data.sdp0version;
548c92f222eSJames Bottomley 	hdr.PageLength = ioc->spi_data.sdp0length;
549c92f222eSJames Bottomley 	hdr.PageNumber = 0;
550c92f222eSJames Bottomley 	hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
551c92f222eSJames Bottomley 
552c92f222eSJames Bottomley 	memset(&cfg, 0, sizeof(cfg));
553c92f222eSJames Bottomley 
554c92f222eSJames Bottomley 	cfg.cfghdr.hdr = &hdr;
555bc6e089aSEric Moore 	cfg.physAddr = spi_dev_pg0_dma;
556c92f222eSJames Bottomley 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
557c92f222eSJames Bottomley 	cfg.dir = 0;
558c92f222eSJames Bottomley 	cfg.pageAddr = starget->id;
559f8c23bdeSKashyap, Desai 	cfg.timeout = 60;
560c92f222eSJames Bottomley 
561c92f222eSJames Bottomley 	if (mpt_config(ioc, &cfg)) {
562c51d0beaSEric Moore 		starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
563c92f222eSJames Bottomley 		goto out_free;
564c92f222eSJames Bottomley 	}
565c92f222eSJames Bottomley 	err = 0;
566bc6e089aSEric Moore 	memcpy(pass_pg0, spi_dev_pg0, size);
567c92f222eSJames Bottomley 
568bc6e089aSEric Moore 	mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters));
569873c82edSEric Moore 
570c92f222eSJames Bottomley  out_free:
571bc6e089aSEric Moore 	dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_dma);
572c92f222eSJames Bottomley 	return err;
573c92f222eSJames Bottomley }
574c92f222eSJames Bottomley 
mptspi_getRP(struct scsi_target * starget)575c92f222eSJames Bottomley static u32 mptspi_getRP(struct scsi_target *starget)
576c92f222eSJames Bottomley {
577c92f222eSJames Bottomley 	u32 nego = 0;
578c92f222eSJames Bottomley 
579c92f222eSJames Bottomley 	nego |= spi_iu(starget) ? MPI_SCSIDEVPAGE1_RP_IU : 0;
580c92f222eSJames Bottomley 	nego |= spi_dt(starget) ? MPI_SCSIDEVPAGE1_RP_DT : 0;
581c92f222eSJames Bottomley 	nego |= spi_qas(starget) ? MPI_SCSIDEVPAGE1_RP_QAS : 0;
582c92f222eSJames Bottomley 	nego |= spi_hold_mcs(starget) ? MPI_SCSIDEVPAGE1_RP_HOLD_MCS : 0;
583c92f222eSJames Bottomley 	nego |= spi_wr_flow(starget) ? MPI_SCSIDEVPAGE1_RP_WR_FLOW : 0;
584c92f222eSJames Bottomley 	nego |= spi_rd_strm(starget) ? MPI_SCSIDEVPAGE1_RP_RD_STRM : 0;
585c92f222eSJames Bottomley 	nego |= spi_rti(starget) ? MPI_SCSIDEVPAGE1_RP_RTI : 0;
586c92f222eSJames Bottomley 	nego |= spi_pcomp_en(starget) ? MPI_SCSIDEVPAGE1_RP_PCOMP_EN : 0;
587c92f222eSJames Bottomley 
588c92f222eSJames Bottomley 	nego |= (spi_period(starget) <<  MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD) & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK;
589c92f222eSJames Bottomley 	nego |= (spi_offset(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET) & MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK;
590c92f222eSJames Bottomley 	nego |= spi_width(starget) ?  MPI_SCSIDEVPAGE1_RP_WIDE : 0;
591c92f222eSJames Bottomley 
592c92f222eSJames Bottomley 	return nego;
593c92f222eSJames Bottomley }
594c92f222eSJames Bottomley 
mptspi_read_parameters(struct scsi_target * starget)595c92f222eSJames Bottomley static void mptspi_read_parameters(struct scsi_target *starget)
596c92f222eSJames Bottomley {
597c92f222eSJames Bottomley 	int nego;
598bc6e089aSEric Moore 	struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0;
599c92f222eSJames Bottomley 
600bc6e089aSEric Moore 	mptspi_read_spi_device_pg0(starget, &spi_dev_pg0);
601c92f222eSJames Bottomley 
602bc6e089aSEric Moore 	nego = le32_to_cpu(spi_dev_pg0.NegotiatedParameters);
603c92f222eSJames Bottomley 
604c92f222eSJames Bottomley 	spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0;
605c92f222eSJames Bottomley 	spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0;
606c92f222eSJames Bottomley 	spi_qas(starget) = (nego & MPI_SCSIDEVPAGE0_NP_QAS) ? 1 : 0;
607c92f222eSJames Bottomley 	spi_wr_flow(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WR_FLOW) ? 1 : 0;
608c92f222eSJames Bottomley 	spi_rd_strm(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RD_STRM) ? 1 : 0;
609c92f222eSJames Bottomley 	spi_rti(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RTI) ? 1 : 0;
610c92f222eSJames Bottomley 	spi_pcomp_en(starget) = (nego & MPI_SCSIDEVPAGE0_NP_PCOMP_EN) ? 1 : 0;
611c92f222eSJames Bottomley 	spi_hold_mcs(starget) = (nego & MPI_SCSIDEVPAGE0_NP_HOLD_MCS) ? 1 : 0;
612c92f222eSJames Bottomley 	spi_period(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD;
613c92f222eSJames Bottomley 	spi_offset(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET;
614c92f222eSJames Bottomley 	spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0;
615c92f222eSJames Bottomley }
616c92f222eSJames Bottomley 
6175767d25fSJoe Lawrence static int
mptscsih_quiesce_raid(MPT_SCSI_HOST * hd,int quiesce,u8 channel,u8 id)618793955f5SEric Moore mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
619c92f222eSJames Bottomley {
62037c60f37SKashyap, Desai 	MPT_ADAPTER	*ioc = hd->ioc;
621c92f222eSJames Bottomley 	MpiRaidActionRequest_t	*pReq;
622c92f222eSJames Bottomley 	MPT_FRAME_HDR		*mf;
62337c60f37SKashyap, Desai 	int			ret;
62437c60f37SKashyap, Desai 	unsigned long 	 	timeleft;
62537c60f37SKashyap, Desai 
62637c60f37SKashyap, Desai 	mutex_lock(&ioc->internal_cmds.mutex);
627c92f222eSJames Bottomley 
628c92f222eSJames Bottomley 	/* Get and Populate a free Frame
629c92f222eSJames Bottomley 	 */
630e80b002bSEric Moore 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
63137c60f37SKashyap, Desai 		dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT
63237c60f37SKashyap, Desai 			"%s: no msg frames!\n", ioc->name, __func__));
63337c60f37SKashyap, Desai 		ret = -EAGAIN;
63437c60f37SKashyap, Desai 		goto out;
635c92f222eSJames Bottomley 	}
636c92f222eSJames Bottomley 	pReq = (MpiRaidActionRequest_t *)mf;
637c92f222eSJames Bottomley 	if (quiesce)
638c92f222eSJames Bottomley 		pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO;
639c92f222eSJames Bottomley 	else
640c92f222eSJames Bottomley 		pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO;
641c92f222eSJames Bottomley 	pReq->Reserved1 = 0;
642c92f222eSJames Bottomley 	pReq->ChainOffset = 0;
643c92f222eSJames Bottomley 	pReq->Function = MPI_FUNCTION_RAID_ACTION;
644793955f5SEric Moore 	pReq->VolumeID = id;
645793955f5SEric Moore 	pReq->VolumeBus = channel;
646c92f222eSJames Bottomley 	pReq->PhysDiskNum = 0;
647c92f222eSJames Bottomley 	pReq->MsgFlags = 0;
648c92f222eSJames Bottomley 	pReq->Reserved2 = 0;
649c92f222eSJames Bottomley 	pReq->ActionDataWord = 0; /* Reserved for this action */
650c92f222eSJames Bottomley 
65114d0f0b0SKashyap, Desai 	ioc->add_sge((char *)&pReq->ActionDataSGE,
652c92f222eSJames Bottomley 		MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
653c92f222eSJames Bottomley 
654e80b002bSEric Moore 	ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
655e80b002bSEric Moore 			ioc->name, pReq->Action, channel, id));
656c92f222eSJames Bottomley 
65737c60f37SKashyap, Desai 	INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
658e80b002bSEric Moore 	mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
65937c60f37SKashyap, Desai 	timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ);
66037c60f37SKashyap, Desai 	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
66137c60f37SKashyap, Desai 		ret = -ETIME;
66237c60f37SKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n",
66337c60f37SKashyap, Desai 		    ioc->name, __func__));
66437c60f37SKashyap, Desai 		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
66537c60f37SKashyap, Desai 			goto out;
66637c60f37SKashyap, Desai 		if (!timeleft) {
66737c60f37SKashyap, Desai 			printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
66837c60f37SKashyap, Desai 			    ioc->name, __func__);
66937c60f37SKashyap, Desai 			mpt_HardResetHandler(ioc, CAN_SLEEP);
67037c60f37SKashyap, Desai 			mpt_free_msg_frame(ioc, mf);
67137c60f37SKashyap, Desai 		}
67237c60f37SKashyap, Desai 		goto out;
67337c60f37SKashyap, Desai 	}
674c92f222eSJames Bottomley 
67537c60f37SKashyap, Desai 	ret = ioc->internal_cmds.completion_code;
676c92f222eSJames Bottomley 
67737c60f37SKashyap, Desai  out:
67837c60f37SKashyap, Desai 	CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
67937c60f37SKashyap, Desai 	mutex_unlock(&ioc->internal_cmds.mutex);
68037c60f37SKashyap, Desai 	return ret;
681c92f222eSJames Bottomley }
682c92f222eSJames Bottomley 
mptspi_dv_device(struct _MPT_SCSI_HOST * hd,struct scsi_device * sdev)683c92f222eSJames Bottomley static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
684c92f222eSJames Bottomley 			     struct scsi_device *sdev)
685c92f222eSJames Bottomley {
686c92f222eSJames Bottomley 	VirtTarget *vtarget = scsi_target(sdev)->hostdata;
687e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
688c92f222eSJames Bottomley 
689c92f222eSJames Bottomley 	/* no DV on RAID devices */
690c92f222eSJames Bottomley 	if (sdev->channel == 0 &&
691793955f5SEric Moore 	    mptspi_is_raid(hd, sdev->id))
692c92f222eSJames Bottomley 		return;
693c92f222eSJames Bottomley 
694c92f222eSJames Bottomley 	/* If this is a piece of a RAID, then quiesce first */
695c92f222eSJames Bottomley 	if (sdev->channel == 1 &&
696793955f5SEric Moore 	    mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
697c51d0beaSEric Moore 		starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
698e80b002bSEric Moore 		    "Integrated RAID quiesce failed\n", ioc->name);
699c92f222eSJames Bottomley 		return;
700c92f222eSJames Bottomley 	}
701c92f222eSJames Bottomley 
70272978245SEric Moore 	hd->spi_pending |= (1 << sdev->id);
703c92f222eSJames Bottomley 	spi_dv_device(sdev);
70472978245SEric Moore 	hd->spi_pending &= ~(1 << sdev->id);
705c92f222eSJames Bottomley 
706c92f222eSJames Bottomley 	if (sdev->channel == 1 &&
707793955f5SEric Moore 	    mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
708c51d0beaSEric Moore 		starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
709e80b002bSEric Moore 		    "Integrated RAID resume failed\n", ioc->name);
710c92f222eSJames Bottomley 
711c92f222eSJames Bottomley 	mptspi_read_parameters(sdev->sdev_target);
712c92f222eSJames Bottomley 	spi_display_xfer_agreement(sdev->sdev_target);
713c92f222eSJames Bottomley 	mptspi_read_parameters(sdev->sdev_target);
714c92f222eSJames Bottomley }
715c92f222eSJames Bottomley 
mptspi_slave_alloc(struct scsi_device * sdev)716c92f222eSJames Bottomley static int mptspi_slave_alloc(struct scsi_device *sdev)
717c92f222eSJames Bottomley {
718e7eae9f6SEric Moore 	MPT_SCSI_HOST *hd = shost_priv(sdev->host);
719793955f5SEric Moore 	VirtTarget		*vtarget;
720a69de507SEric Moore 	VirtDevice		*vdevice;
721793955f5SEric Moore 	struct scsi_target 	*starget;
722e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
723c92f222eSJames Bottomley 
724793955f5SEric Moore 	if (sdev->channel == 1 &&
725e80b002bSEric Moore 		mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0)
726793955f5SEric Moore 			return -ENXIO;
727c92f222eSJames Bottomley 
728a69de507SEric Moore 	vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
729a69de507SEric Moore 	if (!vdevice) {
730793955f5SEric Moore 		printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
731e80b002bSEric Moore 				ioc->name, sizeof(VirtDevice));
732793955f5SEric Moore 		return -ENOMEM;
733c92f222eSJames Bottomley 	}
734c92f222eSJames Bottomley 
735a69de507SEric Moore 	vdevice->lun = sdev->lun;
736a69de507SEric Moore 	sdev->hostdata = vdevice;
737c92f222eSJames Bottomley 
738793955f5SEric Moore 	starget = scsi_target(sdev);
739793955f5SEric Moore 	vtarget = starget->hostdata;
740a69de507SEric Moore 	vdevice->vtarget = vtarget;
741793955f5SEric Moore 	vtarget->num_luns++;
742c92f222eSJames Bottomley 
743793955f5SEric Moore 	if (sdev->channel == 1)
744c92f222eSJames Bottomley 		sdev->no_uld_attach = 1;
745c92f222eSJames Bottomley 
746c92f222eSJames Bottomley 	return 0;
747c92f222eSJames Bottomley }
748c92f222eSJames Bottomley 
mptspi_slave_configure(struct scsi_device * sdev)749c92f222eSJames Bottomley static int mptspi_slave_configure(struct scsi_device *sdev)
750c92f222eSJames Bottomley {
751e7eae9f6SEric Moore 	struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host);
7525a9c47b1SEric Moore 	VirtTarget *vtarget = scsi_target(sdev)->hostdata;
75329982e9aSDoug Chapman 	int ret;
75429982e9aSDoug Chapman 
75529982e9aSDoug Chapman 	mptspi_initTarget(hd, vtarget, sdev);
75629982e9aSDoug Chapman 
75729982e9aSDoug Chapman 	ret = mptscsih_slave_configure(sdev);
758c92f222eSJames Bottomley 
759c92f222eSJames Bottomley 	if (ret)
760c92f222eSJames Bottomley 		return ret;
761c92f222eSJames Bottomley 
762d6ecdd63SPrakash, Sathya 	ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x"
763873c82edSEric Moore 		" max_offset=0x%02x max_width=%d\n", hd->ioc->name,
764873c82edSEric Moore 		sdev->id, spi_min_period(scsi_target(sdev)),
765873c82edSEric Moore 		spi_max_offset(scsi_target(sdev)),
766873c82edSEric Moore 		spi_max_width(scsi_target(sdev))));
767873c82edSEric Moore 
768c92f222eSJames Bottomley 	if ((sdev->channel == 1 ||
769793955f5SEric Moore 	     !(mptspi_is_raid(hd, sdev->id))) &&
770c92f222eSJames Bottomley 	    !spi_initial_dv(sdev->sdev_target))
771c92f222eSJames Bottomley 		mptspi_dv_device(hd, sdev);
772c92f222eSJames Bottomley 
773c92f222eSJames Bottomley 	return 0;
774c92f222eSJames Bottomley }
775c92f222eSJames Bottomley 
776793955f5SEric Moore static int
mptspi_qcmd(struct Scsi_Host * shost,struct scsi_cmnd * SCpnt)777a48ac9e5SMatthew Wilcox mptspi_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)
778793955f5SEric Moore {
779a48ac9e5SMatthew Wilcox 	struct _MPT_SCSI_HOST *hd = shost_priv(shost);
780a69de507SEric Moore 	VirtDevice	*vdevice = SCpnt->device->hostdata;
781e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
782793955f5SEric Moore 
783a69de507SEric Moore 	if (!vdevice || !vdevice->vtarget) {
784793955f5SEric Moore 		SCpnt->result = DID_NO_CONNECT << 16;
7851ae6d167SBart Van Assche 		scsi_done(SCpnt);
786793955f5SEric Moore 		return 0;
787793955f5SEric Moore 	}
788793955f5SEric Moore 
789793955f5SEric Moore 	if (SCpnt->device->channel == 1 &&
790e80b002bSEric Moore 		mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) {
791793955f5SEric Moore 		SCpnt->result = DID_NO_CONNECT << 16;
7921ae6d167SBart Van Assche 		scsi_done(SCpnt);
793793955f5SEric Moore 		return 0;
794793955f5SEric Moore 	}
795793955f5SEric Moore 
796873c82edSEric Moore 	if (spi_dv_pending(scsi_target(SCpnt->device)))
797e80b002bSEric Moore 		ddvprintk(ioc, scsi_print_command(SCpnt));
798873c82edSEric Moore 
799a48ac9e5SMatthew Wilcox 	return mptscsih_qcmd(SCpnt);
800793955f5SEric Moore }
801793955f5SEric Moore 
mptspi_slave_destroy(struct scsi_device * sdev)802c92f222eSJames Bottomley static void mptspi_slave_destroy(struct scsi_device *sdev)
803c92f222eSJames Bottomley {
804c92f222eSJames Bottomley 	struct scsi_target *starget = scsi_target(sdev);
805c92f222eSJames Bottomley 	VirtTarget *vtarget = starget->hostdata;
806c92f222eSJames Bottomley 	VirtDevice *vdevice = sdev->hostdata;
807c92f222eSJames Bottomley 
808c92f222eSJames Bottomley 	/* Will this be the last lun on a non-raid device? */
809c92f222eSJames Bottomley 	if (vtarget->num_luns == 1 && vdevice->configured_lun) {
810c92f222eSJames Bottomley 		struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
811c92f222eSJames Bottomley 
812c92f222eSJames Bottomley 		/* Async Narrow */
813c92f222eSJames Bottomley 		pg1.RequestedParameters = 0;
814c92f222eSJames Bottomley 		pg1.Reserved = 0;
815c92f222eSJames Bottomley 		pg1.Configuration = 0;
816c92f222eSJames Bottomley 
817c92f222eSJames Bottomley 		mptspi_write_spi_device_pg1(starget, &pg1);
818c92f222eSJames Bottomley 	}
819c92f222eSJames Bottomley 
820c92f222eSJames Bottomley 	mptscsih_slave_destroy(sdev);
821c92f222eSJames Bottomley }
822c92f222eSJames Bottomley 
823*95a24cf1SBart Van Assche static const struct scsi_host_template mptspi_driver_template = {
824f78496daSMoore, Eric Dean 	.module				= THIS_MODULE,
825243eabcfSMoore, Eric Dean  	.proc_name			= "mptspi",
826cac19703SAl Viro 	.show_info			= mptscsih_show_info,
827243eabcfSMoore, Eric Dean  	.name				= "MPT SPI Host",
828243eabcfSMoore, Eric Dean  	.info				= mptscsih_info,
829793955f5SEric Moore 	.queuecommand			= mptspi_qcmd,
830c92f222eSJames Bottomley 	.target_alloc			= mptspi_target_alloc,
831c92f222eSJames Bottomley 	.slave_alloc			= mptspi_slave_alloc,
832c92f222eSJames Bottomley 	.slave_configure		= mptspi_slave_configure,
833793955f5SEric Moore 	.target_destroy			= mptspi_target_destroy,
834c92f222eSJames Bottomley 	.slave_destroy			= mptspi_slave_destroy,
8356e3815baSMoore, Eric Dean 	.change_queue_depth 		= mptscsih_change_queue_depth,
836243eabcfSMoore, Eric Dean  	.eh_abort_handler		= mptscsih_abort,
837243eabcfSMoore, Eric Dean  	.eh_device_reset_handler	= mptscsih_dev_reset,
838243eabcfSMoore, Eric Dean  	.eh_bus_reset_handler		= mptscsih_bus_reset,
839243eabcfSMoore, Eric Dean  	.eh_host_reset_handler		= mptscsih_host_reset,
840243eabcfSMoore, Eric Dean  	.bios_param			= mptscsih_bios_param,
841243eabcfSMoore, Eric Dean  	.can_queue			= MPT_SCSI_CAN_QUEUE,
842243eabcfSMoore, Eric Dean  	.this_id			= -1,
843243eabcfSMoore, Eric Dean  	.sg_tablesize			= MPT_SCSI_SG_DEPTH,
844243eabcfSMoore, Eric Dean  	.max_sectors			= 8192,
845243eabcfSMoore, Eric Dean  	.cmd_per_lun			= 7,
8462899836fSBart Van Assche 	.shost_groups			= mptscsih_host_attr_groups,
847243eabcfSMoore, Eric Dean  };
848243eabcfSMoore, Eric Dean  
mptspi_write_spi_device_pg1(struct scsi_target * starget,struct _CONFIG_PAGE_SCSI_DEVICE_1 * pass_pg1)849c92f222eSJames Bottomley static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
850c92f222eSJames Bottomley 			       struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1)
851c92f222eSJames Bottomley {
852c92f222eSJames Bottomley 	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
853e7eae9f6SEric Moore 	struct _MPT_SCSI_HOST *hd = shost_priv(shost);
854c92f222eSJames Bottomley 	struct _MPT_ADAPTER *ioc = hd->ioc;
855c92f222eSJames Bottomley 	struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1;
856c92f222eSJames Bottomley 	dma_addr_t pg1_dma;
857c92f222eSJames Bottomley 	int size;
858c92f222eSJames Bottomley 	struct _x_config_parms cfg;
859c92f222eSJames Bottomley 	struct _CONFIG_PAGE_HEADER hdr;
860c92f222eSJames Bottomley 	int err = -EBUSY;
86119fff154SKashyap, Desai 	u32 nego_parms;
86219fff154SKashyap, Desai 	u32 period;
86319fff154SKashyap, Desai 	struct scsi_device *sdev;
86419fff154SKashyap, Desai 	int i;
865c92f222eSJames Bottomley 
866c92f222eSJames Bottomley 	/* don't allow updating nego parameters on RAID devices */
867c92f222eSJames Bottomley 	if (starget->channel == 0 &&
868793955f5SEric Moore 	    mptspi_is_raid(hd, starget->id))
869c92f222eSJames Bottomley 		return -1;
870c92f222eSJames Bottomley 
871c92f222eSJames Bottomley 	size = ioc->spi_data.sdp1length * 4;
872c92f222eSJames Bottomley 
873c92f222eSJames Bottomley 	pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL);
874c92f222eSJames Bottomley 	if (pg1 == NULL) {
875c51d0beaSEric Moore 		starget_printk(KERN_ERR, starget, MYIOC_s_FMT
87629dd3609SEric Moore 		    "dma_alloc_coherent for parameters failed\n", ioc->name);
877c92f222eSJames Bottomley 		return -EINVAL;
878c92f222eSJames Bottomley 	}
879c92f222eSJames Bottomley 
880c92f222eSJames Bottomley 	memset(&hdr, 0, sizeof(hdr));
881c92f222eSJames Bottomley 
882c92f222eSJames Bottomley 	hdr.PageVersion = ioc->spi_data.sdp1version;
883c92f222eSJames Bottomley 	hdr.PageLength = ioc->spi_data.sdp1length;
884c92f222eSJames Bottomley 	hdr.PageNumber = 1;
885c92f222eSJames Bottomley 	hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
886c92f222eSJames Bottomley 
887c92f222eSJames Bottomley 	memset(&cfg, 0, sizeof(cfg));
888c92f222eSJames Bottomley 
889c92f222eSJames Bottomley 	cfg.cfghdr.hdr = &hdr;
890c92f222eSJames Bottomley 	cfg.physAddr = pg1_dma;
891c92f222eSJames Bottomley 	cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
892c92f222eSJames Bottomley 	cfg.dir = 1;
893c92f222eSJames Bottomley 	cfg.pageAddr = starget->id;
894c92f222eSJames Bottomley 
895c92f222eSJames Bottomley 	memcpy(pg1, pass_pg1, size);
896c92f222eSJames Bottomley 
897c92f222eSJames Bottomley 	pg1->Header.PageVersion = hdr.PageVersion;
898c92f222eSJames Bottomley 	pg1->Header.PageLength = hdr.PageLength;
899c92f222eSJames Bottomley 	pg1->Header.PageNumber = hdr.PageNumber;
900c92f222eSJames Bottomley 	pg1->Header.PageType = hdr.PageType;
901c92f222eSJames Bottomley 
90219fff154SKashyap, Desai 	nego_parms = le32_to_cpu(pg1->RequestedParameters);
90319fff154SKashyap, Desai 	period = (nego_parms & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK) >>
90419fff154SKashyap, Desai 		MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD;
90519fff154SKashyap, Desai 	if (period == 8) {
90619fff154SKashyap, Desai 		/* Turn on inline data padding for TAPE when running U320 */
90719fff154SKashyap, Desai 		for (i = 0 ; i < 16; i++) {
90819fff154SKashyap, Desai 			sdev = scsi_device_lookup_by_target(starget, i);
90919fff154SKashyap, Desai 			if (sdev && sdev->type == TYPE_TAPE) {
91019fff154SKashyap, Desai 				sdev_printk(KERN_DEBUG, sdev, MYIOC_s_FMT
91119fff154SKashyap, Desai 					    "IDP:ON\n", ioc->name);
91219fff154SKashyap, Desai 				nego_parms |= MPI_SCSIDEVPAGE1_RP_IDP;
91319fff154SKashyap, Desai 				pg1->RequestedParameters =
91419fff154SKashyap, Desai 				    cpu_to_le32(nego_parms);
91519fff154SKashyap, Desai 				break;
91619fff154SKashyap, Desai 			}
91719fff154SKashyap, Desai 		}
91819fff154SKashyap, Desai 	}
91919fff154SKashyap, Desai 
920873c82edSEric Moore 	mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
921873c82edSEric Moore 
922c92f222eSJames Bottomley 	if (mpt_config(ioc, &cfg)) {
923c51d0beaSEric Moore 		starget_printk(KERN_ERR, starget, MYIOC_s_FMT
92429dd3609SEric Moore 		    "mpt_config failed\n", ioc->name);
925c92f222eSJames Bottomley 		goto out_free;
926c92f222eSJames Bottomley 	}
927c92f222eSJames Bottomley 	err = 0;
928c92f222eSJames Bottomley 
929c92f222eSJames Bottomley  out_free:
930c92f222eSJames Bottomley 	dma_free_coherent(&ioc->pcidev->dev, size, pg1, pg1_dma);
931c92f222eSJames Bottomley 	return err;
932c92f222eSJames Bottomley }
933c92f222eSJames Bottomley 
mptspi_write_offset(struct scsi_target * starget,int offset)934c92f222eSJames Bottomley static void mptspi_write_offset(struct scsi_target *starget, int offset)
935c92f222eSJames Bottomley {
936c92f222eSJames Bottomley 	struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
937c92f222eSJames Bottomley 	u32 nego;
938c92f222eSJames Bottomley 
939c92f222eSJames Bottomley 	if (offset < 0)
940c92f222eSJames Bottomley 		offset = 0;
941c92f222eSJames Bottomley 
942c92f222eSJames Bottomley 	if (offset > 255)
943c92f222eSJames Bottomley 		offset = 255;
944c92f222eSJames Bottomley 
945c92f222eSJames Bottomley 	if (spi_offset(starget) == -1)
946c92f222eSJames Bottomley 		mptspi_read_parameters(starget);
947c92f222eSJames Bottomley 
948c92f222eSJames Bottomley 	spi_offset(starget) = offset;
949c92f222eSJames Bottomley 
950c92f222eSJames Bottomley 	nego = mptspi_getRP(starget);
951c92f222eSJames Bottomley 
952c92f222eSJames Bottomley 	pg1.RequestedParameters = cpu_to_le32(nego);
953c92f222eSJames Bottomley 	pg1.Reserved = 0;
954c92f222eSJames Bottomley 	pg1.Configuration = 0;
955c92f222eSJames Bottomley 
956c92f222eSJames Bottomley 	mptspi_write_spi_device_pg1(starget, &pg1);
957c92f222eSJames Bottomley }
958c92f222eSJames Bottomley 
mptspi_write_period(struct scsi_target * starget,int period)959c92f222eSJames Bottomley static void mptspi_write_period(struct scsi_target *starget, int period)
960c92f222eSJames Bottomley {
961c92f222eSJames Bottomley 	struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
962c92f222eSJames Bottomley 	u32 nego;
963c92f222eSJames Bottomley 
964c92f222eSJames Bottomley 	if (period < 8)
965c92f222eSJames Bottomley 		period = 8;
966c92f222eSJames Bottomley 
967c92f222eSJames Bottomley 	if (period > 255)
968c92f222eSJames Bottomley 		period = 255;
969c92f222eSJames Bottomley 
970c92f222eSJames Bottomley 	if (spi_period(starget) == -1)
971c92f222eSJames Bottomley 		mptspi_read_parameters(starget);
972c92f222eSJames Bottomley 
973c92f222eSJames Bottomley 	if (period == 8) {
974c92f222eSJames Bottomley 		spi_iu(starget) = 1;
975c92f222eSJames Bottomley 		spi_dt(starget) = 1;
976c92f222eSJames Bottomley 	} else if (period == 9) {
977c92f222eSJames Bottomley 		spi_dt(starget) = 1;
978c92f222eSJames Bottomley 	}
979c92f222eSJames Bottomley 
980c92f222eSJames Bottomley 	spi_period(starget) = period;
981c92f222eSJames Bottomley 
982c92f222eSJames Bottomley 	nego = mptspi_getRP(starget);
983c92f222eSJames Bottomley 
984c92f222eSJames Bottomley 	pg1.RequestedParameters = cpu_to_le32(nego);
985c92f222eSJames Bottomley 	pg1.Reserved = 0;
986c92f222eSJames Bottomley 	pg1.Configuration = 0;
987c92f222eSJames Bottomley 
988c92f222eSJames Bottomley 	mptspi_write_spi_device_pg1(starget, &pg1);
989c92f222eSJames Bottomley }
990c92f222eSJames Bottomley 
mptspi_write_dt(struct scsi_target * starget,int dt)991c92f222eSJames Bottomley static void mptspi_write_dt(struct scsi_target *starget, int dt)
992c92f222eSJames Bottomley {
993c92f222eSJames Bottomley 	struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
994c92f222eSJames Bottomley 	u32 nego;
995c92f222eSJames Bottomley 
996c92f222eSJames Bottomley 	if (spi_period(starget) == -1)
997c92f222eSJames Bottomley 		mptspi_read_parameters(starget);
998c92f222eSJames Bottomley 
999c92f222eSJames Bottomley 	if (!dt && spi_period(starget) < 10)
1000c92f222eSJames Bottomley 		spi_period(starget) = 10;
1001c92f222eSJames Bottomley 
1002c92f222eSJames Bottomley 	spi_dt(starget) = dt;
1003c92f222eSJames Bottomley 
1004c92f222eSJames Bottomley 	nego = mptspi_getRP(starget);
1005c92f222eSJames Bottomley 
1006c92f222eSJames Bottomley 
1007c92f222eSJames Bottomley 	pg1.RequestedParameters = cpu_to_le32(nego);
1008c92f222eSJames Bottomley 	pg1.Reserved = 0;
1009c92f222eSJames Bottomley 	pg1.Configuration = 0;
1010c92f222eSJames Bottomley 
1011c92f222eSJames Bottomley 	mptspi_write_spi_device_pg1(starget, &pg1);
1012c92f222eSJames Bottomley }
1013c92f222eSJames Bottomley 
mptspi_write_iu(struct scsi_target * starget,int iu)1014c92f222eSJames Bottomley static void mptspi_write_iu(struct scsi_target *starget, int iu)
1015c92f222eSJames Bottomley {
1016c92f222eSJames Bottomley 	struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
1017c92f222eSJames Bottomley 	u32 nego;
1018c92f222eSJames Bottomley 
1019c92f222eSJames Bottomley 	if (spi_period(starget) == -1)
1020c92f222eSJames Bottomley 		mptspi_read_parameters(starget);
1021c92f222eSJames Bottomley 
1022c92f222eSJames Bottomley 	if (!iu && spi_period(starget) < 9)
1023c92f222eSJames Bottomley 		spi_period(starget) = 9;
1024c92f222eSJames Bottomley 
1025c92f222eSJames Bottomley 	spi_iu(starget) = iu;
1026c92f222eSJames Bottomley 
1027c92f222eSJames Bottomley 	nego = mptspi_getRP(starget);
1028c92f222eSJames Bottomley 
1029c92f222eSJames Bottomley 	pg1.RequestedParameters = cpu_to_le32(nego);
1030c92f222eSJames Bottomley 	pg1.Reserved = 0;
1031c92f222eSJames Bottomley 	pg1.Configuration = 0;
1032c92f222eSJames Bottomley 
1033c92f222eSJames Bottomley 	mptspi_write_spi_device_pg1(starget, &pg1);
1034c92f222eSJames Bottomley }
1035c92f222eSJames Bottomley 
1036c92f222eSJames Bottomley #define MPTSPI_SIMPLE_TRANSPORT_PARM(parm) 				\
1037c92f222eSJames Bottomley static void mptspi_write_##parm(struct scsi_target *starget, int parm)\
1038c92f222eSJames Bottomley {									\
1039c92f222eSJames Bottomley 	struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;				\
1040c92f222eSJames Bottomley 	u32 nego;							\
1041c92f222eSJames Bottomley 									\
1042c92f222eSJames Bottomley 	spi_##parm(starget) = parm;					\
1043c92f222eSJames Bottomley 									\
1044c92f222eSJames Bottomley 	nego = mptspi_getRP(starget);					\
1045c92f222eSJames Bottomley 									\
1046c92f222eSJames Bottomley 	pg1.RequestedParameters = cpu_to_le32(nego);			\
1047c92f222eSJames Bottomley 	pg1.Reserved = 0;						\
1048c92f222eSJames Bottomley 	pg1.Configuration = 0;						\
1049c92f222eSJames Bottomley 									\
1050c92f222eSJames Bottomley 	mptspi_write_spi_device_pg1(starget, &pg1);				\
1051c92f222eSJames Bottomley }
1052c92f222eSJames Bottomley 
1053c92f222eSJames Bottomley MPTSPI_SIMPLE_TRANSPORT_PARM(rd_strm)
MPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow)1054c92f222eSJames Bottomley MPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow)
1055c92f222eSJames Bottomley MPTSPI_SIMPLE_TRANSPORT_PARM(rti)
1056c92f222eSJames Bottomley MPTSPI_SIMPLE_TRANSPORT_PARM(hold_mcs)
1057c92f222eSJames Bottomley MPTSPI_SIMPLE_TRANSPORT_PARM(pcomp_en)
1058c92f222eSJames Bottomley 
1059c92f222eSJames Bottomley static void mptspi_write_qas(struct scsi_target *starget, int qas)
1060c92f222eSJames Bottomley {
1061c92f222eSJames Bottomley 	struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
1062c92f222eSJames Bottomley 	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1063e7eae9f6SEric Moore 	struct _MPT_SCSI_HOST *hd = shost_priv(shost);
1064c92f222eSJames Bottomley 	VirtTarget *vtarget = starget->hostdata;
1065c92f222eSJames Bottomley 	u32 nego;
1066c92f222eSJames Bottomley 
1067c92f222eSJames Bottomley 	if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) ||
1068c92f222eSJames Bottomley 	    hd->ioc->spi_data.noQas)
1069c92f222eSJames Bottomley 		spi_qas(starget) = 0;
1070c92f222eSJames Bottomley 	else
1071c92f222eSJames Bottomley 		spi_qas(starget) = qas;
1072c92f222eSJames Bottomley 
1073c92f222eSJames Bottomley 	nego = mptspi_getRP(starget);
1074c92f222eSJames Bottomley 
1075c92f222eSJames Bottomley 	pg1.RequestedParameters = cpu_to_le32(nego);
1076c92f222eSJames Bottomley 	pg1.Reserved = 0;
1077c92f222eSJames Bottomley 	pg1.Configuration = 0;
1078c92f222eSJames Bottomley 
1079c92f222eSJames Bottomley 	mptspi_write_spi_device_pg1(starget, &pg1);
1080c92f222eSJames Bottomley }
1081c92f222eSJames Bottomley 
mptspi_write_width(struct scsi_target * starget,int width)1082c92f222eSJames Bottomley static void mptspi_write_width(struct scsi_target *starget, int width)
1083c92f222eSJames Bottomley {
1084c92f222eSJames Bottomley 	struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
1085c92f222eSJames Bottomley 	u32 nego;
1086c92f222eSJames Bottomley 
1087c92f222eSJames Bottomley 	if (!width) {
1088c92f222eSJames Bottomley 		spi_dt(starget) = 0;
1089c92f222eSJames Bottomley 		if (spi_period(starget) < 10)
1090c92f222eSJames Bottomley 			spi_period(starget) = 10;
1091c92f222eSJames Bottomley 	}
1092c92f222eSJames Bottomley 
1093c92f222eSJames Bottomley 	spi_width(starget) = width;
1094c92f222eSJames Bottomley 
1095c92f222eSJames Bottomley 	nego = mptspi_getRP(starget);
1096c92f222eSJames Bottomley 
1097c92f222eSJames Bottomley 	pg1.RequestedParameters = cpu_to_le32(nego);
1098c92f222eSJames Bottomley 	pg1.Reserved = 0;
1099c92f222eSJames Bottomley 	pg1.Configuration = 0;
1100c92f222eSJames Bottomley 
1101c92f222eSJames Bottomley 	mptspi_write_spi_device_pg1(starget, &pg1);
1102c92f222eSJames Bottomley }
1103c92f222eSJames Bottomley 
1104c92f222eSJames Bottomley struct work_queue_wrapper {
1105c92f222eSJames Bottomley 	struct work_struct	work;
1106c92f222eSJames Bottomley 	struct _MPT_SCSI_HOST	*hd;
1107c92f222eSJames Bottomley 	int			disk;
1108c92f222eSJames Bottomley };
1109c92f222eSJames Bottomley 
mpt_work_wrapper(struct work_struct * work)1110c4028958SDavid Howells static void mpt_work_wrapper(struct work_struct *work)
1111c92f222eSJames Bottomley {
1112c4028958SDavid Howells 	struct work_queue_wrapper *wqw =
1113c4028958SDavid Howells 		container_of(work, struct work_queue_wrapper, work);
1114c92f222eSJames Bottomley 	struct _MPT_SCSI_HOST *hd = wqw->hd;
1115e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
1116e80b002bSEric Moore 	struct Scsi_Host *shost = ioc->sh;
1117c92f222eSJames Bottomley 	struct scsi_device *sdev;
1118c92f222eSJames Bottomley 	int disk = wqw->disk;
1119c92f222eSJames Bottomley 	struct _CONFIG_PAGE_IOC_3 *pg3;
1120c92f222eSJames Bottomley 
1121c92f222eSJames Bottomley 	kfree(wqw);
1122c92f222eSJames Bottomley 
1123e80b002bSEric Moore 	mpt_findImVolumes(ioc);
1124e80b002bSEric Moore 	pg3 = ioc->raid_data.pIocPg3;
1125c92f222eSJames Bottomley 	if (!pg3)
1126c92f222eSJames Bottomley 		return;
1127c92f222eSJames Bottomley 
1128c92f222eSJames Bottomley 	shost_for_each_device(sdev,shost) {
1129c92f222eSJames Bottomley 		struct scsi_target *starget = scsi_target(sdev);
1130c92f222eSJames Bottomley 		VirtTarget *vtarget = starget->hostdata;
1131c92f222eSJames Bottomley 
1132c92f222eSJames Bottomley 		/* only want to search RAID components */
1133c92f222eSJames Bottomley 		if (sdev->channel != 1)
1134c92f222eSJames Bottomley 			continue;
1135c92f222eSJames Bottomley 
1136793955f5SEric Moore 		/* The id is the raid PhysDiskNum, even if
1137c92f222eSJames Bottomley 		 * starget->id is the actual target address */
1138793955f5SEric Moore 		if(vtarget->id != disk)
1139c92f222eSJames Bottomley 			continue;
1140c92f222eSJames Bottomley 
1141c51d0beaSEric Moore 		starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT
1142e80b002bSEric Moore 		    "Integrated RAID requests DV of new device\n", ioc->name);
1143c92f222eSJames Bottomley 		mptspi_dv_device(hd, sdev);
1144c92f222eSJames Bottomley 	}
1145c51d0beaSEric Moore 	shost_printk(KERN_INFO, shost, MYIOC_s_FMT
1146e80b002bSEric Moore 	    "Integrated RAID detects new device %d\n", ioc->name, disk);
11471d645088SHannes Reinecke 	scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, SCSI_SCAN_RESCAN);
1148c92f222eSJames Bottomley }
1149c92f222eSJames Bottomley 
1150c92f222eSJames Bottomley 
mpt_dv_raid(struct _MPT_SCSI_HOST * hd,int disk)1151c92f222eSJames Bottomley static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk)
1152c92f222eSJames Bottomley {
1153c92f222eSJames Bottomley 	struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
1154e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
1155c92f222eSJames Bottomley 
1156c92f222eSJames Bottomley 	if (!wqw) {
1157c51d0beaSEric Moore 		shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT
1158c92f222eSJames Bottomley 		    "Failed to act on RAID event for physical disk %d\n",
1159e80b002bSEric Moore 		    ioc->name, disk);
1160c92f222eSJames Bottomley 		return;
1161c92f222eSJames Bottomley 	}
1162c4028958SDavid Howells 	INIT_WORK(&wqw->work, mpt_work_wrapper);
1163c92f222eSJames Bottomley 	wqw->hd = hd;
1164c92f222eSJames Bottomley 	wqw->disk = disk;
1165c92f222eSJames Bottomley 
1166c92f222eSJames Bottomley 	schedule_work(&wqw->work);
1167c92f222eSJames Bottomley }
1168c92f222eSJames Bottomley 
1169c92f222eSJames Bottomley static int
mptspi_event_process(MPT_ADAPTER * ioc,EventNotificationReply_t * pEvReply)1170c92f222eSJames Bottomley mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1171c92f222eSJames Bottomley {
1172c92f222eSJames Bottomley 	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1173e7eae9f6SEric Moore 	struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1174c92f222eSJames Bottomley 
1175ffb7fef3SKashyap, Desai 	if (ioc->bus_type != SPI)
1176ffb7fef3SKashyap, Desai 		return 0;
1177ffb7fef3SKashyap, Desai 
1178c92f222eSJames Bottomley 	if (hd && event ==  MPI_EVENT_INTEGRATED_RAID) {
1179c92f222eSJames Bottomley 		int reason
1180c92f222eSJames Bottomley 			= (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
1181c92f222eSJames Bottomley 
1182c92f222eSJames Bottomley 		if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
1183c92f222eSJames Bottomley 			int disk = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
1184c92f222eSJames Bottomley 			mpt_dv_raid(hd, disk);
1185c92f222eSJames Bottomley 		}
1186c92f222eSJames Bottomley 	}
1187c92f222eSJames Bottomley 	return mptscsih_event_process(ioc, pEvReply);
1188c92f222eSJames Bottomley }
1189c92f222eSJames Bottomley 
1190c92f222eSJames Bottomley static int
mptspi_deny_binding(struct scsi_target * starget)1191c92f222eSJames Bottomley mptspi_deny_binding(struct scsi_target *starget)
1192c92f222eSJames Bottomley {
1193c92f222eSJames Bottomley 	struct _MPT_SCSI_HOST *hd =
1194c92f222eSJames Bottomley 		(struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata;
1195793955f5SEric Moore 	return ((mptspi_is_raid(hd, starget->id)) &&
1196c92f222eSJames Bottomley 		starget->channel == 0) ? 1 : 0;
1197c92f222eSJames Bottomley }
1198c92f222eSJames Bottomley 
1199c92f222eSJames Bottomley static struct spi_function_template mptspi_transport_functions = {
1200c92f222eSJames Bottomley 	.get_offset	= mptspi_read_parameters,
1201c92f222eSJames Bottomley 	.set_offset	= mptspi_write_offset,
1202c92f222eSJames Bottomley 	.show_offset	= 1,
1203c92f222eSJames Bottomley 	.get_period	= mptspi_read_parameters,
1204c92f222eSJames Bottomley 	.set_period	= mptspi_write_period,
1205c92f222eSJames Bottomley 	.show_period	= 1,
1206c92f222eSJames Bottomley 	.get_width	= mptspi_read_parameters,
1207c92f222eSJames Bottomley 	.set_width	= mptspi_write_width,
1208c92f222eSJames Bottomley 	.show_width	= 1,
1209c92f222eSJames Bottomley 	.get_iu		= mptspi_read_parameters,
1210c92f222eSJames Bottomley 	.set_iu		= mptspi_write_iu,
1211c92f222eSJames Bottomley 	.show_iu	= 1,
1212c92f222eSJames Bottomley 	.get_dt		= mptspi_read_parameters,
1213c92f222eSJames Bottomley 	.set_dt		= mptspi_write_dt,
1214c92f222eSJames Bottomley 	.show_dt	= 1,
1215c92f222eSJames Bottomley 	.get_qas	= mptspi_read_parameters,
1216c92f222eSJames Bottomley 	.set_qas	= mptspi_write_qas,
1217c92f222eSJames Bottomley 	.show_qas	= 1,
1218c92f222eSJames Bottomley 	.get_wr_flow	= mptspi_read_parameters,
1219c92f222eSJames Bottomley 	.set_wr_flow	= mptspi_write_wr_flow,
1220c92f222eSJames Bottomley 	.show_wr_flow	= 1,
1221c92f222eSJames Bottomley 	.get_rd_strm	= mptspi_read_parameters,
1222c92f222eSJames Bottomley 	.set_rd_strm	= mptspi_write_rd_strm,
1223c92f222eSJames Bottomley 	.show_rd_strm	= 1,
1224c92f222eSJames Bottomley 	.get_rti	= mptspi_read_parameters,
1225c92f222eSJames Bottomley 	.set_rti	= mptspi_write_rti,
1226c92f222eSJames Bottomley 	.show_rti	= 1,
1227c92f222eSJames Bottomley 	.get_pcomp_en	= mptspi_read_parameters,
1228c92f222eSJames Bottomley 	.set_pcomp_en	= mptspi_write_pcomp_en,
1229c92f222eSJames Bottomley 	.show_pcomp_en	= 1,
1230c92f222eSJames Bottomley 	.get_hold_mcs	= mptspi_read_parameters,
1231c92f222eSJames Bottomley 	.set_hold_mcs	= mptspi_write_hold_mcs,
1232c92f222eSJames Bottomley 	.show_hold_mcs	= 1,
1233c92f222eSJames Bottomley 	.deny_binding	= mptspi_deny_binding,
1234c92f222eSJames Bottomley };
1235243eabcfSMoore, Eric Dean  
1236243eabcfSMoore, Eric Dean  /****************************************************************************
1237243eabcfSMoore, Eric Dean   * Supported hardware
1238243eabcfSMoore, Eric Dean   */
1239243eabcfSMoore, Eric Dean  
1240243eabcfSMoore, Eric Dean  static struct pci_device_id mptspi_pci_table[] = {
124187cf8986SEric Moore 	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030,
1242243eabcfSMoore, Eric Dean  		PCI_ANY_ID, PCI_ANY_ID },
1243232f08fcSEric Moore 	{ PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030,
1244232f08fcSEric Moore 		PCI_ANY_ID, PCI_ANY_ID },
124587cf8986SEric Moore 	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035,
1246243eabcfSMoore, Eric Dean  		PCI_ANY_ID, PCI_ANY_ID },
1247243eabcfSMoore, Eric Dean  	{0}	/* Terminating entry */
1248243eabcfSMoore, Eric Dean  };
1249243eabcfSMoore, Eric Dean  MODULE_DEVICE_TABLE(pci, mptspi_pci_table);
1250243eabcfSMoore, Eric Dean  
12516e1cad02SEric Moore 
12526e1cad02SEric Moore /*
12536e1cad02SEric Moore  * renegotiate for a given target
12546e1cad02SEric Moore  */
12556e1cad02SEric Moore static void
mptspi_dv_renegotiate_work(struct work_struct * work)1256c4028958SDavid Howells mptspi_dv_renegotiate_work(struct work_struct *work)
12576e1cad02SEric Moore {
1258c4028958SDavid Howells 	struct work_queue_wrapper *wqw =
1259c4028958SDavid Howells 		container_of(work, struct work_queue_wrapper, work);
12606e1cad02SEric Moore 	struct _MPT_SCSI_HOST *hd = wqw->hd;
12616e1cad02SEric Moore 	struct scsi_device *sdev;
126272978245SEric Moore 	struct scsi_target *starget;
126372978245SEric Moore 	struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
126472978245SEric Moore 	u32 nego;
1265e80b002bSEric Moore 	MPT_ADAPTER *ioc = hd->ioc;
12666e1cad02SEric Moore 
12676e1cad02SEric Moore 	kfree(wqw);
12686e1cad02SEric Moore 
126972978245SEric Moore 	if (hd->spi_pending) {
1270e80b002bSEric Moore 		shost_for_each_device(sdev, ioc->sh) {
127172978245SEric Moore 			if  (hd->spi_pending & (1 << sdev->id))
127272978245SEric Moore 				continue;
127372978245SEric Moore 			starget = scsi_target(sdev);
127472978245SEric Moore 			nego = mptspi_getRP(starget);
127572978245SEric Moore 			pg1.RequestedParameters = cpu_to_le32(nego);
127672978245SEric Moore 			pg1.Reserved = 0;
127772978245SEric Moore 			pg1.Configuration = 0;
127872978245SEric Moore 			mptspi_write_spi_device_pg1(starget, &pg1);
127972978245SEric Moore 		}
128072978245SEric Moore 	} else {
1281e80b002bSEric Moore 		shost_for_each_device(sdev, ioc->sh)
12826e1cad02SEric Moore 			mptspi_dv_device(hd, sdev);
12836e1cad02SEric Moore 	}
128472978245SEric Moore }
12856e1cad02SEric Moore 
12866e1cad02SEric Moore static void
mptspi_dv_renegotiate(struct _MPT_SCSI_HOST * hd)12876e1cad02SEric Moore mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
12886e1cad02SEric Moore {
12896e1cad02SEric Moore 	struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
12906e1cad02SEric Moore 
12916e1cad02SEric Moore 	if (!wqw)
12926e1cad02SEric Moore 		return;
12936e1cad02SEric Moore 
1294c4028958SDavid Howells 	INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work);
12956e1cad02SEric Moore 	wqw->hd = hd;
12966e1cad02SEric Moore 
12976e1cad02SEric Moore 	schedule_work(&wqw->work);
12986e1cad02SEric Moore }
12996e1cad02SEric Moore 
13006e1cad02SEric Moore /*
13016e1cad02SEric Moore  * spi module reset handler
13026e1cad02SEric Moore  */
13036e1cad02SEric Moore static int
mptspi_ioc_reset(MPT_ADAPTER * ioc,int reset_phase)13046e1cad02SEric Moore mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
13056e1cad02SEric Moore {
13066e1cad02SEric Moore 	int rc;
13076e1cad02SEric Moore 
13086e1cad02SEric Moore 	rc = mptscsih_ioc_reset(ioc, reset_phase);
1309ffb7fef3SKashyap, Desai 	if ((ioc->bus_type != SPI) || (!rc))
1310ffb7fef3SKashyap, Desai 		return rc;
13116e1cad02SEric Moore 
1312081a5bcbSJames Bottomley 	/* only try to do a renegotiation if we're properly set up
1313081a5bcbSJames Bottomley 	 * if we get an ioc fault on bringup, ioc->sh will be NULL */
1314081a5bcbSJames Bottomley 	if (reset_phase == MPT_IOC_POST_RESET &&
1315081a5bcbSJames Bottomley 	    ioc->sh) {
1316081a5bcbSJames Bottomley 		struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1317081a5bcbSJames Bottomley 
13186e1cad02SEric Moore 		mptspi_dv_renegotiate(hd);
1319081a5bcbSJames Bottomley 	}
13206e1cad02SEric Moore 
13216e1cad02SEric Moore 	return rc;
13226e1cad02SEric Moore }
13236e1cad02SEric Moore 
1324c29ca9d1STom "spot" Callaway #ifdef CONFIG_PM
13256e1cad02SEric Moore /*
13266e1cad02SEric Moore  * spi module resume handler
13276e1cad02SEric Moore  */
13286e1cad02SEric Moore static int
mptspi_resume(struct pci_dev * pdev)13296e1cad02SEric Moore mptspi_resume(struct pci_dev *pdev)
13306e1cad02SEric Moore {
13316e1cad02SEric Moore 	MPT_ADAPTER 	*ioc = pci_get_drvdata(pdev);
1332e7eae9f6SEric Moore 	struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
13336e1cad02SEric Moore 	int rc;
13346e1cad02SEric Moore 
13356e1cad02SEric Moore 	rc = mptscsih_resume(pdev);
13366e1cad02SEric Moore 	mptspi_dv_renegotiate(hd);
13376e1cad02SEric Moore 
13386e1cad02SEric Moore 	return rc;
13396e1cad02SEric Moore }
1340c29ca9d1STom "spot" Callaway #endif
13416e1cad02SEric Moore 
1342243eabcfSMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1343243eabcfSMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1344243eabcfSMoore, Eric Dean  /*
1345243eabcfSMoore, Eric Dean   *	mptspi_probe - Installs scsi devices per bus.
1346243eabcfSMoore, Eric Dean   *	@pdev: Pointer to pci_dev structure
1347243eabcfSMoore, Eric Dean   *
1348243eabcfSMoore, Eric Dean   *	Returns 0 for success, non-zero for failure.
1349243eabcfSMoore, Eric Dean   *
1350243eabcfSMoore, Eric Dean   */
1351243eabcfSMoore, Eric Dean  static int
mptspi_probe(struct pci_dev * pdev,const struct pci_device_id * id)1352243eabcfSMoore, Eric Dean  mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1353243eabcfSMoore, Eric Dean  {
1354243eabcfSMoore, Eric Dean  	struct Scsi_Host	*sh;
1355243eabcfSMoore, Eric Dean  	MPT_SCSI_HOST		*hd;
1356243eabcfSMoore, Eric Dean  	MPT_ADAPTER 		*ioc;
1357243eabcfSMoore, Eric Dean  	unsigned long		 flags;
13581ca00bb7SChristoph Hellwig 	int			 ii;
1359243eabcfSMoore, Eric Dean  	int			 numSGE = 0;
1360243eabcfSMoore, Eric Dean  	int			 scale;
1361243eabcfSMoore, Eric Dean  	int			 ioc_cap;
1362243eabcfSMoore, Eric Dean  	int			error=0;
1363243eabcfSMoore, Eric Dean  	int			r;
1364243eabcfSMoore, Eric Dean  
1365243eabcfSMoore, Eric Dean  	if ((r = mpt_attach(pdev,id)) != 0)
1366243eabcfSMoore, Eric Dean  		return r;
1367243eabcfSMoore, Eric Dean  
1368243eabcfSMoore, Eric Dean  	ioc = pci_get_drvdata(pdev);
1369d335cc38SMoore, Eric Dean  	ioc->DoneCtx = mptspiDoneCtx;
1370d335cc38SMoore, Eric Dean  	ioc->TaskCtx = mptspiTaskCtx;
1371d335cc38SMoore, Eric Dean  	ioc->InternalCtx = mptspiInternalCtx;
1372243eabcfSMoore, Eric Dean  
1373243eabcfSMoore, Eric Dean  	/*  Added sanity check on readiness of the MPT adapter.
1374243eabcfSMoore, Eric Dean  	 */
1375243eabcfSMoore, Eric Dean  	if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1376243eabcfSMoore, Eric Dean  		printk(MYIOC_s_WARN_FMT
1377243eabcfSMoore, Eric Dean  		  "Skipping because it's not operational!\n",
1378243eabcfSMoore, Eric Dean  		  ioc->name);
13797acec1e7SMoore, Eric Dean 		error = -ENODEV;
13807acec1e7SMoore, Eric Dean 		goto out_mptspi_probe;
1381243eabcfSMoore, Eric Dean  	}
1382243eabcfSMoore, Eric Dean  
1383243eabcfSMoore, Eric Dean  	if (!ioc->active) {
1384243eabcfSMoore, Eric Dean  		printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1385243eabcfSMoore, Eric Dean  		  ioc->name);
13867acec1e7SMoore, Eric Dean 		error = -ENODEV;
13877acec1e7SMoore, Eric Dean 		goto out_mptspi_probe;
1388243eabcfSMoore, Eric Dean  	}
1389243eabcfSMoore, Eric Dean  
1390243eabcfSMoore, Eric Dean  	/*  Sanity check - ensure at least 1 port is INITIATOR capable
1391243eabcfSMoore, Eric Dean  	 */
1392243eabcfSMoore, Eric Dean  	ioc_cap = 0;
1393243eabcfSMoore, Eric Dean  	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1394243eabcfSMoore, Eric Dean  		if (ioc->pfacts[ii].ProtocolFlags &
1395243eabcfSMoore, Eric Dean  		    MPI_PORTFACTS_PROTOCOL_INITIATOR)
1396243eabcfSMoore, Eric Dean  			ioc_cap ++;
1397243eabcfSMoore, Eric Dean  	}
1398243eabcfSMoore, Eric Dean  
1399243eabcfSMoore, Eric Dean  	if (!ioc_cap) {
1400243eabcfSMoore, Eric Dean  		printk(MYIOC_s_WARN_FMT
1401243eabcfSMoore, Eric Dean  			"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1402243eabcfSMoore, Eric Dean  			ioc->name, ioc);
1403466544d8SMoore, Eric Dean 		return 0;
1404243eabcfSMoore, Eric Dean  	}
1405243eabcfSMoore, Eric Dean  
1406243eabcfSMoore, Eric Dean  	sh = scsi_host_alloc(&mptspi_driver_template, sizeof(MPT_SCSI_HOST));
1407243eabcfSMoore, Eric Dean  
1408243eabcfSMoore, Eric Dean  	if (!sh) {
1409243eabcfSMoore, Eric Dean  		printk(MYIOC_s_WARN_FMT
1410243eabcfSMoore, Eric Dean  			"Unable to register controller with SCSI subsystem\n",
1411243eabcfSMoore, Eric Dean  			ioc->name);
14127acec1e7SMoore, Eric Dean 		error = -1;
14137acec1e7SMoore, Eric Dean 		goto out_mptspi_probe;
1414243eabcfSMoore, Eric Dean          }
1415243eabcfSMoore, Eric Dean  
14164089b71cSChris J Arges 	/* VMWare emulation doesn't properly implement WRITE_SAME
14174089b71cSChris J Arges 	 */
14184089b71cSChris J Arges 	if (pdev->subsystem_vendor == 0x15AD)
14194089b71cSChris J Arges 		sh->no_write_same = 1;
14204089b71cSChris J Arges 
1421243eabcfSMoore, Eric Dean  	spin_lock_irqsave(&ioc->FreeQlock, flags);
1422243eabcfSMoore, Eric Dean  
1423243eabcfSMoore, Eric Dean  	/* Attach the SCSI Host to the IOC structure
1424243eabcfSMoore, Eric Dean  	 */
1425243eabcfSMoore, Eric Dean  	ioc->sh = sh;
1426243eabcfSMoore, Eric Dean  
1427243eabcfSMoore, Eric Dean  	sh->io_port = 0;
1428243eabcfSMoore, Eric Dean  	sh->n_io_port = 0;
1429243eabcfSMoore, Eric Dean  	sh->irq = 0;
1430243eabcfSMoore, Eric Dean  
1431243eabcfSMoore, Eric Dean  	/* set 16 byte cdb's */
1432243eabcfSMoore, Eric Dean  	sh->max_cmd_len = 16;
1433243eabcfSMoore, Eric Dean  
1434243eabcfSMoore, Eric Dean  	/* Yikes!  This is important!
1435243eabcfSMoore, Eric Dean  	 * Otherwise, by default, linux
1436243eabcfSMoore, Eric Dean  	 * only scans target IDs 0-7!
1437243eabcfSMoore, Eric Dean  	 * pfactsN->MaxDevices unreliable
1438243eabcfSMoore, Eric Dean  	 * (not supported in early
1439243eabcfSMoore, Eric Dean  	 *	versions of the FW).
1440243eabcfSMoore, Eric Dean  	 * max_id = 1 + actual max id,
1441243eabcfSMoore, Eric Dean  	 * max_lun = 1 + actual last lun,
1442243eabcfSMoore, Eric Dean  	 *	see hosts.h :o(
1443243eabcfSMoore, Eric Dean  	 */
1444793955f5SEric Moore 	sh->max_id = ioc->devices_per_bus;
1445243eabcfSMoore, Eric Dean  
1446243eabcfSMoore, Eric Dean  	sh->max_lun = MPT_LAST_LUN + 1;
1447c92f222eSJames Bottomley 	/*
1448c92f222eSJames Bottomley 	 * If RAID Firmware Detected, setup virtual channel
1449c92f222eSJames Bottomley 	 */
1450b506ade9SEric Moore 	if (ioc->ir_firmware)
1451c92f222eSJames Bottomley 		sh->max_channel = 1;
1452c92f222eSJames Bottomley 	else
1453243eabcfSMoore, Eric Dean  		sh->max_channel = 0;
1454243eabcfSMoore, Eric Dean  	sh->this_id = ioc->pfacts[0].PortSCSIID;
1455243eabcfSMoore, Eric Dean  
1456243eabcfSMoore, Eric Dean  	/* Required entry.
1457243eabcfSMoore, Eric Dean  	 */
1458243eabcfSMoore, Eric Dean  	sh->unique_id = ioc->id;
1459243eabcfSMoore, Eric Dean  
1460243eabcfSMoore, Eric Dean  	/* Verify that we won't exceed the maximum
1461243eabcfSMoore, Eric Dean  	 * number of chain buffers
1462243eabcfSMoore, Eric Dean  	 * We can optimize:  ZZ = req_sz/sizeof(SGE)
1463243eabcfSMoore, Eric Dean  	 * For 32bit SGE's:
1464243eabcfSMoore, Eric Dean  	 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1465243eabcfSMoore, Eric Dean  	 *               + (req_sz - 64)/sizeof(SGE)
1466243eabcfSMoore, Eric Dean  	 * A slightly different algorithm is required for
1467243eabcfSMoore, Eric Dean  	 * 64bit SGEs.
1468243eabcfSMoore, Eric Dean  	 */
146914d0f0b0SKashyap, Desai 	scale = ioc->req_sz/ioc->SGE_size;
147014d0f0b0SKashyap, Desai 	if (ioc->sg_addr_size == sizeof(u64)) {
1471243eabcfSMoore, Eric Dean  		numSGE = (scale - 1) *
1472243eabcfSMoore, Eric Dean  		  (ioc->facts.MaxChainDepth-1) + scale +
147314d0f0b0SKashyap, Desai 		  (ioc->req_sz - 60) / ioc->SGE_size;
1474243eabcfSMoore, Eric Dean  	} else {
1475243eabcfSMoore, Eric Dean  		numSGE = 1 + (scale - 1) *
1476243eabcfSMoore, Eric Dean  		  (ioc->facts.MaxChainDepth-1) + scale +
147714d0f0b0SKashyap, Desai 		  (ioc->req_sz - 64) / ioc->SGE_size;
1478243eabcfSMoore, Eric Dean  	}
1479243eabcfSMoore, Eric Dean  
1480243eabcfSMoore, Eric Dean  	if (numSGE < sh->sg_tablesize) {
1481243eabcfSMoore, Eric Dean  		/* Reset this value */
148229dd3609SEric Moore 		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1483243eabcfSMoore, Eric Dean  		  "Resetting sg_tablesize to %d from %d\n",
1484243eabcfSMoore, Eric Dean  		  ioc->name, numSGE, sh->sg_tablesize));
1485243eabcfSMoore, Eric Dean  		sh->sg_tablesize = numSGE;
1486243eabcfSMoore, Eric Dean  	}
1487243eabcfSMoore, Eric Dean  
1488243eabcfSMoore, Eric Dean  	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1489243eabcfSMoore, Eric Dean  
1490e7eae9f6SEric Moore 	hd = shost_priv(sh);
1491243eabcfSMoore, Eric Dean  	hd->ioc = ioc;
1492243eabcfSMoore, Eric Dean  
1493243eabcfSMoore, Eric Dean  	/* SCSI needs scsi_cmnd lookup table!
1494243eabcfSMoore, Eric Dean  	 * (with size equal to req_depth*PtrSz!)
1495243eabcfSMoore, Eric Dean  	 */
1496f69b0791SJulia Lawall 	ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_KERNEL);
1497e8206381SEric Moore 	if (!ioc->ScsiLookup) {
1498243eabcfSMoore, Eric Dean  		error = -ENOMEM;
14997acec1e7SMoore, Eric Dean 		goto out_mptspi_probe;
1500243eabcfSMoore, Eric Dean  	}
1501e8206381SEric Moore 	spin_lock_init(&ioc->scsi_lookup_lock);
1502243eabcfSMoore, Eric Dean  
1503d6ecdd63SPrakash, Sathya 	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
1504e8206381SEric Moore 		 ioc->name, ioc->ScsiLookup));
1505243eabcfSMoore, Eric Dean  
1506243eabcfSMoore, Eric Dean  	ioc->spi_data.Saf_Te = mpt_saf_te;
1507d6ecdd63SPrakash, Sathya 	ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1508ba856d32SEric Moore 		"saf_te %x\n",
1509243eabcfSMoore, Eric Dean  		ioc->name,
1510ba856d32SEric Moore 		mpt_saf_te));
1511243eabcfSMoore, Eric Dean  	ioc->spi_data.noQas = 0;
1512243eabcfSMoore, Eric Dean  
1513243eabcfSMoore, Eric Dean  	hd->last_queue_full = 0;
151472978245SEric Moore 	hd->spi_pending = 0;
1515243eabcfSMoore, Eric Dean  
1516c92f222eSJames Bottomley 	/* Some versions of the firmware don't support page 0; without
1517c92f222eSJames Bottomley 	 * that we can't get the parameters */
1518e80b002bSEric Moore 	if (ioc->spi_data.sdp0length != 0)
1519c92f222eSJames Bottomley 		sh->transportt = mptspi_transport_template;
1520c92f222eSJames Bottomley 
1521243eabcfSMoore, Eric Dean  	error = scsi_add_host (sh, &ioc->pcidev->dev);
1522243eabcfSMoore, Eric Dean  	if(error) {
152329dd3609SEric Moore 		dprintk(ioc, printk(MYIOC_s_ERR_FMT
152429dd3609SEric Moore 		  "scsi_add_host failed\n", ioc->name));
15257acec1e7SMoore, Eric Dean 		goto out_mptspi_probe;
1526243eabcfSMoore, Eric Dean  	}
1527243eabcfSMoore, Eric Dean  
1528d8e925dcSMoore, Eric 	/*
1529d8e925dcSMoore, Eric 	 * issue internal bus reset
1530d8e925dcSMoore, Eric 	 */
1531d8e925dcSMoore, Eric 	if (ioc->spi_data.bus_reset)
15321ba9ab2eSKashyap, Desai 		mptscsih_IssueTaskMgmt(hd,
1533d8e925dcSMoore, Eric 		    MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1534d8e925dcSMoore, Eric 		    0, 0, 0, 0, 5);
1535d8e925dcSMoore, Eric 
1536243eabcfSMoore, Eric Dean  	scsi_scan_host(sh);
1537243eabcfSMoore, Eric Dean  	return 0;
1538243eabcfSMoore, Eric Dean  
15397acec1e7SMoore, Eric Dean out_mptspi_probe:
1540243eabcfSMoore, Eric Dean  
1541243eabcfSMoore, Eric Dean  	mptscsih_remove(pdev);
1542243eabcfSMoore, Eric Dean  	return error;
1543243eabcfSMoore, Eric Dean  }
1544243eabcfSMoore, Eric Dean  
mptspi_remove(struct pci_dev * pdev)1545cfd2aff7SHannes Reinecke static void mptspi_remove(struct pci_dev *pdev)
1546cfd2aff7SHannes Reinecke {
1547cfd2aff7SHannes Reinecke 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1548cfd2aff7SHannes Reinecke 
1549cfd2aff7SHannes Reinecke 	scsi_remove_host(ioc->sh);
1550cfd2aff7SHannes Reinecke 	mptscsih_remove(pdev);
1551cfd2aff7SHannes Reinecke }
1552cfd2aff7SHannes Reinecke 
1553243eabcfSMoore, Eric Dean  static struct pci_driver mptspi_driver = {
1554243eabcfSMoore, Eric Dean  	.name		= "mptspi",
1555243eabcfSMoore, Eric Dean  	.id_table	= mptspi_pci_table,
1556243eabcfSMoore, Eric Dean  	.probe		= mptspi_probe,
1557cfd2aff7SHannes Reinecke 	.remove		= mptspi_remove,
1558243eabcfSMoore, Eric Dean  	.shutdown	= mptscsih_shutdown,
1559243eabcfSMoore, Eric Dean  #ifdef CONFIG_PM
1560243eabcfSMoore, Eric Dean  	.suspend	= mptscsih_suspend,
15616e1cad02SEric Moore 	.resume		= mptspi_resume,
1562243eabcfSMoore, Eric Dean  #endif
1563243eabcfSMoore, Eric Dean  };
1564243eabcfSMoore, Eric Dean  
1565243eabcfSMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1566243eabcfSMoore, Eric Dean  /**
1567d9489fb6SRandy Dunlap  *	mptspi_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
1568243eabcfSMoore, Eric Dean   *
1569243eabcfSMoore, Eric Dean   *	Returns 0 for success, non-zero for failure.
1570243eabcfSMoore, Eric Dean   */
1571243eabcfSMoore, Eric Dean  static int __init
mptspi_init(void)1572243eabcfSMoore, Eric Dean  mptspi_init(void)
1573243eabcfSMoore, Eric Dean  {
157457ce21bfSPrakash, Sathya 	int error;
157557ce21bfSPrakash, Sathya 
1576243eabcfSMoore, Eric Dean  	show_mptmod_ver(my_NAME, my_VERSION);
1577243eabcfSMoore, Eric Dean  
1578c92f222eSJames Bottomley 	mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions);
1579c92f222eSJames Bottomley 	if (!mptspi_transport_template)
1580c92f222eSJames Bottomley 		return -ENODEV;
1581c92f222eSJames Bottomley 
1582213aaca3SKashyap, Desai 	mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER,
1583213aaca3SKashyap, Desai 	    "mptscsih_io_done");
1584213aaca3SKashyap, Desai 	mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER,
1585213aaca3SKashyap, Desai 	    "mptscsih_taskmgmt_complete");
1586213aaca3SKashyap, Desai 	mptspiInternalCtx = mpt_register(mptscsih_scandv_complete,
1587213aaca3SKashyap, Desai 	    MPTSPI_DRIVER, "mptscsih_scandv_complete");
1588243eabcfSMoore, Eric Dean  
1589d6ecdd63SPrakash, Sathya 	mpt_event_register(mptspiDoneCtx, mptspi_event_process);
1590d6ecdd63SPrakash, Sathya 	mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset);
1591243eabcfSMoore, Eric Dean  
159257ce21bfSPrakash, Sathya 	error = pci_register_driver(&mptspi_driver);
159357ce21bfSPrakash, Sathya 	if (error)
159457ce21bfSPrakash, Sathya 		spi_release_transport(mptspi_transport_template);
159557ce21bfSPrakash, Sathya 
159657ce21bfSPrakash, Sathya 	return error;
1597243eabcfSMoore, Eric Dean  }
1598243eabcfSMoore, Eric Dean  
1599243eabcfSMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1600243eabcfSMoore, Eric Dean  /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1601243eabcfSMoore, Eric Dean  /**
1602243eabcfSMoore, Eric Dean   *	mptspi_exit - Unregisters MPT adapter(s)
1603243eabcfSMoore, Eric Dean   */
1604243eabcfSMoore, Eric Dean  static void __exit
mptspi_exit(void)1605243eabcfSMoore, Eric Dean  mptspi_exit(void)
1606243eabcfSMoore, Eric Dean  {
1607243eabcfSMoore, Eric Dean  	pci_unregister_driver(&mptspi_driver);
1608243eabcfSMoore, Eric Dean  
1609243eabcfSMoore, Eric Dean  	mpt_reset_deregister(mptspiDoneCtx);
1610243eabcfSMoore, Eric Dean  	mpt_event_deregister(mptspiDoneCtx);
1611243eabcfSMoore, Eric Dean  
1612243eabcfSMoore, Eric Dean  	mpt_deregister(mptspiInternalCtx);
1613243eabcfSMoore, Eric Dean  	mpt_deregister(mptspiTaskCtx);
1614243eabcfSMoore, Eric Dean  	mpt_deregister(mptspiDoneCtx);
1615c92f222eSJames Bottomley 	spi_release_transport(mptspi_transport_template);
1616243eabcfSMoore, Eric Dean  }
1617243eabcfSMoore, Eric Dean  
1618243eabcfSMoore, Eric Dean  module_init(mptspi_init);
1619243eabcfSMoore, Eric Dean  module_exit(mptspi_exit);
1620