xref: /openbmc/linux/drivers/message/fusion/mptctl.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/drivers/message/fusion/mptctl.c
3b6fe4ddcSMoore, Eric Dean   *      mpt Ioctl driver.
4f36789e2SPrakash, Sathya  *      For use with LSI PCI chip/adapters
5f36789e2SPrakash, Sathya  *      running LSI Fusion MPT (Message Passing Technology) firmware.
61da177e4SLinus Torvalds  *
7cddc0ab7SPrakash, Sathya  *  Copyright (c) 1999-2008 LSI Corporation
816d20101SEric Moore  *  (mailto:DL-MPTFusionLinux@lsi.com)
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
121da177e4SLinus Torvalds /*
131da177e4SLinus Torvalds     This program is free software; you can redistribute it and/or modify
141da177e4SLinus Torvalds     it under the terms of the GNU General Public License as published by
151da177e4SLinus Torvalds     the Free Software Foundation; version 2 of the License.
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds     This program is distributed in the hope that it will be useful,
181da177e4SLinus Torvalds     but WITHOUT ANY WARRANTY; without even the implied warranty of
191da177e4SLinus Torvalds     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
201da177e4SLinus Torvalds     GNU General Public License for more details.
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds     NO WARRANTY
231da177e4SLinus Torvalds     THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
241da177e4SLinus Torvalds     CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
251da177e4SLinus Torvalds     LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
261da177e4SLinus Torvalds     MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
271da177e4SLinus Torvalds     solely responsible for determining the appropriateness of using and
281da177e4SLinus Torvalds     distributing the Program and assumes all risks associated with its
291da177e4SLinus Torvalds     exercise of rights under this Agreement, including but not limited to
301da177e4SLinus Torvalds     the risks and costs of program errors, damage to or loss of data,
311da177e4SLinus Torvalds     programs or equipment, and unavailability or interruption of operations.
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds     DISCLAIMER OF LIABILITY
341da177e4SLinus Torvalds     NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
351da177e4SLinus Torvalds     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
361da177e4SLinus Torvalds     DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
371da177e4SLinus Torvalds     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
381da177e4SLinus Torvalds     TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
391da177e4SLinus Torvalds     USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
401da177e4SLinus Torvalds     HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds     You should have received a copy of the GNU General Public License
431da177e4SLinus Torvalds     along with this program; if not, write to the Free Software
441da177e4SLinus Torvalds     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
451da177e4SLinus Torvalds */
461da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds #include <linux/kernel.h>
491da177e4SLinus Torvalds #include <linux/module.h>
501da177e4SLinus Torvalds #include <linux/errno.h>
511da177e4SLinus Torvalds #include <linux/init.h>
521da177e4SLinus Torvalds #include <linux/slab.h>
531da177e4SLinus Torvalds #include <linux/types.h>
541da177e4SLinus Torvalds #include <linux/pci.h>
551da177e4SLinus Torvalds #include <linux/delay.h>	/* for mdelay */
561da177e4SLinus Torvalds #include <linux/miscdevice.h>
57c45d15d2SArnd Bergmann #include <linux/mutex.h>
581da177e4SLinus Torvalds #include <linux/compat.h>
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds #include <asm/io.h>
617c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds #include <scsi/scsi.h>
641da177e4SLinus Torvalds #include <scsi/scsi_cmnd.h>
651da177e4SLinus Torvalds #include <scsi/scsi_device.h>
661da177e4SLinus Torvalds #include <scsi/scsi_host.h>
671da177e4SLinus Torvalds #include <scsi/scsi_tcq.h>
681da177e4SLinus Torvalds 
69cddc0ab7SPrakash, Sathya #define COPYRIGHT	"Copyright (c) 1999-2008 LSI Corporation"
70f36789e2SPrakash, Sathya #define MODULEAUTHOR	"LSI Corporation"
711da177e4SLinus Torvalds #include "mptbase.h"
721da177e4SLinus Torvalds #include "mptctl.h"
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
751da177e4SLinus Torvalds #define my_NAME		"Fusion MPT misc device (ioctl) driver"
761da177e4SLinus Torvalds #define my_VERSION	MPT_LINUX_VERSION_COMMON
771da177e4SLinus Torvalds #define MYNAM		"mptctl"
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds MODULE_AUTHOR(MODULEAUTHOR);
801da177e4SLinus Torvalds MODULE_DESCRIPTION(my_NAME);
811da177e4SLinus Torvalds MODULE_LICENSE("GPL");
829f4203b3SEric Moore MODULE_VERSION(my_VERSION);
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
851da177e4SLinus Torvalds 
86c45d15d2SArnd Bergmann static DEFINE_MUTEX(mpctl_mutex);
87f606f571SPrakash, Sathya static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS;
88ea2a788dSKashyap, Desai static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS;
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds struct buflist {
951da177e4SLinus Torvalds 	u8	*kptr;
961da177e4SLinus Torvalds 	int	 len;
971da177e4SLinus Torvalds };
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds /*
1001da177e4SLinus Torvalds  * Function prototypes. Called from OS entry point mptctl_ioctl.
1011da177e4SLinus Torvalds  * arg contents specific to function.
1021da177e4SLinus Torvalds  */
10328d76df1SDan Carpenter static int mptctl_fw_download(MPT_ADAPTER *iocp, unsigned long arg);
10428d76df1SDan Carpenter static int mptctl_getiocinfo(MPT_ADAPTER *iocp, unsigned long arg, unsigned int cmd);
10528d76df1SDan Carpenter static int mptctl_gettargetinfo(MPT_ADAPTER *iocp, unsigned long arg);
10628d76df1SDan Carpenter static int mptctl_readtest(MPT_ADAPTER *iocp, unsigned long arg);
10728d76df1SDan Carpenter static int mptctl_mpt_command(MPT_ADAPTER *iocp, unsigned long arg);
10828d76df1SDan Carpenter static int mptctl_eventquery(MPT_ADAPTER *iocp, unsigned long arg);
10928d76df1SDan Carpenter static int mptctl_eventenable(MPT_ADAPTER *iocp, unsigned long arg);
11028d76df1SDan Carpenter static int mptctl_eventreport(MPT_ADAPTER *iocp, unsigned long arg);
11128d76df1SDan Carpenter static int mptctl_replace_fw(MPT_ADAPTER *iocp, unsigned long arg);
1121da177e4SLinus Torvalds 
11328d76df1SDan Carpenter static int mptctl_do_reset(MPT_ADAPTER *iocp, unsigned long arg);
11428d76df1SDan Carpenter static int mptctl_hp_hostinfo(MPT_ADAPTER *iocp, unsigned long arg, unsigned int cmd);
11528d76df1SDan Carpenter static int mptctl_hp_targetinfo(MPT_ADAPTER *iocp, unsigned long arg);
1161da177e4SLinus Torvalds 
117a534ff3fSUwe Kleine-König static int  mptctl_probe(struct pci_dev *);
1181da177e4SLinus Torvalds static void mptctl_remove(struct pci_dev *);
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
1211da177e4SLinus Torvalds static long compat_mpctl_ioctl(struct file *f, unsigned cmd, unsigned long arg);
1221da177e4SLinus Torvalds #endif
1231da177e4SLinus Torvalds /*
1241da177e4SLinus Torvalds  * Private function calls.
1251da177e4SLinus Torvalds  */
12628d76df1SDan Carpenter static int mptctl_do_mpt_command(MPT_ADAPTER *iocp, struct mpt_ioctl_command karg, void __user *mfPtr);
12728d76df1SDan Carpenter static int mptctl_do_fw_download(MPT_ADAPTER *iocp, char __user *ufwbuf, size_t fwlen);
1281da177e4SLinus Torvalds static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags,
1291da177e4SLinus Torvalds 		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
1301da177e4SLinus Torvalds static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
1311da177e4SLinus Torvalds 		struct buflist *buflist, MPT_ADAPTER *ioc);
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds /*
1341da177e4SLinus Torvalds  * Reset Handler cleanup function
1351da177e4SLinus Torvalds  */
1361da177e4SLinus Torvalds static int  mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase);
1371da177e4SLinus Torvalds 
138ea5a7a82SMoore, Eric /*
139ea5a7a82SMoore, Eric  * Event Handler function
140ea5a7a82SMoore, Eric  */
141ea5a7a82SMoore, Eric static int mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
142c972c70fSMoore, Eric static struct fasync_struct *async_queue=NULL;
143ea5a7a82SMoore, Eric 
1441da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1451da177e4SLinus Torvalds /*
1461da177e4SLinus Torvalds  * Scatter gather list (SGL) sizes and limits...
1471da177e4SLinus Torvalds  */
1481da177e4SLinus Torvalds //#define MAX_SCSI_FRAGS	9
1491da177e4SLinus Torvalds #define MAX_FRAGS_SPILL1	9
1501da177e4SLinus Torvalds #define MAX_FRAGS_SPILL2	15
1511da177e4SLinus Torvalds #define FRAGS_PER_BUCKET	(MAX_FRAGS_SPILL2 + 1)
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds //#define MAX_CHAIN_FRAGS	64
1541da177e4SLinus Torvalds //#define MAX_CHAIN_FRAGS	(15+15+15+16)
1551da177e4SLinus Torvalds #define MAX_CHAIN_FRAGS		(4 * MAX_FRAGS_SPILL2 + 1)
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds //  Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each)
1581da177e4SLinus Torvalds //  Works out to: 592d bytes!     (9+1)*8 + 4*(15+1)*8
1591da177e4SLinus Torvalds //                  ^----------------- 80 + 512
1601da177e4SLinus Torvalds #define MAX_SGL_BYTES		((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8)
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds /* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */
1631da177e4SLinus Torvalds #define MAX_KMALLOC_SZ		(128*1024)
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds #define MPT_IOCTL_DEFAULT_TIMEOUT 10	/* Default timeout value (seconds) */
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1681da177e4SLinus Torvalds /**
1691da177e4SLinus Torvalds  *	mptctl_syscall_down - Down the MPT adapter syscall semaphore.
1701da177e4SLinus Torvalds  *	@ioc: Pointer to MPT adapter
1711da177e4SLinus Torvalds  *	@nonblock: boolean, non-zero if O_NONBLOCK is set
1721da177e4SLinus Torvalds  *
1731da177e4SLinus Torvalds  *	All of the ioctl commands can potentially sleep, which is illegal
1741da177e4SLinus Torvalds  *	with a spinlock held, thus we perform mutual exclusion here.
1751da177e4SLinus Torvalds  *
1761da177e4SLinus Torvalds  *	Returns negative errno on error, or zero for success.
1771da177e4SLinus Torvalds  */
1781da177e4SLinus Torvalds static inline int
mptctl_syscall_down(MPT_ADAPTER * ioc,int nonblock)1791da177e4SLinus Torvalds mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds 	int rc = 0;
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds 	if (nonblock) {
184ea2a788dSKashyap, Desai 		if (!mutex_trylock(&ioc->ioctl_cmds.mutex))
1851da177e4SLinus Torvalds 			rc = -EAGAIN;
1861da177e4SLinus Torvalds 	} else {
187ea2a788dSKashyap, Desai 		if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex))
1881da177e4SLinus Torvalds 			rc = -ERESTARTSYS;
1891da177e4SLinus Torvalds 	}
1901da177e4SLinus Torvalds 	return rc;
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1941da177e4SLinus Torvalds /*
1951da177e4SLinus Torvalds  *  This is the callback for any message we have posted. The message itself
1961da177e4SLinus Torvalds  *  will be returned to the message pool when we return from the IRQ
1971da177e4SLinus Torvalds  *
1981da177e4SLinus Torvalds  *  This runs in irq context so be short and sweet.
1991da177e4SLinus Torvalds  */
2001da177e4SLinus Torvalds static int
mptctl_reply(MPT_ADAPTER * ioc,MPT_FRAME_HDR * req,MPT_FRAME_HDR * reply)2011da177e4SLinus Torvalds mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
2021da177e4SLinus Torvalds {
2031da177e4SLinus Torvalds 	char	*sense_data;
204ea2a788dSKashyap, Desai 	int	req_index;
205ea2a788dSKashyap, Desai 	int	sz;
2061da177e4SLinus Torvalds 
207ea2a788dSKashyap, Desai 	if (!req)
208ea2a788dSKashyap, Desai 		return 0;
2091da177e4SLinus Torvalds 
210ea2a788dSKashyap, Desai 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function "
211ea2a788dSKashyap, Desai 	    "(0x%02X), req=%p, reply=%p\n", ioc->name,  req->u.hdr.Function,
212ea2a788dSKashyap, Desai 	    req, reply));
2131da177e4SLinus Torvalds 
214ea2a788dSKashyap, Desai 	/*
215ea2a788dSKashyap, Desai 	 * Handling continuation of the same reply. Processing the first
216ea2a788dSKashyap, Desai 	 * reply, and eating the other replys that come later.
2171da177e4SLinus Torvalds 	 */
218ea2a788dSKashyap, Desai 	if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext)
219ea2a788dSKashyap, Desai 		goto out_continuation;
2201da177e4SLinus Torvalds 
221ea2a788dSKashyap, Desai 	ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2221da177e4SLinus Torvalds 
223ea2a788dSKashyap, Desai 	if (!reply)
224ea2a788dSKashyap, Desai 		goto out;
2251da177e4SLinus Torvalds 
226ea2a788dSKashyap, Desai 	ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
227ea2a788dSKashyap, Desai 	sz = min(ioc->reply_sz, 4*reply->u.reply.MsgLength);
228ea2a788dSKashyap, Desai 	memcpy(ioc->ioctl_cmds.reply, reply, sz);
2291da177e4SLinus Torvalds 
230ea2a788dSKashyap, Desai 	if (reply->u.reply.IOCStatus || reply->u.reply.IOCLogInfo)
231ea2a788dSKashyap, Desai 		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
232ea2a788dSKashyap, Desai 		    "iocstatus (0x%04X), loginfo (0x%08X)\n", ioc->name,
233ea2a788dSKashyap, Desai 		    le16_to_cpu(reply->u.reply.IOCStatus),
23409120a8cSPrakash, Sathya 		    le32_to_cpu(reply->u.reply.IOCLogInfo)));
23509120a8cSPrakash, Sathya 
236ea2a788dSKashyap, Desai 	if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
237ea2a788dSKashyap, Desai 		(req->u.hdr.Function ==
238ea2a788dSKashyap, Desai 		 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
23909120a8cSPrakash, Sathya 
24009120a8cSPrakash, Sathya 		if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
24109120a8cSPrakash, Sathya 			dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
242ea2a788dSKashyap, Desai 			"scsi_status (0x%02x), scsi_state (0x%02x), "
24309120a8cSPrakash, Sathya 			"tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
24409120a8cSPrakash, Sathya 			reply->u.sreply.SCSIStatus,
24509120a8cSPrakash, Sathya 			reply->u.sreply.SCSIState,
24609120a8cSPrakash, Sathya 			le16_to_cpu(reply->u.sreply.TaskTag),
24709120a8cSPrakash, Sathya 			le32_to_cpu(reply->u.sreply.TransferCount)));
24809120a8cSPrakash, Sathya 
249ea2a788dSKashyap, Desai 		if (reply->u.sreply.SCSIState &
250ea2a788dSKashyap, Desai 			MPI_SCSI_STATE_AUTOSENSE_VALID) {
2511da177e4SLinus Torvalds 			sz = req->u.scsireq.SenseBufferLength;
2521da177e4SLinus Torvalds 			req_index =
2531da177e4SLinus Torvalds 			    le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
254ea2a788dSKashyap, Desai 			sense_data = ((u8 *)ioc->sense_buf_pool +
2551da177e4SLinus Torvalds 			     (req_index * MPT_SENSE_BUFFER_ALLOC));
256ea2a788dSKashyap, Desai 			memcpy(ioc->ioctl_cmds.sense, sense_data, sz);
257ea2a788dSKashyap, Desai 			ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID;
258ea2a788dSKashyap, Desai 		}
2591da177e4SLinus Torvalds 	}
2601da177e4SLinus Torvalds 
261ea2a788dSKashyap, Desai  out:
2621da177e4SLinus Torvalds 	/* We are done, issue wake up
2631da177e4SLinus Torvalds 	 */
264ea2a788dSKashyap, Desai 	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
265b68bf096SKashyap, Desai 		if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
266ea2a788dSKashyap, Desai 			mpt_clear_taskmgmt_in_progress_flag(ioc);
267ea2a788dSKashyap, Desai 			ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
268ea2a788dSKashyap, Desai 			complete(&ioc->ioctl_cmds.done);
269b68bf096SKashyap, Desai 			if (ioc->bus_type == SAS)
270b68bf096SKashyap, Desai 				ioc->schedule_target_reset(ioc);
271b68bf096SKashyap, Desai 		} else {
272b68bf096SKashyap, Desai 			ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
273b68bf096SKashyap, Desai 			complete(&ioc->ioctl_cmds.done);
274b68bf096SKashyap, Desai 		}
2751da177e4SLinus Torvalds 	}
276ea2a788dSKashyap, Desai 
277ea2a788dSKashyap, Desai  out_continuation:
278ea2a788dSKashyap, Desai 	if (reply && (reply->u.reply.MsgFlags &
279ea2a788dSKashyap, Desai 	    MPI_MSGFLAGS_CONTINUATION_REPLY))
280ea2a788dSKashyap, Desai 		return 0;
2811da177e4SLinus Torvalds 	return 1;
2821da177e4SLinus Torvalds }
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 
285ea2a788dSKashyap, Desai static int
mptctl_taskmgmt_reply(MPT_ADAPTER * ioc,MPT_FRAME_HDR * mf,MPT_FRAME_HDR * mr)286ea2a788dSKashyap, Desai mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
287ea2a788dSKashyap, Desai {
288ea2a788dSKashyap, Desai 	if (!mf)
289ea2a788dSKashyap, Desai 		return 0;
290ea2a788dSKashyap, Desai 
291ea2a788dSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
292ea2a788dSKashyap, Desai 		"TaskMgmt completed (mf=%p, mr=%p)\n",
293ea2a788dSKashyap, Desai 		ioc->name, mf, mr));
294ea2a788dSKashyap, Desai 
295ea2a788dSKashyap, Desai 	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
296ea2a788dSKashyap, Desai 
297ea2a788dSKashyap, Desai 	if (!mr)
298ea2a788dSKashyap, Desai 		goto out;
299ea2a788dSKashyap, Desai 
300ea2a788dSKashyap, Desai 	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
301ea2a788dSKashyap, Desai 	memcpy(ioc->taskmgmt_cmds.reply, mr,
302ea2a788dSKashyap, Desai 	    min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
303ea2a788dSKashyap, Desai  out:
304ea2a788dSKashyap, Desai 	if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
305ea2a788dSKashyap, Desai 		mpt_clear_taskmgmt_in_progress_flag(ioc);
306ea2a788dSKashyap, Desai 		ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
307ea2a788dSKashyap, Desai 		complete(&ioc->taskmgmt_cmds.done);
308b68bf096SKashyap, Desai 		if (ioc->bus_type == SAS)
309b68bf096SKashyap, Desai 			ioc->schedule_target_reset(ioc);
310ea2a788dSKashyap, Desai 		return 1;
311ea2a788dSKashyap, Desai 	}
312ea2a788dSKashyap, Desai 	return 0;
3131da177e4SLinus Torvalds }
3141da177e4SLinus Torvalds 
3157d757f18SKashyap, Desai static int
mptctl_do_taskmgmt(MPT_ADAPTER * ioc,u8 tm_type,u8 bus_id,u8 target_id)3167d757f18SKashyap, Desai mptctl_do_taskmgmt(MPT_ADAPTER *ioc, u8 tm_type, u8 bus_id, u8 target_id)
3171da177e4SLinus Torvalds {
3181da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
3191da177e4SLinus Torvalds 	SCSITaskMgmt_t	*pScsiTm;
320ea2a788dSKashyap, Desai 	SCSITaskMgmtReply_t *pScsiTmReply;
3211da177e4SLinus Torvalds 	int		 ii;
322ea2a788dSKashyap, Desai 	int		 retval;
323ea2a788dSKashyap, Desai 	unsigned long	 timeout;
324ea2a788dSKashyap, Desai 	u16		 iocstatus;
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 
327ea2a788dSKashyap, Desai 	mutex_lock(&ioc->taskmgmt_cmds.mutex);
328ea2a788dSKashyap, Desai 	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
329ea2a788dSKashyap, Desai 		mutex_unlock(&ioc->taskmgmt_cmds.mutex);
3301da177e4SLinus Torvalds 		return -EPERM;
331ea2a788dSKashyap, Desai 	}
3321da177e4SLinus Torvalds 
333ea2a788dSKashyap, Desai 	retval = 0;
3341da177e4SLinus Torvalds 
335ea2a788dSKashyap, Desai 	mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc);
336ea2a788dSKashyap, Desai 	if (mf == NULL) {
3377d757f18SKashyap, Desai 		dtmprintk(ioc,
3387d757f18SKashyap, Desai 			printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
3397d757f18SKashyap, Desai 			ioc->name));
340ea2a788dSKashyap, Desai 		mpt_clear_taskmgmt_in_progress_flag(ioc);
341ea2a788dSKashyap, Desai 		retval = -ENOMEM;
3427d757f18SKashyap, Desai 		goto tm_done;
3431da177e4SLinus Torvalds 	}
3441da177e4SLinus Torvalds 
345ea2a788dSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
346ea2a788dSKashyap, Desai 		ioc->name, mf));
3471da177e4SLinus Torvalds 
3481da177e4SLinus Torvalds 	pScsiTm = (SCSITaskMgmt_t *) mf;
349ea2a788dSKashyap, Desai 	memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
3501da177e4SLinus Torvalds 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
3517d757f18SKashyap, Desai 	pScsiTm->TaskType = tm_type;
3527d757f18SKashyap, Desai 	if ((tm_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) &&
3537d757f18SKashyap, Desai 		(ioc->bus_type == FC))
3547d757f18SKashyap, Desai 		pScsiTm->MsgFlags =
3557d757f18SKashyap, Desai 				MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
3567d757f18SKashyap, Desai 	pScsiTm->TargetID = target_id;
3577d757f18SKashyap, Desai 	pScsiTm->Bus = bus_id;
358ea2a788dSKashyap, Desai 	pScsiTm->ChainOffset = 0;
359ea2a788dSKashyap, Desai 	pScsiTm->Reserved = 0;
360ea2a788dSKashyap, Desai 	pScsiTm->Reserved1 = 0;
361ea2a788dSKashyap, Desai 	pScsiTm->TaskMsgContext = 0;
3621da177e4SLinus Torvalds 	for (ii= 0; ii < 8; ii++)
3631da177e4SLinus Torvalds 		pScsiTm->LUN[ii] = 0;
3641da177e4SLinus Torvalds 	for (ii=0; ii < 7; ii++)
3651da177e4SLinus Torvalds 		pScsiTm->Reserved2[ii] = 0;
3661da177e4SLinus Torvalds 
367ea2a788dSKashyap, Desai 	switch (ioc->bus_type) {
368ea2a788dSKashyap, Desai 	case FC:
369ea2a788dSKashyap, Desai 		timeout = 40;
370ea2a788dSKashyap, Desai 		break;
371ea2a788dSKashyap, Desai 	case SAS:
372ea2a788dSKashyap, Desai 		timeout = 30;
373ea2a788dSKashyap, Desai 		break;
374ea2a788dSKashyap, Desai 	case SPI:
375ea2a788dSKashyap, Desai 		default:
3767d757f18SKashyap, Desai 		timeout = 10;
377ea2a788dSKashyap, Desai 		break;
378ea2a788dSKashyap, Desai 	}
3791da177e4SLinus Torvalds 
3807d757f18SKashyap, Desai 	dtmprintk(ioc,
3817d757f18SKashyap, Desai 		printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
3827d757f18SKashyap, Desai 		ioc->name, tm_type, timeout));
3831da177e4SLinus Torvalds 
384ea2a788dSKashyap, Desai 	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
385ea2a788dSKashyap, Desai 	if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
386ea2a788dSKashyap, Desai 	    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
387ea2a788dSKashyap, Desai 		mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf);
3887a195f46SPrakash, Sathya 	else {
389ea2a788dSKashyap, Desai 		retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
3907a195f46SPrakash, Sathya 		    sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP);
3917a195f46SPrakash, Sathya 		if (retval != 0) {
3927d757f18SKashyap, Desai 			dfailprintk(ioc,
3937d757f18SKashyap, Desai 				printk(MYIOC_s_ERR_FMT
394ea2a788dSKashyap, Desai 				"TaskMgmt send_handshake FAILED!"
395ea2a788dSKashyap, Desai 				" (ioc %p, mf %p, rc=%d) \n", ioc->name,
396ea2a788dSKashyap, Desai 				ioc, mf, retval));
3977d757f18SKashyap, Desai 			mpt_free_msg_frame(ioc, mf);
398ea2a788dSKashyap, Desai 			mpt_clear_taskmgmt_in_progress_flag(ioc);
3997d757f18SKashyap, Desai 			goto tm_done;
4001da177e4SLinus Torvalds 		}
4017a195f46SPrakash, Sathya 	}
4021da177e4SLinus Torvalds 
4031da177e4SLinus Torvalds 	/* Now wait for the command to complete */
404ea2a788dSKashyap, Desai 	ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
4057d757f18SKashyap, Desai 
406ea2a788dSKashyap, Desai 	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
407ea2a788dSKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
408ea2a788dSKashyap, Desai 		    "TaskMgmt failed\n", ioc->name));
409ea2a788dSKashyap, Desai 		mpt_free_msg_frame(ioc, mf);
410ea2a788dSKashyap, Desai 		mpt_clear_taskmgmt_in_progress_flag(ioc);
411ea2a788dSKashyap, Desai 		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
412ea2a788dSKashyap, Desai 			retval = 0;
413ea2a788dSKashyap, Desai 		else
414ea2a788dSKashyap, Desai 			retval = -1; /* return failure */
4157d757f18SKashyap, Desai 		goto tm_done;
416ea2a788dSKashyap, Desai 	}
4171da177e4SLinus Torvalds 
418ea2a788dSKashyap, Desai 	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
419ea2a788dSKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
420ea2a788dSKashyap, Desai 		    "TaskMgmt failed\n", ioc->name));
421ea2a788dSKashyap, Desai 		retval = -1; /* return failure */
4227d757f18SKashyap, Desai 		goto tm_done;
423ea2a788dSKashyap, Desai 	}
424ea2a788dSKashyap, Desai 
425ea2a788dSKashyap, Desai 	pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
426ea2a788dSKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
427ea2a788dSKashyap, Desai 	    "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "
428ea2a788dSKashyap, Desai 	    "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "
429ea2a788dSKashyap, Desai 	    "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus,
4307d757f18SKashyap, Desai 	    pScsiTmReply->TargetID, tm_type,
431ea2a788dSKashyap, Desai 	    le16_to_cpu(pScsiTmReply->IOCStatus),
432ea2a788dSKashyap, Desai 	    le32_to_cpu(pScsiTmReply->IOCLogInfo),
433ea2a788dSKashyap, Desai 	    pScsiTmReply->ResponseCode,
434ea2a788dSKashyap, Desai 	    le32_to_cpu(pScsiTmReply->TerminationCount)));
435ea2a788dSKashyap, Desai 
436ea2a788dSKashyap, Desai 	iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
437ea2a788dSKashyap, Desai 
438ea2a788dSKashyap, Desai 	if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
439ea2a788dSKashyap, Desai 	   iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED ||
440ea2a788dSKashyap, Desai 	   iocstatus == MPI_IOCSTATUS_SUCCESS)
441ea2a788dSKashyap, Desai 		retval = 0;
442ea2a788dSKashyap, Desai 	else {
443ea2a788dSKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
444ea2a788dSKashyap, Desai 		    "TaskMgmt failed\n", ioc->name));
4451da177e4SLinus Torvalds 		retval = -1; /* return failure */
4461da177e4SLinus Torvalds 	}
4471da177e4SLinus Torvalds 
4487d757f18SKashyap, Desai  tm_done:
449ea2a788dSKashyap, Desai 	mutex_unlock(&ioc->taskmgmt_cmds.mutex);
450ea2a788dSKashyap, Desai 	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4511da177e4SLinus Torvalds 	return retval;
4521da177e4SLinus Torvalds }
4531da177e4SLinus Torvalds 
4547d757f18SKashyap, Desai /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4557d757f18SKashyap, Desai /* mptctl_timeout_expired
4567d757f18SKashyap, Desai  *
4577d757f18SKashyap, Desai  * Expecting an interrupt, however timed out.
4587d757f18SKashyap, Desai  *
4597d757f18SKashyap, Desai  */
4607d757f18SKashyap, Desai static void
mptctl_timeout_expired(MPT_ADAPTER * ioc,MPT_FRAME_HDR * mf)4617d757f18SKashyap, Desai mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
4627d757f18SKashyap, Desai {
4637d757f18SKashyap, Desai 	unsigned long flags;
4647d757f18SKashyap, Desai 	int ret_val = -1;
4657d757f18SKashyap, Desai 	SCSIIORequest_t *scsi_req = (SCSIIORequest_t *) mf;
4667d757f18SKashyap, Desai 	u8 function = mf->u.hdr.Function;
4677d757f18SKashyap, Desai 
4687d757f18SKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
4697d757f18SKashyap, Desai 		ioc->name, __func__));
4707d757f18SKashyap, Desai 
4717d757f18SKashyap, Desai 	if (mpt_fwfault_debug)
4727d757f18SKashyap, Desai 		mpt_halt_firmware(ioc);
4737d757f18SKashyap, Desai 
4747d757f18SKashyap, Desai 	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
4757d757f18SKashyap, Desai 	if (ioc->ioc_reset_in_progress) {
4767d757f18SKashyap, Desai 		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
4777d757f18SKashyap, Desai 		CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
4787d757f18SKashyap, Desai 		mpt_free_msg_frame(ioc, mf);
4797d757f18SKashyap, Desai 		return;
4807d757f18SKashyap, Desai 	}
4817d757f18SKashyap, Desai 	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
4827d757f18SKashyap, Desai 
4837d757f18SKashyap, Desai 
4847d757f18SKashyap, Desai 	CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
4857d757f18SKashyap, Desai 
4867d757f18SKashyap, Desai 	if (ioc->bus_type == SAS) {
4877d757f18SKashyap, Desai 		if (function == MPI_FUNCTION_SCSI_IO_REQUEST)
4887d757f18SKashyap, Desai 			ret_val = mptctl_do_taskmgmt(ioc,
4897d757f18SKashyap, Desai 				MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
4907d757f18SKashyap, Desai 				scsi_req->Bus, scsi_req->TargetID);
4917d757f18SKashyap, Desai 		else if (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
4927d757f18SKashyap, Desai 			ret_val = mptctl_do_taskmgmt(ioc,
4937d757f18SKashyap, Desai 				MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
4947d757f18SKashyap, Desai 				scsi_req->Bus, 0);
4957d757f18SKashyap, Desai 		if (!ret_val)
4967d757f18SKashyap, Desai 			return;
4977d757f18SKashyap, Desai 	} else {
4987d757f18SKashyap, Desai 		if ((function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
4997d757f18SKashyap, Desai 			(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH))
5007d757f18SKashyap, Desai 			ret_val = mptctl_do_taskmgmt(ioc,
5017d757f18SKashyap, Desai 				MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
5027d757f18SKashyap, Desai 				scsi_req->Bus, 0);
5037d757f18SKashyap, Desai 		if (!ret_val)
5047d757f18SKashyap, Desai 			return;
5057d757f18SKashyap, Desai 	}
5067d757f18SKashyap, Desai 
5077d757f18SKashyap, Desai 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling Reset! \n",
5087d757f18SKashyap, Desai 		 ioc->name));
5097d757f18SKashyap, Desai 	mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
5107d757f18SKashyap, Desai 	mpt_free_msg_frame(ioc, mf);
5117d757f18SKashyap, Desai }
5127d757f18SKashyap, Desai 
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5151da177e4SLinus Torvalds /* mptctl_ioc_reset
5161da177e4SLinus Torvalds  *
5171da177e4SLinus Torvalds  * Clean-up functionality. Used only if there has been a
5181da177e4SLinus Torvalds  * reload of the FW due.
5191da177e4SLinus Torvalds  *
5201da177e4SLinus Torvalds  */
5211da177e4SLinus Torvalds static int
mptctl_ioc_reset(MPT_ADAPTER * ioc,int reset_phase)5221da177e4SLinus Torvalds mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5231da177e4SLinus Torvalds {
5241da177e4SLinus Torvalds 	switch(reset_phase) {
5251da177e4SLinus Torvalds 	case MPT_IOC_SETUP_RESET:
526ea2a788dSKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
527ea2a788dSKashyap, Desai 		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
5281da177e4SLinus Torvalds 		break;
5291da177e4SLinus Torvalds 	case MPT_IOC_PRE_RESET:
530ea2a788dSKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
531ea2a788dSKashyap, Desai 		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
532ea2a788dSKashyap, Desai 		break;
533ea2a788dSKashyap, Desai 	case MPT_IOC_POST_RESET:
534ea2a788dSKashyap, Desai 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
535ea2a788dSKashyap, Desai 		    "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
536ea2a788dSKashyap, Desai 		if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
537ea2a788dSKashyap, Desai 			ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
538ea2a788dSKashyap, Desai 			complete(&ioc->ioctl_cmds.done);
539ea2a788dSKashyap, Desai 		}
540ea2a788dSKashyap, Desai 		break;
5411da177e4SLinus Torvalds 	default:
5421da177e4SLinus Torvalds 		break;
5431da177e4SLinus Torvalds 	}
5441da177e4SLinus Torvalds 
5451da177e4SLinus Torvalds 	return 1;
5461da177e4SLinus Torvalds }
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
549ea5a7a82SMoore, Eric /* ASYNC Event Notification Support */
550ea5a7a82SMoore, Eric static int
mptctl_event_process(MPT_ADAPTER * ioc,EventNotificationReply_t * pEvReply)551ea5a7a82SMoore, Eric mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
552ea5a7a82SMoore, Eric {
553ea5a7a82SMoore, Eric 	u8 event;
554ea5a7a82SMoore, Eric 
555ea5a7a82SMoore, Eric 	event = le32_to_cpu(pEvReply->Event) & 0xFF;
556ea5a7a82SMoore, Eric 
55709120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n",
558cadbd4a5SHarvey Harrison 	    ioc->name, __func__));
559ea5a7a82SMoore, Eric 	if(async_queue == NULL)
560ea5a7a82SMoore, Eric 		return 1;
561ea5a7a82SMoore, Eric 
562ea5a7a82SMoore, Eric 	/* Raise SIGIO for persistent events.
563ea5a7a82SMoore, Eric 	 * TODO - this define is not in MPI spec yet,
564ea5a7a82SMoore, Eric 	 * but they plan to set it to 0x21
565ea5a7a82SMoore, Eric 	 */
566ea5a7a82SMoore, Eric 	if (event == 0x21) {
567ea5a7a82SMoore, Eric 		ioc->aen_event_read_flag=1;
56809120a8cSPrakash, Sathya 		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Raised SIGIO to application\n",
56909120a8cSPrakash, Sathya 		    ioc->name));
57009120a8cSPrakash, Sathya 		devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
57109120a8cSPrakash, Sathya 		    "Raised SIGIO to application\n", ioc->name));
572ea5a7a82SMoore, Eric 		kill_fasync(&async_queue, SIGIO, POLL_IN);
573ea5a7a82SMoore, Eric 		return 1;
574ea5a7a82SMoore, Eric 	 }
575ea5a7a82SMoore, Eric 
576ea5a7a82SMoore, Eric 	/* This flag is set after SIGIO was raised, and
577ea5a7a82SMoore, Eric 	 * remains set until the application has read
578ea5a7a82SMoore, Eric 	 * the event log via ioctl=MPTEVENTREPORT
579ea5a7a82SMoore, Eric 	 */
580ea5a7a82SMoore, Eric 	if(ioc->aen_event_read_flag)
581ea5a7a82SMoore, Eric 		return 1;
582ea5a7a82SMoore, Eric 
583ea5a7a82SMoore, Eric 	/* Signal only for the events that are
584ea5a7a82SMoore, Eric 	 * requested for by the application
585ea5a7a82SMoore, Eric 	 */
586ea5a7a82SMoore, Eric 	if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
587ea5a7a82SMoore, Eric 		ioc->aen_event_read_flag=1;
58809120a8cSPrakash, Sathya 		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
58909120a8cSPrakash, Sathya 		    "Raised SIGIO to application\n", ioc->name));
59009120a8cSPrakash, Sathya 		devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
59109120a8cSPrakash, Sathya 		    "Raised SIGIO to application\n", ioc->name));
592ea5a7a82SMoore, Eric 		kill_fasync(&async_queue, SIGIO, POLL_IN);
593ea5a7a82SMoore, Eric 	}
594ea5a7a82SMoore, Eric 	return 1;
595ea5a7a82SMoore, Eric }
596ea5a7a82SMoore, Eric 
597ea5a7a82SMoore, Eric static int
mptctl_fasync(int fd,struct file * filep,int mode)598ea5a7a82SMoore, Eric mptctl_fasync(int fd, struct file *filep, int mode)
599ea5a7a82SMoore, Eric {
600ea5a7a82SMoore, Eric 	MPT_ADAPTER	*ioc;
601b7e3e1fbSJonathan Corbet 	int ret;
602ea5a7a82SMoore, Eric 
603c45d15d2SArnd Bergmann 	mutex_lock(&mpctl_mutex);
604ea5a7a82SMoore, Eric 	list_for_each_entry(ioc, &ioc_list, list)
605ea5a7a82SMoore, Eric 		ioc->aen_event_read_flag=0;
606ea5a7a82SMoore, Eric 
607b7e3e1fbSJonathan Corbet 	ret = fasync_helper(fd, filep, mode, &async_queue);
608c45d15d2SArnd Bergmann 	mutex_unlock(&mpctl_mutex);
609b7e3e1fbSJonathan Corbet 	return ret;
610ea5a7a82SMoore, Eric }
611ea5a7a82SMoore, Eric 
612ea5a7a82SMoore, Eric /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6131da177e4SLinus Torvalds /*
6141da177e4SLinus Torvalds  *  MPT ioctl handler
6151da177e4SLinus Torvalds  *  cmd - specify the particular IOCTL command to be issued
6161da177e4SLinus Torvalds  *  arg - data specific to the command. Must not be null.
6171da177e4SLinus Torvalds  */
6181da177e4SLinus Torvalds static long
__mptctl_ioctl(struct file * file,unsigned int cmd,unsigned long arg)6191da177e4SLinus Torvalds __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
6201da177e4SLinus Torvalds {
6211da177e4SLinus Torvalds 	mpt_ioctl_header __user *uhdr = (void __user *) arg;
6221da177e4SLinus Torvalds 	mpt_ioctl_header	 khdr;
6231da177e4SLinus Torvalds 	unsigned iocnumX;
6241da177e4SLinus Torvalds 	int nonblock = (file->f_flags & O_NONBLOCK);
6251da177e4SLinus Torvalds 	int ret;
6261da177e4SLinus Torvalds 	MPT_ADAPTER *iocp = NULL;
6271da177e4SLinus Torvalds 
6281da177e4SLinus Torvalds 	if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
62929dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - "
6301da177e4SLinus Torvalds 				"Unable to copy mpt_ioctl_header data @ %p\n",
6311da177e4SLinus Torvalds 				__FILE__, __LINE__, uhdr);
6321da177e4SLinus Torvalds 		return -EFAULT;
6331da177e4SLinus Torvalds 	}
6341da177e4SLinus Torvalds 	ret = -ENXIO;				/* (-6) No such device or address */
6351da177e4SLinus Torvalds 
636231159f3SColin Ian King 	/* Verify intended MPT adapter - set iocnumX and the adapter
6371da177e4SLinus Torvalds 	 * pointer (iocp)
6381da177e4SLinus Torvalds 	 */
6391da177e4SLinus Torvalds 	iocnumX = khdr.iocnum & 0xFF;
640231159f3SColin Ian King 	if ((mpt_verify_adapter(iocnumX, &iocp) < 0) || (iocp == NULL))
6411da177e4SLinus Torvalds 		return -ENODEV;
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds 	if (!iocp->active) {
64429dd3609SEric Moore 		printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n",
6451da177e4SLinus Torvalds 				__FILE__, __LINE__);
6461da177e4SLinus Torvalds 		return -EFAULT;
6471da177e4SLinus Torvalds 	}
6481da177e4SLinus Torvalds 
6491da177e4SLinus Torvalds 	/* Handle those commands that are just returning
6501da177e4SLinus Torvalds 	 * information stored in the driver.
6511da177e4SLinus Torvalds 	 * These commands should never time out and are unaffected
6521da177e4SLinus Torvalds 	 * by TM and FW reloads.
6531da177e4SLinus Torvalds 	 */
6541da177e4SLinus Torvalds 	if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) {
65528d76df1SDan Carpenter 		return mptctl_getiocinfo(iocp, arg, _IOC_SIZE(cmd));
6561da177e4SLinus Torvalds 	} else if (cmd == MPTTARGETINFO) {
65728d76df1SDan Carpenter 		return mptctl_gettargetinfo(iocp, arg);
6581da177e4SLinus Torvalds 	} else if (cmd == MPTTEST) {
65928d76df1SDan Carpenter 		return mptctl_readtest(iocp, arg);
6601da177e4SLinus Torvalds 	} else if (cmd == MPTEVENTQUERY) {
66128d76df1SDan Carpenter 		return mptctl_eventquery(iocp, arg);
6621da177e4SLinus Torvalds 	} else if (cmd == MPTEVENTENABLE) {
66328d76df1SDan Carpenter 		return mptctl_eventenable(iocp, arg);
6641da177e4SLinus Torvalds 	} else if (cmd == MPTEVENTREPORT) {
66528d76df1SDan Carpenter 		return mptctl_eventreport(iocp, arg);
6661da177e4SLinus Torvalds 	} else if (cmd == MPTFWREPLACE) {
66728d76df1SDan Carpenter 		return mptctl_replace_fw(iocp, arg);
6681da177e4SLinus Torvalds 	}
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 	/* All of these commands require an interrupt or
6711da177e4SLinus Torvalds 	 * are unknown/illegal.
6721da177e4SLinus Torvalds 	 */
6731da177e4SLinus Torvalds 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
6741da177e4SLinus Torvalds 		return ret;
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds 	if (cmd == MPTFWDOWNLOAD)
67728d76df1SDan Carpenter 		ret = mptctl_fw_download(iocp, arg);
6781da177e4SLinus Torvalds 	else if (cmd == MPTCOMMAND)
67928d76df1SDan Carpenter 		ret = mptctl_mpt_command(iocp, arg);
6801da177e4SLinus Torvalds 	else if (cmd == MPTHARDRESET)
68128d76df1SDan Carpenter 		ret = mptctl_do_reset(iocp, arg);
6821da177e4SLinus Torvalds 	else if ((cmd & ~IOCSIZE_MASK) == (HP_GETHOSTINFO & ~IOCSIZE_MASK))
68328d76df1SDan Carpenter 		ret = mptctl_hp_hostinfo(iocp, arg, _IOC_SIZE(cmd));
6841da177e4SLinus Torvalds 	else if (cmd == HP_GETTARGETINFO)
68528d76df1SDan Carpenter 		ret = mptctl_hp_targetinfo(iocp, arg);
6861da177e4SLinus Torvalds 	else
6871da177e4SLinus Torvalds 		ret = -EINVAL;
6881da177e4SLinus Torvalds 
689ea2a788dSKashyap, Desai 	mutex_unlock(&iocp->ioctl_cmds.mutex);
6901da177e4SLinus Torvalds 
6911da177e4SLinus Torvalds 	return ret;
6921da177e4SLinus Torvalds }
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds static long
mptctl_ioctl(struct file * file,unsigned int cmd,unsigned long arg)6951da177e4SLinus Torvalds mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
6961da177e4SLinus Torvalds {
6971da177e4SLinus Torvalds 	long ret;
698c45d15d2SArnd Bergmann 	mutex_lock(&mpctl_mutex);
6991da177e4SLinus Torvalds 	ret = __mptctl_ioctl(file, cmd, arg);
700c45d15d2SArnd Bergmann 	mutex_unlock(&mpctl_mutex);
7011da177e4SLinus Torvalds 	return ret;
7021da177e4SLinus Torvalds }
7031da177e4SLinus Torvalds 
mptctl_do_reset(MPT_ADAPTER * iocp,unsigned long arg)70428d76df1SDan Carpenter static int mptctl_do_reset(MPT_ADAPTER *iocp, unsigned long arg)
7051da177e4SLinus Torvalds {
7061da177e4SLinus Torvalds 	struct mpt_ioctl_diag_reset __user *urinfo = (void __user *) arg;
7071da177e4SLinus Torvalds 	struct mpt_ioctl_diag_reset krinfo;
7081da177e4SLinus Torvalds 
7091da177e4SLinus Torvalds 	if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
71029dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - "
7111da177e4SLinus Torvalds 				"Unable to copy mpt_ioctl_diag_reset struct @ %p\n",
7121da177e4SLinus Torvalds 				__FILE__, __LINE__, urinfo);
7131da177e4SLinus Torvalds 		return -EFAULT;
7141da177e4SLinus Torvalds 	}
7151da177e4SLinus Torvalds 
71609120a8cSPrakash, Sathya 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_reset called.\n",
71709120a8cSPrakash, Sathya 	    iocp->name));
71809120a8cSPrakash, Sathya 
7191da177e4SLinus Torvalds 	if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {
72029dd3609SEric Moore 		printk (MYIOC_s_ERR_FMT "%s@%d::mptctl_do_reset - reset failed.\n",
72129dd3609SEric Moore 			iocp->name, __FILE__, __LINE__);
7221da177e4SLinus Torvalds 		return -1;
7231da177e4SLinus Torvalds 	}
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds 	return 0;
7261da177e4SLinus Torvalds }
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7291da177e4SLinus Torvalds /*
7301da177e4SLinus Torvalds  * MPT FW download function.  Cast the arg into the mpt_fw_xfer structure.
7311da177e4SLinus Torvalds  * This structure contains: iocnum, firmware length (bytes),
7321da177e4SLinus Torvalds  *      pointer to user space memory where the fw image is stored.
7331da177e4SLinus Torvalds  *
7341da177e4SLinus Torvalds  * Outputs:	None.
7351da177e4SLinus Torvalds  * Return:	0 if successful
7361da177e4SLinus Torvalds  *		-EFAULT if data unavailable
7371da177e4SLinus Torvalds  *		-ENXIO  if no such device
7381da177e4SLinus Torvalds  *		-EAGAIN if resource problem
7391da177e4SLinus Torvalds  *		-ENOMEM if no memory for SGE
7401da177e4SLinus Torvalds  *		-EMLINK if too many chain buffers required
7411da177e4SLinus Torvalds  *		-EBADRQC if adapter does not support FW download
7421da177e4SLinus Torvalds  *		-EBUSY if adapter is busy
7431da177e4SLinus Torvalds  *		-ENOMSG if FW upload returned bad status
7441da177e4SLinus Torvalds  */
7451da177e4SLinus Torvalds static int
mptctl_fw_download(MPT_ADAPTER * iocp,unsigned long arg)74628d76df1SDan Carpenter mptctl_fw_download(MPT_ADAPTER *iocp, unsigned long arg)
7471da177e4SLinus Torvalds {
7481da177e4SLinus Torvalds 	struct mpt_fw_xfer __user *ufwdl = (void __user *) arg;
7491da177e4SLinus Torvalds 	struct mpt_fw_xfer	 kfwdl;
7501da177e4SLinus Torvalds 
7511da177e4SLinus Torvalds 	if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
75229dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::_ioctl_fwdl - "
7531da177e4SLinus Torvalds 				"Unable to copy mpt_fw_xfer struct @ %p\n",
7541da177e4SLinus Torvalds 				__FILE__, __LINE__, ufwdl);
7551da177e4SLinus Torvalds 		return -EFAULT;
7561da177e4SLinus Torvalds 	}
7571da177e4SLinus Torvalds 
75828d76df1SDan Carpenter 	return mptctl_do_fw_download(iocp, kfwdl.bufp, kfwdl.fwlen);
7591da177e4SLinus Torvalds }
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7621da177e4SLinus Torvalds /*
7631da177e4SLinus Torvalds  * FW Download engine.
7641da177e4SLinus Torvalds  * Outputs:	None.
7651da177e4SLinus Torvalds  * Return:	0 if successful
7661da177e4SLinus Torvalds  *		-EFAULT if data unavailable
7671da177e4SLinus Torvalds  *		-ENXIO  if no such device
7681da177e4SLinus Torvalds  *		-EAGAIN if resource problem
7691da177e4SLinus Torvalds  *		-ENOMEM if no memory for SGE
7701da177e4SLinus Torvalds  *		-EMLINK if too many chain buffers required
7711da177e4SLinus Torvalds  *		-EBADRQC if adapter does not support FW download
7721da177e4SLinus Torvalds  *		-EBUSY if adapter is busy
7731da177e4SLinus Torvalds  *		-ENOMSG if FW upload returned bad status
7741da177e4SLinus Torvalds  */
7751da177e4SLinus Torvalds static int
mptctl_do_fw_download(MPT_ADAPTER * iocp,char __user * ufwbuf,size_t fwlen)77628d76df1SDan Carpenter mptctl_do_fw_download(MPT_ADAPTER *iocp, char __user *ufwbuf, size_t fwlen)
7771da177e4SLinus Torvalds {
7781da177e4SLinus Torvalds 	FWDownload_t		*dlmsg;
7791da177e4SLinus Torvalds 	MPT_FRAME_HDR		*mf;
7801da177e4SLinus Torvalds 	FWDownloadTCSGE_t	*ptsge;
7811da177e4SLinus Torvalds 	MptSge_t		*sgl, *sgIn;
7821da177e4SLinus Torvalds 	char			*sgOut;
7831da177e4SLinus Torvalds 	struct buflist		*buflist;
7841da177e4SLinus Torvalds 	struct buflist		*bl;
7851da177e4SLinus Torvalds 	dma_addr_t		 sgl_dma;
7861da177e4SLinus Torvalds 	int			 ret;
7871da177e4SLinus Torvalds 	int			 numfrags = 0;
7881da177e4SLinus Torvalds 	int			 maxfrags;
7891da177e4SLinus Torvalds 	int			 n = 0;
7901da177e4SLinus Torvalds 	u32			 sgdir;
7911da177e4SLinus Torvalds 	u32			 nib;
7921da177e4SLinus Torvalds 	int			 fw_bytes_copied = 0;
7931da177e4SLinus Torvalds 	int			 i;
7941da177e4SLinus Torvalds 	int			 sge_offset = 0;
7951da177e4SLinus Torvalds 	u16			 iocstat;
7961da177e4SLinus Torvalds 	pFWDownloadReply_t	 ReplyMsg = NULL;
797ea2a788dSKashyap, Desai 	unsigned long		 timeleft;
7981da177e4SLinus Torvalds 
7991da177e4SLinus Torvalds 	/*  Valid device. Get a message frame and construct the FW download message.
8001da177e4SLinus Torvalds 	*/
8011da177e4SLinus Torvalds 	if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL)
8021da177e4SLinus Torvalds 		return -EAGAIN;
80309120a8cSPrakash, Sathya 
80409120a8cSPrakash, Sathya 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT
80509120a8cSPrakash, Sathya 	    "mptctl_do_fwdl called. mptctl_id = %xh.\n", iocp->name, mptctl_id));
80609120a8cSPrakash, Sathya 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.bufp  = %p\n",
80709120a8cSPrakash, Sathya 	    iocp->name, ufwbuf));
80809120a8cSPrakash, Sathya 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.fwlen = %d\n",
80909120a8cSPrakash, Sathya 	    iocp->name, (int)fwlen));
81009120a8cSPrakash, Sathya 
8111da177e4SLinus Torvalds 	dlmsg = (FWDownload_t*) mf;
8121da177e4SLinus Torvalds 	ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;
8131da177e4SLinus Torvalds 	sgOut = (char *) (ptsge + 1);
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds 	/*
8161da177e4SLinus Torvalds 	 * Construct f/w download request
8171da177e4SLinus Torvalds 	 */
8181da177e4SLinus Torvalds 	dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW;
8191da177e4SLinus Torvalds 	dlmsg->Reserved = 0;
8201da177e4SLinus Torvalds 	dlmsg->ChainOffset = 0;
8211da177e4SLinus Torvalds 	dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD;
8221da177e4SLinus Torvalds 	dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0;
823946cbf04SMoore, Eric 	if (iocp->facts.MsgVersion >= MPI_VERSION_01_05)
824946cbf04SMoore, Eric 		dlmsg->MsgFlags = MPI_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
825946cbf04SMoore, Eric 	else
8261da177e4SLinus Torvalds 		dlmsg->MsgFlags = 0;
8271da177e4SLinus Torvalds 
828946cbf04SMoore, Eric 
8291da177e4SLinus Torvalds 	/* Set up the Transaction SGE.
8301da177e4SLinus Torvalds 	 */
8311da177e4SLinus Torvalds 	ptsge->Reserved = 0;
8321da177e4SLinus Torvalds 	ptsge->ContextSize = 0;
8331da177e4SLinus Torvalds 	ptsge->DetailsLength = 12;
8341da177e4SLinus Torvalds 	ptsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
8351da177e4SLinus Torvalds 	ptsge->Reserved_0100_Checksum = 0;
8361da177e4SLinus Torvalds 	ptsge->ImageOffset = 0;
8371da177e4SLinus Torvalds 	ptsge->ImageSize = cpu_to_le32(fwlen);
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	/* Add the SGL
8401da177e4SLinus Torvalds 	 */
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	/*
8431da177e4SLinus Torvalds 	 * Need to kmalloc area(s) for holding firmware image bytes.
8441da177e4SLinus Torvalds 	 * But we need to do it piece meal, using a proper
8451da177e4SLinus Torvalds 	 * scatter gather list (with 128kB MAX hunks).
8461da177e4SLinus Torvalds 	 *
8471da177e4SLinus Torvalds 	 * A practical limit here might be # of sg hunks that fit into
8481da177e4SLinus Torvalds 	 * a single IOC request frame; 12 or 8 (see below), so:
8491da177e4SLinus Torvalds 	 * For FC9xx: 12 x 128kB == 1.5 mB (max)
8501da177e4SLinus Torvalds 	 * For C1030:  8 x 128kB == 1   mB (max)
8511da177e4SLinus Torvalds 	 * We could support chaining, but things get ugly(ier:)
8521da177e4SLinus Torvalds 	 *
8531da177e4SLinus Torvalds 	 * Set the sge_offset to the start of the sgl (bytes).
8541da177e4SLinus Torvalds 	 */
8551da177e4SLinus Torvalds 	sgdir = 0x04000000;		/* IOC will READ from sys mem */
8561da177e4SLinus Torvalds 	sge_offset = sizeof(MPIHeader_t) + sizeof(FWDownloadTCSGE_t);
8571da177e4SLinus Torvalds 	if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, sge_offset,
8581da177e4SLinus Torvalds 				    &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
8591da177e4SLinus Torvalds 		return -ENOMEM;
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds 	/*
8621da177e4SLinus Torvalds 	 * We should only need SGL with 2 simple_32bit entries (up to 256 kB)
8631da177e4SLinus Torvalds 	 * for FC9xx f/w image, but calculate max number of sge hunks
8641da177e4SLinus Torvalds 	 * we can fit into a request frame, and limit ourselves to that.
8651da177e4SLinus Torvalds 	 * (currently no chain support)
8661da177e4SLinus Torvalds 	 * maxfrags = (Request Size - FWdownload Size ) / Size of 32 bit SGE
8671da177e4SLinus Torvalds 	 *	Request		maxfrags
8681da177e4SLinus Torvalds 	 *	128		12
8691da177e4SLinus Torvalds 	 *	96		8
8701da177e4SLinus Torvalds 	 *	64		4
8711da177e4SLinus Torvalds 	 */
87214d0f0b0SKashyap, Desai 	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) -
87314d0f0b0SKashyap, Desai 			sizeof(FWDownloadTCSGE_t))
87414d0f0b0SKashyap, Desai 			/ iocp->SGE_size;
8751da177e4SLinus Torvalds 	if (numfrags > maxfrags) {
8761da177e4SLinus Torvalds 		ret = -EMLINK;
8771da177e4SLinus Torvalds 		goto fwdl_out;
8781da177e4SLinus Torvalds 	}
8791da177e4SLinus Torvalds 
88009120a8cSPrakash, Sathya 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: sgl buffer = %p, sgfrags = %d\n",
88109120a8cSPrakash, Sathya 	    iocp->name, sgl, numfrags));
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds 	/*
8841da177e4SLinus Torvalds 	 * Parse SG list, copying sgl itself,
8851da177e4SLinus Torvalds 	 * plus f/w image hunks from user space as we go...
8861da177e4SLinus Torvalds 	 */
8871da177e4SLinus Torvalds 	ret = -EFAULT;
8881da177e4SLinus Torvalds 	sgIn = sgl;
8891da177e4SLinus Torvalds 	bl = buflist;
8901da177e4SLinus Torvalds 	for (i=0; i < numfrags; i++) {
8911da177e4SLinus Torvalds 
8921da177e4SLinus Torvalds 		/* Get the SGE type: 0 - TCSGE, 3 - Chain, 1 - Simple SGE
8931da177e4SLinus Torvalds 		 * Skip everything but Simple. If simple, copy from
8941da177e4SLinus Torvalds 		 *	user space into kernel space.
8951da177e4SLinus Torvalds 		 * Note: we should not have anything but Simple as
8961da177e4SLinus Torvalds 		 *	Chain SGE are illegal.
8971da177e4SLinus Torvalds 		 */
8981da177e4SLinus Torvalds 		nib = (sgIn->FlagsLength & 0x30000000) >> 28;
8991da177e4SLinus Torvalds 		if (nib == 0 || nib == 3) {
9001da177e4SLinus Torvalds 			;
9011da177e4SLinus Torvalds 		} else if (sgIn->Address) {
90214d0f0b0SKashyap, Desai 			iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
9031da177e4SLinus Torvalds 			n++;
9041da177e4SLinus Torvalds 			if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
90529dd3609SEric Moore 				printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
9061da177e4SLinus Torvalds 					"Unable to copy f/w buffer hunk#%d @ %p\n",
90729dd3609SEric Moore 					iocp->name, __FILE__, __LINE__, n, ufwbuf);
9081da177e4SLinus Torvalds 				goto fwdl_out;
9091da177e4SLinus Torvalds 			}
9101da177e4SLinus Torvalds 			fw_bytes_copied += bl->len;
9111da177e4SLinus Torvalds 		}
9121da177e4SLinus Torvalds 		sgIn++;
9131da177e4SLinus Torvalds 		bl++;
91414d0f0b0SKashyap, Desai 		sgOut += iocp->SGE_size;
9151da177e4SLinus Torvalds 	}
9161da177e4SLinus Torvalds 
91709120a8cSPrakash, Sathya 	DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags);
9181da177e4SLinus Torvalds 
9191da177e4SLinus Torvalds 	/*
9201da177e4SLinus Torvalds 	 * Finally, perform firmware download.
9211da177e4SLinus Torvalds 	 */
922946cbf04SMoore, Eric 	ReplyMsg = NULL;
923ea2a788dSKashyap, Desai 	SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, dlmsg->MsgContext);
924ea2a788dSKashyap, Desai 	INITIALIZE_MGMT_STATUS(iocp->ioctl_cmds.status)
9251da177e4SLinus Torvalds 	mpt_put_msg_frame(mptctl_id, iocp, mf);
9261da177e4SLinus Torvalds 
9271da177e4SLinus Torvalds 	/* Now wait for the command to complete */
928ea2a788dSKashyap, Desai retry_wait:
929ea2a788dSKashyap, Desai 	timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60);
930ea2a788dSKashyap, Desai 	if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
931ea2a788dSKashyap, Desai 		ret = -ETIME;
932ea2a788dSKashyap, Desai 		printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__);
933ea2a788dSKashyap, Desai 		if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
934ea2a788dSKashyap, Desai 			mpt_free_msg_frame(iocp, mf);
935ea2a788dSKashyap, Desai 			goto fwdl_out;
936ea2a788dSKashyap, Desai 		}
93797009a29SKei Tokunaga 		if (!timeleft) {
93897009a29SKei Tokunaga 			printk(MYIOC_s_WARN_FMT
93997009a29SKei Tokunaga 			       "FW download timeout, doorbell=0x%08x\n",
94097009a29SKei Tokunaga 			       iocp->name, mpt_GetIocState(iocp, 0));
941ea2a788dSKashyap, Desai 			mptctl_timeout_expired(iocp, mf);
94297009a29SKei Tokunaga 		} else
943ea2a788dSKashyap, Desai 			goto retry_wait;
944ea2a788dSKashyap, Desai 		goto fwdl_out;
945ea2a788dSKashyap, Desai 	}
9461da177e4SLinus Torvalds 
947ea2a788dSKashyap, Desai 	if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
948ea2a788dSKashyap, Desai 		printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__);
949ea2a788dSKashyap, Desai 		mpt_free_msg_frame(iocp, mf);
9501da177e4SLinus Torvalds 		ret = -ENODATA;
9511da177e4SLinus Torvalds 		goto fwdl_out;
9521da177e4SLinus Torvalds 	}
9531da177e4SLinus Torvalds 
9541da177e4SLinus Torvalds 	if (sgl)
9551da177e4SLinus Torvalds 		kfree_sgl(sgl, sgl_dma, buflist, iocp);
9561da177e4SLinus Torvalds 
957ea2a788dSKashyap, Desai 	ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply;
9581da177e4SLinus Torvalds 	iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
9591da177e4SLinus Torvalds 	if (iocstat == MPI_IOCSTATUS_SUCCESS) {
96025985edcSLucas De Marchi 		printk(MYIOC_s_INFO_FMT "F/W update successful!\n", iocp->name);
9611da177e4SLinus Torvalds 		return 0;
9621da177e4SLinus Torvalds 	} else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
96329dd3609SEric Moore 		printk(MYIOC_s_WARN_FMT "Hmmm...  F/W download not supported!?!\n",
9641da177e4SLinus Torvalds 			iocp->name);
96529dd3609SEric Moore 		printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n",
96629dd3609SEric Moore 			iocp->name);
9671da177e4SLinus Torvalds 		return -EBADRQC;
9681da177e4SLinus Torvalds 	} else if (iocstat == MPI_IOCSTATUS_BUSY) {
96929dd3609SEric Moore 		printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name);
97029dd3609SEric Moore 		printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name);
9711da177e4SLinus Torvalds 		return -EBUSY;
9721da177e4SLinus Torvalds 	} else {
97329dd3609SEric Moore 		printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n",
9741da177e4SLinus Torvalds 			iocp->name, iocstat);
97529dd3609SEric Moore 		printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name);
9761da177e4SLinus Torvalds 		return -ENOMSG;
9771da177e4SLinus Torvalds 	}
9781da177e4SLinus Torvalds 	return 0;
9791da177e4SLinus Torvalds 
9801da177e4SLinus Torvalds fwdl_out:
981ea2a788dSKashyap, Desai 
982ea2a788dSKashyap, Desai 	CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status);
983ea2a788dSKashyap, Desai 	SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0);
9841da177e4SLinus Torvalds         kfree_sgl(sgl, sgl_dma, buflist, iocp);
9851da177e4SLinus Torvalds 	return ret;
9861da177e4SLinus Torvalds }
9871da177e4SLinus Torvalds 
9881da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
9891da177e4SLinus Torvalds /*
9901da177e4SLinus Torvalds  * SGE Allocation routine
9911da177e4SLinus Torvalds  *
9921da177e4SLinus Torvalds  * Inputs:	bytes - number of bytes to be transferred
9931da177e4SLinus Torvalds  *		sgdir - data direction
9941da177e4SLinus Torvalds  *		sge_offset - offset (in bytes) from the start of the request
9951da177e4SLinus Torvalds  *			frame to the first SGE
9961da177e4SLinus Torvalds  *		ioc - pointer to the mptadapter
9971da177e4SLinus Torvalds  * Outputs:	frags - number of scatter gather elements
9981da177e4SLinus Torvalds  *		blp - point to the buflist pointer
9991da177e4SLinus Torvalds  *		sglbuf_dma - pointer to the (dma) sgl
10001da177e4SLinus Torvalds  * Returns:	Null if failes
10011da177e4SLinus Torvalds  *		pointer to the (virtual) sgl if successful.
10021da177e4SLinus Torvalds  */
10031da177e4SLinus Torvalds static MptSge_t *
kbuf_alloc_2_sgl(int bytes,u32 sgdir,int sge_offset,int * frags,struct buflist ** blp,dma_addr_t * sglbuf_dma,MPT_ADAPTER * ioc)10041da177e4SLinus Torvalds kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
10051da177e4SLinus Torvalds 		 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
10061da177e4SLinus Torvalds {
10071da177e4SLinus Torvalds 	MptSge_t	*sglbuf = NULL;		/* pointer to array of SGE */
10081da177e4SLinus Torvalds 						/* and chain buffers */
10091da177e4SLinus Torvalds 	struct buflist	*buflist = NULL;	/* kernel routine */
10101da177e4SLinus Torvalds 	MptSge_t	*sgl;
10111da177e4SLinus Torvalds 	int		 numfrags = 0;
10121da177e4SLinus Torvalds 	int		 fragcnt = 0;
10131da177e4SLinus Torvalds 	int		 alloc_sz = min(bytes,MAX_KMALLOC_SZ);	// avoid kernel warning msg!
10141da177e4SLinus Torvalds 	int		 bytes_allocd = 0;
10151da177e4SLinus Torvalds 	int		 this_alloc;
10161da177e4SLinus Torvalds 	dma_addr_t	 pa;					// phys addr
10171da177e4SLinus Torvalds 	int		 i, buflist_ent;
10181da177e4SLinus Torvalds 	int		 sg_spill = MAX_FRAGS_SPILL1;
10191da177e4SLinus Torvalds 	int		 dir;
102049121201SDan Carpenter 
102149121201SDan Carpenter 	if (bytes < 0)
102249121201SDan Carpenter 		return NULL;
102349121201SDan Carpenter 
10241da177e4SLinus Torvalds 	/* initialization */
10251da177e4SLinus Torvalds 	*frags = 0;
10261da177e4SLinus Torvalds 	*blp = NULL;
10271da177e4SLinus Torvalds 
10281da177e4SLinus Torvalds 	/* Allocate and initialize an array of kernel
10291da177e4SLinus Torvalds 	 * structures for the SG elements.
10301da177e4SLinus Torvalds 	 */
10311da177e4SLinus Torvalds 	i = MAX_SGL_BYTES / 8;
1032d7383a23SMariusz Kozlowski 	buflist = kzalloc(i, GFP_USER);
1033d7383a23SMariusz Kozlowski 	if (!buflist)
10341da177e4SLinus Torvalds 		return NULL;
10351da177e4SLinus Torvalds 	buflist_ent = 0;
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds 	/* Allocate a single block of memory to store the sg elements and
10381da177e4SLinus Torvalds 	 * the chain buffers.  The calling routine is responsible for
10391da177e4SLinus Torvalds 	 * copying the data in this array into the correct place in the
10401da177e4SLinus Torvalds 	 * request and chain buffers.
10411da177e4SLinus Torvalds 	 */
1042706dc3b9SChristophe JAILLET 	sglbuf = dma_alloc_coherent(&ioc->pcidev->dev, MAX_SGL_BYTES,
1043706dc3b9SChristophe JAILLET 				    sglbuf_dma, GFP_KERNEL);
10441da177e4SLinus Torvalds 	if (sglbuf == NULL)
10451da177e4SLinus Torvalds 		goto free_and_fail;
10461da177e4SLinus Torvalds 
10471da177e4SLinus Torvalds 	if (sgdir & 0x04000000)
1048b114dda6SChristophe JAILLET 		dir = DMA_TO_DEVICE;
10491da177e4SLinus Torvalds 	else
1050b114dda6SChristophe JAILLET 		dir = DMA_FROM_DEVICE;
10511da177e4SLinus Torvalds 
10521da177e4SLinus Torvalds 	/* At start:
10531da177e4SLinus Torvalds 	 *	sgl = sglbuf = point to beginning of sg buffer
10541da177e4SLinus Torvalds 	 *	buflist_ent = 0 = first kernel structure
10551da177e4SLinus Torvalds 	 *	sg_spill = number of SGE that can be written before the first
10561da177e4SLinus Torvalds 	 *		chain element.
10571da177e4SLinus Torvalds 	 *
10581da177e4SLinus Torvalds 	 */
10591da177e4SLinus Torvalds 	sgl = sglbuf;
106014d0f0b0SKashyap, Desai 	sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1;
10611da177e4SLinus Torvalds 	while (bytes_allocd < bytes) {
10621da177e4SLinus Torvalds 		this_alloc = min(alloc_sz, bytes-bytes_allocd);
10631da177e4SLinus Torvalds 		buflist[buflist_ent].len = this_alloc;
1064706dc3b9SChristophe JAILLET 		buflist[buflist_ent].kptr = dma_alloc_coherent(&ioc->pcidev->dev,
10651da177e4SLinus Torvalds 							       this_alloc,
1066706dc3b9SChristophe JAILLET 							       &pa, GFP_KERNEL);
10671da177e4SLinus Torvalds 		if (buflist[buflist_ent].kptr == NULL) {
10681da177e4SLinus Torvalds 			alloc_sz = alloc_sz / 2;
10691da177e4SLinus Torvalds 			if (alloc_sz == 0) {
107029dd3609SEric Moore 				printk(MYIOC_s_WARN_FMT "-SG: No can do - "
107129dd3609SEric Moore 				    "not enough memory!   :-(\n", ioc->name);
107229dd3609SEric Moore 				printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
107329dd3609SEric Moore 					ioc->name, numfrags);
10741da177e4SLinus Torvalds 				goto free_and_fail;
10751da177e4SLinus Torvalds 			}
10761da177e4SLinus Torvalds 			continue;
10771da177e4SLinus Torvalds 		} else {
10781da177e4SLinus Torvalds 			dma_addr_t dma_addr;
10791da177e4SLinus Torvalds 
10801da177e4SLinus Torvalds 			bytes_allocd += this_alloc;
108114d0f0b0SKashyap, Desai 			sgl->FlagsLength = (0x10000000|sgdir|this_alloc);
1082b114dda6SChristophe JAILLET 			dma_addr = dma_map_single(&ioc->pcidev->dev,
1083b114dda6SChristophe JAILLET 						  buflist[buflist_ent].kptr,
1084b114dda6SChristophe JAILLET 						  this_alloc, dir);
10851da177e4SLinus Torvalds 			sgl->Address = dma_addr;
10861da177e4SLinus Torvalds 
10871da177e4SLinus Torvalds 			fragcnt++;
10881da177e4SLinus Torvalds 			numfrags++;
10891da177e4SLinus Torvalds 			sgl++;
10901da177e4SLinus Torvalds 			buflist_ent++;
10911da177e4SLinus Torvalds 		}
10921da177e4SLinus Torvalds 
10931da177e4SLinus Torvalds 		if (bytes_allocd >= bytes)
10941da177e4SLinus Torvalds 			break;
10951da177e4SLinus Torvalds 
10961da177e4SLinus Torvalds 		/* Need to chain? */
10971da177e4SLinus Torvalds 		if (fragcnt == sg_spill) {
109829dd3609SEric Moore 			printk(MYIOC_s_WARN_FMT
109929dd3609SEric Moore 			    "-SG: No can do - " "Chain required!   :-(\n", ioc->name);
110029dd3609SEric Moore 			printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags);
11011da177e4SLinus Torvalds 			goto free_and_fail;
11021da177e4SLinus Torvalds 		}
11031da177e4SLinus Torvalds 
11041da177e4SLinus Torvalds 		/* overflow check... */
11051da177e4SLinus Torvalds 		if (numfrags*8 > MAX_SGL_BYTES){
11061da177e4SLinus Torvalds 			/* GRRRRR... */
110729dd3609SEric Moore 			printk(MYIOC_s_WARN_FMT "-SG: No can do - "
110829dd3609SEric Moore 				"too many SG frags!   :-(\n", ioc->name);
110929dd3609SEric Moore 			printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
111029dd3609SEric Moore 				ioc->name, numfrags);
11111da177e4SLinus Torvalds 			goto free_and_fail;
11121da177e4SLinus Torvalds 		}
11131da177e4SLinus Torvalds 	}
11141da177e4SLinus Torvalds 
11151da177e4SLinus Torvalds 	/* Last sge fixup: set LE+eol+eob bits */
11161da177e4SLinus Torvalds 	sgl[-1].FlagsLength |= 0xC1000000;
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 	*frags = numfrags;
11191da177e4SLinus Torvalds 	*blp = buflist;
11201da177e4SLinus Torvalds 
112109120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - "
112209120a8cSPrakash, Sathya 	   "%d SG frags generated!\n", ioc->name, numfrags));
11231da177e4SLinus Torvalds 
112409120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - "
112509120a8cSPrakash, Sathya 	   "last (big) alloc_sz=%d\n", ioc->name, alloc_sz));
11261da177e4SLinus Torvalds 
11271da177e4SLinus Torvalds 	return sglbuf;
11281da177e4SLinus Torvalds 
11291da177e4SLinus Torvalds free_and_fail:
11301da177e4SLinus Torvalds 	if (sglbuf != NULL) {
11311da177e4SLinus Torvalds 		for (i = 0; i < numfrags; i++) {
11321da177e4SLinus Torvalds 			dma_addr_t dma_addr;
11331da177e4SLinus Torvalds 			u8 *kptr;
11341da177e4SLinus Torvalds 			int len;
11351da177e4SLinus Torvalds 
11361da177e4SLinus Torvalds 			if ((sglbuf[i].FlagsLength >> 24) == 0x30)
11371da177e4SLinus Torvalds 				continue;
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds 			dma_addr = sglbuf[i].Address;
11401da177e4SLinus Torvalds 			kptr = buflist[i].kptr;
11411da177e4SLinus Torvalds 			len = buflist[i].len;
11421da177e4SLinus Torvalds 
1143b114dda6SChristophe JAILLET 			dma_free_coherent(&ioc->pcidev->dev, len, kptr,
1144b114dda6SChristophe JAILLET 					  dma_addr);
11451da177e4SLinus Torvalds 		}
1146b114dda6SChristophe JAILLET 		dma_free_coherent(&ioc->pcidev->dev, MAX_SGL_BYTES, sglbuf,
1147b114dda6SChristophe JAILLET 				  *sglbuf_dma);
11481da177e4SLinus Torvalds 	}
11491da177e4SLinus Torvalds 	kfree(buflist);
11501da177e4SLinus Torvalds 	return NULL;
11511da177e4SLinus Torvalds }
11521da177e4SLinus Torvalds 
11531da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11541da177e4SLinus Torvalds /*
11551da177e4SLinus Torvalds  * Routine to free the SGL elements.
11561da177e4SLinus Torvalds  */
11571da177e4SLinus Torvalds static void
kfree_sgl(MptSge_t * sgl,dma_addr_t sgl_dma,struct buflist * buflist,MPT_ADAPTER * ioc)11581da177e4SLinus Torvalds kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
11591da177e4SLinus Torvalds {
11601da177e4SLinus Torvalds 	MptSge_t	*sg = sgl;
11611da177e4SLinus Torvalds 	struct buflist	*bl = buflist;
11621da177e4SLinus Torvalds 	u32		 nib;
11631da177e4SLinus Torvalds 	int		 dir;
11641da177e4SLinus Torvalds 	int		 n = 0;
11651da177e4SLinus Torvalds 
11661da177e4SLinus Torvalds 	if (sg->FlagsLength & 0x04000000)
1167b114dda6SChristophe JAILLET 		dir = DMA_TO_DEVICE;
11681da177e4SLinus Torvalds 	else
1169b114dda6SChristophe JAILLET 		dir = DMA_FROM_DEVICE;
11701da177e4SLinus Torvalds 
11711da177e4SLinus Torvalds 	nib = (sg->FlagsLength & 0xF0000000) >> 28;
11721da177e4SLinus Torvalds 	while (! (nib & 0x4)) { /* eob */
11731da177e4SLinus Torvalds 		/* skip ignore/chain. */
11741da177e4SLinus Torvalds 		if (nib == 0 || nib == 3) {
11751da177e4SLinus Torvalds 			;
11761da177e4SLinus Torvalds 		} else if (sg->Address) {
11771da177e4SLinus Torvalds 			dma_addr_t dma_addr;
11781da177e4SLinus Torvalds 			void *kptr;
11791da177e4SLinus Torvalds 			int len;
11801da177e4SLinus Torvalds 
11811da177e4SLinus Torvalds 			dma_addr = sg->Address;
11821da177e4SLinus Torvalds 			kptr = bl->kptr;
11831da177e4SLinus Torvalds 			len = bl->len;
1184b114dda6SChristophe JAILLET 			dma_unmap_single(&ioc->pcidev->dev, dma_addr, len,
1185b114dda6SChristophe JAILLET 					 dir);
1186b114dda6SChristophe JAILLET 			dma_free_coherent(&ioc->pcidev->dev, len, kptr,
1187b114dda6SChristophe JAILLET 					  dma_addr);
11881da177e4SLinus Torvalds 			n++;
11891da177e4SLinus Torvalds 		}
11901da177e4SLinus Torvalds 		sg++;
11911da177e4SLinus Torvalds 		bl++;
11921da177e4SLinus Torvalds 		nib = (le32_to_cpu(sg->FlagsLength) & 0xF0000000) >> 28;
11931da177e4SLinus Torvalds 	}
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds 	/* we're at eob! */
11961da177e4SLinus Torvalds 	if (sg->Address) {
11971da177e4SLinus Torvalds 		dma_addr_t dma_addr;
11981da177e4SLinus Torvalds 		void *kptr;
11991da177e4SLinus Torvalds 		int len;
12001da177e4SLinus Torvalds 
12011da177e4SLinus Torvalds 		dma_addr = sg->Address;
12021da177e4SLinus Torvalds 		kptr = bl->kptr;
12031da177e4SLinus Torvalds 		len = bl->len;
1204b114dda6SChristophe JAILLET 		dma_unmap_single(&ioc->pcidev->dev, dma_addr, len, dir);
1205b114dda6SChristophe JAILLET 		dma_free_coherent(&ioc->pcidev->dev, len, kptr, dma_addr);
12061da177e4SLinus Torvalds 		n++;
12071da177e4SLinus Torvalds 	}
12081da177e4SLinus Torvalds 
1209b114dda6SChristophe JAILLET 	dma_free_coherent(&ioc->pcidev->dev, MAX_SGL_BYTES, sgl, sgl_dma);
12101da177e4SLinus Torvalds 	kfree(buflist);
121109120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: Free'd 1 SGL buf + %d kbufs!\n",
121209120a8cSPrakash, Sathya 	    ioc->name, n));
12131da177e4SLinus Torvalds }
12141da177e4SLinus Torvalds 
12151da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12161da177e4SLinus Torvalds /*
12171da177e4SLinus Torvalds  *	mptctl_getiocinfo - Query the host adapter for IOC information.
12181da177e4SLinus Torvalds  *	@arg: User space argument
12191da177e4SLinus Torvalds  *
12201da177e4SLinus Torvalds  * Outputs:	None.
12211da177e4SLinus Torvalds  * Return:	0 if successful
12221da177e4SLinus Torvalds  *		-EFAULT if data unavailable
12231da177e4SLinus Torvalds  *		-ENODEV  if no such device/adapter
12241da177e4SLinus Torvalds  */
12251da177e4SLinus Torvalds static int
mptctl_getiocinfo(MPT_ADAPTER * ioc,unsigned long arg,unsigned int data_size)122628d76df1SDan Carpenter mptctl_getiocinfo (MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size)
12271da177e4SLinus Torvalds {
12281da177e4SLinus Torvalds 	struct mpt_ioctl_iocinfo __user *uarg = (void __user *) arg;
12291da177e4SLinus Torvalds 	struct mpt_ioctl_iocinfo *karg;
12301da177e4SLinus Torvalds 	struct pci_dev		*pdev;
1231b6fe4ddcSMoore, Eric Dean  	unsigned int		port;
12321da177e4SLinus Torvalds 	int			cim_rev;
1233793955f5SEric Moore 	struct scsi_device 	*sdev;
1234a69de507SEric Moore 	VirtDevice		*vdevice;
12351da177e4SLinus Torvalds 
12361da177e4SLinus Torvalds 	/* Add of PCI INFO results in unaligned access for
12371da177e4SLinus Torvalds 	 * IA64 and Sparc. Reset long to int. Return no PCI
12381da177e4SLinus Torvalds 	 * data for obsolete format.
12391da177e4SLinus Torvalds 	 */
12401da177e4SLinus Torvalds 	if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev0))
12411da177e4SLinus Torvalds 		cim_rev = 0;
12421da177e4SLinus Torvalds 	else if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev1))
12431da177e4SLinus Torvalds 		cim_rev = 1;
12441da177e4SLinus Torvalds 	else if (data_size == sizeof(struct mpt_ioctl_iocinfo))
12451da177e4SLinus Torvalds 		cim_rev = 2;
12461da177e4SLinus Torvalds 	else if (data_size == (sizeof(struct mpt_ioctl_iocinfo_rev0)+12))
12471da177e4SLinus Torvalds 		cim_rev = 0;	/* obsolete */
12481da177e4SLinus Torvalds 	else
12491da177e4SLinus Torvalds 		return -EFAULT;
12501da177e4SLinus Torvalds 
12513e67c459SJoe Lawrence 	karg = memdup_user(uarg, data_size);
12523e67c459SJoe Lawrence 	if (IS_ERR(karg)) {
12533e67c459SJoe Lawrence 		printk(KERN_ERR MYNAM "%s@%d::mpt_ioctl_iocinfo() - memdup_user returned error [%ld]\n",
12543e67c459SJoe Lawrence 				__FILE__, __LINE__, PTR_ERR(karg));
12553e67c459SJoe Lawrence 		return PTR_ERR(karg);
12561da177e4SLinus Torvalds 	}
12571da177e4SLinus Torvalds 
1258b6fe4ddcSMoore, Eric Dean  	/* Verify the data transfer size is correct. */
12591da177e4SLinus Torvalds 	if (karg->hdr.maxDataSize != data_size) {
126029dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
12611da177e4SLinus Torvalds 			"Structure size mismatch. Command not completed.\n",
126229dd3609SEric Moore 			ioc->name, __FILE__, __LINE__);
12631da177e4SLinus Torvalds 		kfree(karg);
12641da177e4SLinus Torvalds 		return -EFAULT;
12651da177e4SLinus Torvalds 	}
12661da177e4SLinus Torvalds 
126709120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_getiocinfo called.\n",
126809120a8cSPrakash, Sathya 	    ioc->name));
126909120a8cSPrakash, Sathya 
12701da177e4SLinus Torvalds 	/* Fill in the data and return the structure to the calling
12711da177e4SLinus Torvalds 	 * program
12721da177e4SLinus Torvalds 	 */
12739cc1cfbcSMoore, Eric 	if (ioc->bus_type == SAS)
12749cc1cfbcSMoore, Eric 		karg->adapterType = MPT_IOCTL_INTERFACE_SAS;
12759cc1cfbcSMoore, Eric 	else if (ioc->bus_type == FC)
12761da177e4SLinus Torvalds 		karg->adapterType = MPT_IOCTL_INTERFACE_FC;
12771da177e4SLinus Torvalds 	else
12781da177e4SLinus Torvalds 		karg->adapterType = MPT_IOCTL_INTERFACE_SCSI;
12791da177e4SLinus Torvalds 
1280efee0bd9SJesper Juhl 	if (karg->hdr.port > 1) {
1281efee0bd9SJesper Juhl 		kfree(karg);
1282b6fe4ddcSMoore, Eric Dean  		return -EINVAL;
1283efee0bd9SJesper Juhl 	}
12841da177e4SLinus Torvalds 	port = karg->hdr.port;
12851da177e4SLinus Torvalds 
12861da177e4SLinus Torvalds 	karg->port = port;
12871da177e4SLinus Torvalds 	pdev = (struct pci_dev *) ioc->pcidev;
12881da177e4SLinus Torvalds 
12891da177e4SLinus Torvalds 	karg->pciId = pdev->device;
12909ceb5c16SSergei Shtylyov 	karg->hwRev = pdev->revision;
12911da177e4SLinus Torvalds 	karg->subSystemDevice = pdev->subsystem_device;
12921da177e4SLinus Torvalds 	karg->subSystemVendor = pdev->subsystem_vendor;
12931da177e4SLinus Torvalds 
12941da177e4SLinus Torvalds 	if (cim_rev == 1) {
12951da177e4SLinus Torvalds 		/* Get the PCI bus, device, and function numbers for the IOC
12961da177e4SLinus Torvalds 		 */
12971da177e4SLinus Torvalds 		karg->pciInfo.u.bits.busNumber = pdev->bus->number;
12981da177e4SLinus Torvalds 		karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn );
12991da177e4SLinus Torvalds 		karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn );
13001da177e4SLinus Torvalds 	} else if (cim_rev == 2) {
13011da177e4SLinus Torvalds 		/* Get the PCI bus, device, function and segment ID numbers
13021da177e4SLinus Torvalds 		   for the IOC */
13031da177e4SLinus Torvalds 		karg->pciInfo.u.bits.busNumber = pdev->bus->number;
13041da177e4SLinus Torvalds 		karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn );
13051da177e4SLinus Torvalds 		karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn );
13061da177e4SLinus Torvalds 		karg->pciInfo.segmentID = pci_domain_nr(pdev->bus);
13071da177e4SLinus Torvalds 	}
13081da177e4SLinus Torvalds 
13091da177e4SLinus Torvalds 	/* Get number of devices
13101da177e4SLinus Torvalds          */
1311793955f5SEric Moore 	karg->numDevices = 0;
1312793955f5SEric Moore 	if (ioc->sh) {
1313793955f5SEric Moore 		shost_for_each_device(sdev, ioc->sh) {
1314a69de507SEric Moore 			vdevice = sdev->hostdata;
131508f5c5c2SKashyap, Desai 			if (vdevice == NULL || vdevice->vtarget == NULL)
131608f5c5c2SKashyap, Desai 				continue;
1317a69de507SEric Moore 			if (vdevice->vtarget->tflags &
1318793955f5SEric Moore 			    MPT_TARGET_FLAGS_RAID_COMPONENT)
1319793955f5SEric Moore 				continue;
1320793955f5SEric Moore 			karg->numDevices++;
13211da177e4SLinus Torvalds 		}
13221da177e4SLinus Torvalds 	}
13231da177e4SLinus Torvalds 
13241da177e4SLinus Torvalds 	/* Set the BIOS and FW Version
13251da177e4SLinus Torvalds 	 */
13261da177e4SLinus Torvalds 	karg->FWVersion = ioc->facts.FWVersion.Word;
13271da177e4SLinus Torvalds 	karg->BIOSVersion = ioc->biosVersion;
13281da177e4SLinus Torvalds 
13291da177e4SLinus Torvalds 	/* Set the Version Strings.
13301da177e4SLinus Torvalds 	 */
13311da177e4SLinus Torvalds 	strncpy (karg->driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH);
13321da177e4SLinus Torvalds 	karg->driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0';
13331da177e4SLinus Torvalds 
13341da177e4SLinus Torvalds 	karg->busChangeEvent = 0;
13351da177e4SLinus Torvalds 	karg->hostId = ioc->pfacts[port].PortSCSIID;
13361da177e4SLinus Torvalds 	karg->rsvd[0] = karg->rsvd[1] = 0;
13371da177e4SLinus Torvalds 
13381da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
13391da177e4SLinus Torvalds 	 */
13401da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, karg, data_size)) {
134129dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
13421da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_iocinfo struct @ %p\n",
134329dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, uarg);
13441da177e4SLinus Torvalds 		kfree(karg);
13451da177e4SLinus Torvalds 		return -EFAULT;
13461da177e4SLinus Torvalds 	}
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds 	kfree(karg);
13491da177e4SLinus Torvalds 	return 0;
13501da177e4SLinus Torvalds }
13511da177e4SLinus Torvalds 
13521da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13531da177e4SLinus Torvalds /*
13541da177e4SLinus Torvalds  *	mptctl_gettargetinfo - Query the host adapter for target information.
13551da177e4SLinus Torvalds  *	@arg: User space argument
13561da177e4SLinus Torvalds  *
13571da177e4SLinus Torvalds  * Outputs:	None.
13581da177e4SLinus Torvalds  * Return:	0 if successful
13591da177e4SLinus Torvalds  *		-EFAULT if data unavailable
13601da177e4SLinus Torvalds  *		-ENODEV  if no such device/adapter
13611da177e4SLinus Torvalds  */
13621da177e4SLinus Torvalds static int
mptctl_gettargetinfo(MPT_ADAPTER * ioc,unsigned long arg)136328d76df1SDan Carpenter mptctl_gettargetinfo (MPT_ADAPTER *ioc, unsigned long arg)
13641da177e4SLinus Torvalds {
13651da177e4SLinus Torvalds 	struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
13661da177e4SLinus Torvalds 	struct mpt_ioctl_targetinfo karg;
1367a69de507SEric Moore 	VirtDevice		*vdevice;
13681da177e4SLinus Torvalds 	char			*pmem;
13691da177e4SLinus Torvalds 	int			*pdata;
13701da177e4SLinus Torvalds 	int			numDevices = 0;
1371793955f5SEric Moore 	int			lun;
13721da177e4SLinus Torvalds 	int			maxWordsLeft;
13731da177e4SLinus Torvalds 	int			numBytes;
1374793955f5SEric Moore 	struct scsi_device 	*sdev;
13751da177e4SLinus Torvalds 
13761da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
137729dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_gettargetinfo - "
13781da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
13791da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
13801da177e4SLinus Torvalds 		return -EFAULT;
13811da177e4SLinus Torvalds 	}
13821da177e4SLinus Torvalds 
138309120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_gettargetinfo called.\n",
138409120a8cSPrakash, Sathya 	    ioc->name));
13851da177e4SLinus Torvalds 	numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
13861da177e4SLinus Torvalds 	maxWordsLeft = numBytes/sizeof(int);
13871da177e4SLinus Torvalds 
13881da177e4SLinus Torvalds 	if (maxWordsLeft <= 0) {
138929dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
139029dd3609SEric Moore 			ioc->name, __FILE__, __LINE__);
13911da177e4SLinus Torvalds 		return -ENOMEM;
13921da177e4SLinus Torvalds 	}
13931da177e4SLinus Torvalds 
13941da177e4SLinus Torvalds 	/* Fill in the data and return the structure to the calling
13951da177e4SLinus Torvalds 	 * program
13961da177e4SLinus Torvalds 	 */
13971da177e4SLinus Torvalds 
13981da177e4SLinus Torvalds 	/* struct mpt_ioctl_targetinfo does not contain sufficient space
13991da177e4SLinus Torvalds 	 * for the target structures so when the IOCTL is called, there is
14001da177e4SLinus Torvalds 	 * not sufficient stack space for the structure. Allocate memory,
14011da177e4SLinus Torvalds 	 * populate the memory, copy back to the user, then free memory.
14021da177e4SLinus Torvalds 	 * targetInfo format:
14031da177e4SLinus Torvalds 	 * bits 31-24: reserved
14041da177e4SLinus Torvalds 	 *      23-16: LUN
14051da177e4SLinus Torvalds 	 *      15- 8: Bus Number
14061da177e4SLinus Torvalds 	 *       7- 0: Target ID
14071da177e4SLinus Torvalds 	 */
1408d7383a23SMariusz Kozlowski 	pmem = kzalloc(numBytes, GFP_KERNEL);
1409d7383a23SMariusz Kozlowski 	if (!pmem) {
141029dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
141129dd3609SEric Moore 			ioc->name, __FILE__, __LINE__);
14121da177e4SLinus Torvalds 		return -ENOMEM;
14131da177e4SLinus Torvalds 	}
14141da177e4SLinus Torvalds 	pdata =  (int *) pmem;
14151da177e4SLinus Torvalds 
14161da177e4SLinus Torvalds 	/* Get number of devices
14171da177e4SLinus Torvalds          */
1418793955f5SEric Moore 	if (ioc->sh){
1419793955f5SEric Moore 		shost_for_each_device(sdev, ioc->sh) {
1420793955f5SEric Moore 			if (!maxWordsLeft)
1421793955f5SEric Moore 				continue;
1422a69de507SEric Moore 			vdevice = sdev->hostdata;
142308f5c5c2SKashyap, Desai 			if (vdevice == NULL || vdevice->vtarget == NULL)
142408f5c5c2SKashyap, Desai 				continue;
1425a69de507SEric Moore 			if (vdevice->vtarget->tflags &
1426793955f5SEric Moore 			    MPT_TARGET_FLAGS_RAID_COMPONENT)
1427793955f5SEric Moore 				continue;
1428a69de507SEric Moore 			lun = (vdevice->vtarget->raidVolume) ? 0x80 : vdevice->lun;
1429a69de507SEric Moore 			*pdata = (((u8)lun << 16) + (vdevice->vtarget->channel << 8) +
1430a69de507SEric Moore 			    (vdevice->vtarget->id ));
14311da177e4SLinus Torvalds 			pdata++;
14321da177e4SLinus Torvalds 			numDevices++;
14331da177e4SLinus Torvalds 			--maxWordsLeft;
14341da177e4SLinus Torvalds 		}
14351da177e4SLinus Torvalds 	}
14361da177e4SLinus Torvalds 	karg.numDevices = numDevices;
14371da177e4SLinus Torvalds 
14381da177e4SLinus Torvalds 	/* Copy part of the data from kernel memory to user memory
14391da177e4SLinus Torvalds 	 */
14401da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg,
14411da177e4SLinus Torvalds 				sizeof(struct mpt_ioctl_targetinfo))) {
144229dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
14431da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
144429dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, uarg);
14451da177e4SLinus Torvalds 		kfree(pmem);
14461da177e4SLinus Torvalds 		return -EFAULT;
14471da177e4SLinus Torvalds 	}
14481da177e4SLinus Torvalds 
14491da177e4SLinus Torvalds 	/* Copy the remaining data from kernel memory to user memory
14501da177e4SLinus Torvalds 	 */
14511da177e4SLinus Torvalds 	if (copy_to_user(uarg->targetInfo, pmem, numBytes)) {
145229dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
14531da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
145429dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, pdata);
14551da177e4SLinus Torvalds 		kfree(pmem);
14561da177e4SLinus Torvalds 		return -EFAULT;
14571da177e4SLinus Torvalds 	}
14581da177e4SLinus Torvalds 
14591da177e4SLinus Torvalds 	kfree(pmem);
14601da177e4SLinus Torvalds 
14611da177e4SLinus Torvalds 	return 0;
14621da177e4SLinus Torvalds }
14631da177e4SLinus Torvalds 
14641da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
14651da177e4SLinus Torvalds /* MPT IOCTL Test function.
14661da177e4SLinus Torvalds  *
14671da177e4SLinus Torvalds  * Outputs:	None.
14681da177e4SLinus Torvalds  * Return:	0 if successful
14691da177e4SLinus Torvalds  *		-EFAULT if data unavailable
14701da177e4SLinus Torvalds  *		-ENODEV  if no such device/adapter
14711da177e4SLinus Torvalds  */
14721da177e4SLinus Torvalds static int
mptctl_readtest(MPT_ADAPTER * ioc,unsigned long arg)147328d76df1SDan Carpenter mptctl_readtest (MPT_ADAPTER *ioc, unsigned long arg)
14741da177e4SLinus Torvalds {
14751da177e4SLinus Torvalds 	struct mpt_ioctl_test __user *uarg = (void __user *) arg;
14761da177e4SLinus Torvalds 	struct mpt_ioctl_test	 karg;
14771da177e4SLinus Torvalds 
14781da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
147929dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - "
14801da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_test struct @ %p\n",
14811da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
14821da177e4SLinus Torvalds 		return -EFAULT;
14831da177e4SLinus Torvalds 	}
14841da177e4SLinus Torvalds 
148509120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_readtest called.\n",
148609120a8cSPrakash, Sathya 	    ioc->name));
14871da177e4SLinus Torvalds 	/* Fill in the data and return the structure to the calling
14881da177e4SLinus Torvalds 	 * program
14891da177e4SLinus Torvalds 	 */
14901da177e4SLinus Torvalds 
14911da177e4SLinus Torvalds #ifdef MFCNT
14921da177e4SLinus Torvalds 	karg.chip_type = ioc->mfcnt;
14931da177e4SLinus Torvalds #else
14941da177e4SLinus Torvalds 	karg.chip_type = ioc->pcidev->device;
14951da177e4SLinus Torvalds #endif
14961da177e4SLinus Torvalds 	strncpy (karg.name, ioc->name, MPT_MAX_NAME);
14971da177e4SLinus Torvalds 	karg.name[MPT_MAX_NAME-1]='\0';
14981da177e4SLinus Torvalds 	strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH);
14991da177e4SLinus Torvalds 	karg.product[MPT_PRODUCT_LENGTH-1]='\0';
15001da177e4SLinus Torvalds 
15011da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
15021da177e4SLinus Torvalds 	 */
15031da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) {
150429dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_readtest - "
15051da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_test struct @ %p\n",
150629dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, uarg);
15071da177e4SLinus Torvalds 		return -EFAULT;
15081da177e4SLinus Torvalds 	}
15091da177e4SLinus Torvalds 
15101da177e4SLinus Torvalds 	return 0;
15111da177e4SLinus Torvalds }
15121da177e4SLinus Torvalds 
15131da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
15141da177e4SLinus Torvalds /*
15151da177e4SLinus Torvalds  *	mptctl_eventquery - Query the host adapter for the event types
15161da177e4SLinus Torvalds  *	that are being logged.
15171da177e4SLinus Torvalds  *	@arg: User space argument
15181da177e4SLinus Torvalds  *
15191da177e4SLinus Torvalds  * Outputs:	None.
15201da177e4SLinus Torvalds  * Return:	0 if successful
15211da177e4SLinus Torvalds  *		-EFAULT if data unavailable
15221da177e4SLinus Torvalds  *		-ENODEV  if no such device/adapter
15231da177e4SLinus Torvalds  */
15241da177e4SLinus Torvalds static int
mptctl_eventquery(MPT_ADAPTER * ioc,unsigned long arg)152528d76df1SDan Carpenter mptctl_eventquery (MPT_ADAPTER *ioc, unsigned long arg)
15261da177e4SLinus Torvalds {
15271da177e4SLinus Torvalds 	struct mpt_ioctl_eventquery __user *uarg = (void __user *) arg;
15281da177e4SLinus Torvalds 	struct mpt_ioctl_eventquery	 karg;
15291da177e4SLinus Torvalds 
15301da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
153129dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - "
15321da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_eventquery struct @ %p\n",
15331da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
15341da177e4SLinus Torvalds 		return -EFAULT;
15351da177e4SLinus Torvalds 	}
15361da177e4SLinus Torvalds 
153709120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n",
153809120a8cSPrakash, Sathya 	    ioc->name));
15395b5ef4f6SMoore, Eric 	karg.eventEntries = MPTCTL_EVENT_LOG_SIZE;
15401da177e4SLinus Torvalds 	karg.eventTypes = ioc->eventTypes;
15411da177e4SLinus Torvalds 
15421da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
15431da177e4SLinus Torvalds 	 */
15441da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) {
154529dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventquery - "
15461da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_eventquery struct @ %p\n",
154729dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, uarg);
15481da177e4SLinus Torvalds 		return -EFAULT;
15491da177e4SLinus Torvalds 	}
15501da177e4SLinus Torvalds 	return 0;
15511da177e4SLinus Torvalds }
15521da177e4SLinus Torvalds 
15531da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
15541da177e4SLinus Torvalds static int
mptctl_eventenable(MPT_ADAPTER * ioc,unsigned long arg)155528d76df1SDan Carpenter mptctl_eventenable (MPT_ADAPTER *ioc, unsigned long arg)
15561da177e4SLinus Torvalds {
15571da177e4SLinus Torvalds 	struct mpt_ioctl_eventenable __user *uarg = (void __user *) arg;
15581da177e4SLinus Torvalds 	struct mpt_ioctl_eventenable	 karg;
15591da177e4SLinus Torvalds 
15601da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
156129dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - "
15621da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_eventenable struct @ %p\n",
15631da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
15641da177e4SLinus Torvalds 		return -EFAULT;
15651da177e4SLinus Torvalds 	}
15661da177e4SLinus Torvalds 
156709120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n",
156809120a8cSPrakash, Sathya 	    ioc->name));
15691da177e4SLinus Torvalds 	if (ioc->events == NULL) {
15701da177e4SLinus Torvalds 		/* Have not yet allocated memory - do so now.
15711da177e4SLinus Torvalds 		 */
15721da177e4SLinus Torvalds 		int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
1573d7383a23SMariusz Kozlowski 		ioc->events = kzalloc(sz, GFP_KERNEL);
1574d7383a23SMariusz Kozlowski 		if (!ioc->events) {
157529dd3609SEric Moore 			printk(MYIOC_s_ERR_FMT
157629dd3609SEric Moore 			    ": ERROR - Insufficient memory to add adapter!\n",
157729dd3609SEric Moore 			    ioc->name);
15781da177e4SLinus Torvalds 			return -ENOMEM;
15791da177e4SLinus Torvalds 		}
15801da177e4SLinus Torvalds 		ioc->alloc_total += sz;
15811da177e4SLinus Torvalds 
15821da177e4SLinus Torvalds 		ioc->eventContext = 0;
15831da177e4SLinus Torvalds         }
15841da177e4SLinus Torvalds 
15851da177e4SLinus Torvalds 	/* Update the IOC event logging flag.
15861da177e4SLinus Torvalds 	 */
15871da177e4SLinus Torvalds 	ioc->eventTypes = karg.eventTypes;
15881da177e4SLinus Torvalds 
15891da177e4SLinus Torvalds 	return 0;
15901da177e4SLinus Torvalds }
15911da177e4SLinus Torvalds 
15921da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
15931da177e4SLinus Torvalds static int
mptctl_eventreport(MPT_ADAPTER * ioc,unsigned long arg)159428d76df1SDan Carpenter mptctl_eventreport (MPT_ADAPTER *ioc, unsigned long arg)
15951da177e4SLinus Torvalds {
15961da177e4SLinus Torvalds 	struct mpt_ioctl_eventreport __user *uarg = (void __user *) arg;
15971da177e4SLinus Torvalds 	struct mpt_ioctl_eventreport	 karg;
15981da177e4SLinus Torvalds 	int			 numBytes, maxEvents, max;
15991da177e4SLinus Torvalds 
16001da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
160129dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_eventreport - "
16021da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_eventreport struct @ %p\n",
16031da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
16041da177e4SLinus Torvalds 		return -EFAULT;
16051da177e4SLinus Torvalds 	}
16061da177e4SLinus Torvalds 
160709120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
160809120a8cSPrakash, Sathya 	    ioc->name));
16091da177e4SLinus Torvalds 
16101da177e4SLinus Torvalds 	numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
16111da177e4SLinus Torvalds 	maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
16121da177e4SLinus Torvalds 
16131da177e4SLinus Torvalds 
16145b5ef4f6SMoore, Eric 	max = MPTCTL_EVENT_LOG_SIZE < maxEvents ? MPTCTL_EVENT_LOG_SIZE : maxEvents;
16151da177e4SLinus Torvalds 
16161da177e4SLinus Torvalds 	/* If fewer than 1 event is requested, there must have
16171da177e4SLinus Torvalds 	 * been some type of error.
16181da177e4SLinus Torvalds 	 */
16191da177e4SLinus Torvalds 	if ((max < 1) || !ioc->events)
16201da177e4SLinus Torvalds 		return -ENODATA;
16211da177e4SLinus Torvalds 
1622ea5a7a82SMoore, Eric 	/* reset this flag so SIGIO can restart */
1623ea5a7a82SMoore, Eric 	ioc->aen_event_read_flag=0;
1624ea5a7a82SMoore, Eric 
16251da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
16261da177e4SLinus Torvalds 	 */
16271da177e4SLinus Torvalds 	numBytes = max * sizeof(MPT_IOCTL_EVENTS);
16281da177e4SLinus Torvalds 	if (copy_to_user(uarg->eventData, ioc->events, numBytes)) {
162929dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventreport - "
16301da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_eventreport struct @ %p\n",
163129dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, ioc->events);
16321da177e4SLinus Torvalds 		return -EFAULT;
16331da177e4SLinus Torvalds 	}
16341da177e4SLinus Torvalds 
16351da177e4SLinus Torvalds 	return 0;
16361da177e4SLinus Torvalds }
16371da177e4SLinus Torvalds 
16381da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
16391da177e4SLinus Torvalds static int
mptctl_replace_fw(MPT_ADAPTER * ioc,unsigned long arg)164028d76df1SDan Carpenter mptctl_replace_fw (MPT_ADAPTER *ioc, unsigned long arg)
16411da177e4SLinus Torvalds {
16421da177e4SLinus Torvalds 	struct mpt_ioctl_replace_fw __user *uarg = (void __user *) arg;
16431da177e4SLinus Torvalds 	struct mpt_ioctl_replace_fw	 karg;
16441da177e4SLinus Torvalds 	int			 newFwSize;
16451da177e4SLinus Torvalds 
16461da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
164729dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_replace_fw - "
16481da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
16491da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
16501da177e4SLinus Torvalds 		return -EFAULT;
16511da177e4SLinus Torvalds 	}
16521da177e4SLinus Torvalds 
165309120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n",
165409120a8cSPrakash, Sathya 	    ioc->name));
16551da177e4SLinus Torvalds 	/* If caching FW, Free the old FW image
16561da177e4SLinus Torvalds 	 */
16571da177e4SLinus Torvalds 	if (ioc->cached_fw == NULL)
16581da177e4SLinus Torvalds 		return 0;
16591da177e4SLinus Torvalds 
16601da177e4SLinus Torvalds 	mpt_free_fw_memory(ioc);
16611da177e4SLinus Torvalds 
16621da177e4SLinus Torvalds 	/* Allocate memory for the new FW image
16631da177e4SLinus Torvalds 	 */
1664f6e495a2SRasmus Villemoes 	newFwSize = ALIGN(karg.newImageSize, 4);
16651da177e4SLinus Torvalds 
16661da177e4SLinus Torvalds 	mpt_alloc_fw_memory(ioc, newFwSize);
16671da177e4SLinus Torvalds 	if (ioc->cached_fw == NULL)
16681da177e4SLinus Torvalds 		return -ENOMEM;
16691da177e4SLinus Torvalds 
16701da177e4SLinus Torvalds 	/* Copy the data from user memory to kernel space
16711da177e4SLinus Torvalds 	 */
16721da177e4SLinus Torvalds 	if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
167329dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - "
16741da177e4SLinus Torvalds 				"Unable to read in mpt_ioctl_replace_fw image "
167529dd3609SEric Moore 				"@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
16761da177e4SLinus Torvalds 		mpt_free_fw_memory(ioc);
16771da177e4SLinus Torvalds 		return -EFAULT;
16781da177e4SLinus Torvalds 	}
16791da177e4SLinus Torvalds 
16801da177e4SLinus Torvalds 	/* Update IOCFactsReply
16811da177e4SLinus Torvalds 	 */
16821da177e4SLinus Torvalds 	ioc->facts.FWImageSize = newFwSize;
16831da177e4SLinus Torvalds 	return 0;
16841da177e4SLinus Torvalds }
16851da177e4SLinus Torvalds 
16861da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
16871da177e4SLinus Torvalds /* MPT IOCTL MPTCOMMAND function.
16881da177e4SLinus Torvalds  * Cast the arg into the mpt_ioctl_mpt_command structure.
16891da177e4SLinus Torvalds  *
16901da177e4SLinus Torvalds  * Outputs:	None.
16911da177e4SLinus Torvalds  * Return:	0 if successful
1692fc1323bbSJoe Perches  *		-EBUSY  if previous command timeout and IOC reset is not complete.
16931da177e4SLinus Torvalds  *		-EFAULT if data unavailable
16941da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
16951da177e4SLinus Torvalds  *		-ETIME	if timer expires
16961da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
16971da177e4SLinus Torvalds  */
16981da177e4SLinus Torvalds static int
mptctl_mpt_command(MPT_ADAPTER * ioc,unsigned long arg)169928d76df1SDan Carpenter mptctl_mpt_command (MPT_ADAPTER *ioc, unsigned long arg)
17001da177e4SLinus Torvalds {
17011da177e4SLinus Torvalds 	struct mpt_ioctl_command __user *uarg = (void __user *) arg;
17021da177e4SLinus Torvalds 	struct mpt_ioctl_command  karg;
17031da177e4SLinus Torvalds 	int		rc;
17041da177e4SLinus Torvalds 
17051da177e4SLinus Torvalds 
17061da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
170729dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_mpt_command - "
17081da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_command struct @ %p\n",
17091da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
17101da177e4SLinus Torvalds 		return -EFAULT;
17111da177e4SLinus Torvalds 	}
17121da177e4SLinus Torvalds 
171328d76df1SDan Carpenter 	rc = mptctl_do_mpt_command (ioc, karg, &uarg->MF);
17141da177e4SLinus Torvalds 
17151da177e4SLinus Torvalds 	return rc;
17161da177e4SLinus Torvalds }
17171da177e4SLinus Torvalds 
17181da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
17191da177e4SLinus Torvalds /* Worker routine for the IOCTL MPTCOMMAND and MPTCOMMAND32 (sparc) commands.
17201da177e4SLinus Torvalds  *
17211da177e4SLinus Torvalds  * Outputs:	None.
17221da177e4SLinus Torvalds  * Return:	0 if successful
1723fc1323bbSJoe Perches  *		-EBUSY  if previous command timeout and IOC reset is not complete.
17241da177e4SLinus Torvalds  *		-EFAULT if data unavailable
17251da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
17261da177e4SLinus Torvalds  *		-ETIME	if timer expires
17271da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
17281da177e4SLinus Torvalds  *		-EPERM if SCSI I/O and target is untagged
17291da177e4SLinus Torvalds  */
17301da177e4SLinus Torvalds static int
mptctl_do_mpt_command(MPT_ADAPTER * ioc,struct mpt_ioctl_command karg,void __user * mfPtr)173128d76df1SDan Carpenter mptctl_do_mpt_command (MPT_ADAPTER *ioc, struct mpt_ioctl_command karg, void __user *mfPtr)
17321da177e4SLinus Torvalds {
17331da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf = NULL;
17341da177e4SLinus Torvalds 	MPIHeader_t	*hdr;
17351da177e4SLinus Torvalds 	char		*psge;
17361da177e4SLinus Torvalds 	struct buflist	bufIn;	/* data In buffer */
17371da177e4SLinus Torvalds 	struct buflist	bufOut; /* data Out buffer */
17381da177e4SLinus Torvalds 	dma_addr_t	dma_addr_in;
17391da177e4SLinus Torvalds 	dma_addr_t	dma_addr_out;
17401da177e4SLinus Torvalds 	int		sgSize = 0;	/* Num SG elements */
174128d76df1SDan Carpenter 	int		flagsLength;
17421da177e4SLinus Torvalds 	int		sz, rc = 0;
17431da177e4SLinus Torvalds 	int		msgContext;
17441da177e4SLinus Torvalds 	u16		req_idx;
17451da177e4SLinus Torvalds 	ulong 		timeout;
1746ea2a788dSKashyap, Desai 	unsigned long	timeleft;
1747793955f5SEric Moore 	struct scsi_device *sdev;
1748ea2a788dSKashyap, Desai 	unsigned long	 flags;
1749ea2a788dSKashyap, Desai 	u8		 function;
17501da177e4SLinus Torvalds 
1751ab371287SEric Moore 	/* bufIn and bufOut are used for user to kernel space transfers
1752ab371287SEric Moore 	 */
17531da177e4SLinus Torvalds 	bufIn.kptr = bufOut.kptr = NULL;
1754ab371287SEric Moore 	bufIn.len = bufOut.len = 0;
17551da177e4SLinus Torvalds 
1756ea2a788dSKashyap, Desai 	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
1757ea2a788dSKashyap, Desai 	if (ioc->ioc_reset_in_progress) {
1758ea2a788dSKashyap, Desai 		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
175929dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
1760ea2a788dSKashyap, Desai 			"Busy with diagnostic reset\n", __FILE__, __LINE__);
17611da177e4SLinus Torvalds 		return -EBUSY;
17621da177e4SLinus Torvalds 	}
1763ea2a788dSKashyap, Desai 	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
17641da177e4SLinus Torvalds 
1765e819cdb1SDan Carpenter 	/* Basic sanity checks to prevent underflows or integer overflows */
1766e819cdb1SDan Carpenter 	if (karg.maxReplyBytes < 0 ||
1767e819cdb1SDan Carpenter 	    karg.dataInSize < 0 ||
1768e819cdb1SDan Carpenter 	    karg.dataOutSize < 0 ||
1769e819cdb1SDan Carpenter 	    karg.dataSgeOffset < 0 ||
1770e819cdb1SDan Carpenter 	    karg.maxSenseBytes < 0 ||
1771e819cdb1SDan Carpenter 	    karg.dataSgeOffset > ioc->req_sz / 4)
1772e819cdb1SDan Carpenter 		return -EINVAL;
1773e819cdb1SDan Carpenter 
17741da177e4SLinus Torvalds 	/* Verify that the final request frame will not be too large.
17751da177e4SLinus Torvalds 	 */
17761da177e4SLinus Torvalds 	sz = karg.dataSgeOffset * 4;
17771da177e4SLinus Torvalds 	if (karg.dataInSize > 0)
177814d0f0b0SKashyap, Desai 		sz += ioc->SGE_size;
17791da177e4SLinus Torvalds 	if (karg.dataOutSize > 0)
178014d0f0b0SKashyap, Desai 		sz += ioc->SGE_size;
17811da177e4SLinus Torvalds 
17821da177e4SLinus Torvalds 	if (sz > ioc->req_sz) {
178329dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
17841da177e4SLinus Torvalds 			"Request frame too large (%d) maximum (%d)\n",
178529dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, sz, ioc->req_sz);
17861da177e4SLinus Torvalds 		return -EFAULT;
17871da177e4SLinus Torvalds 	}
17881da177e4SLinus Torvalds 
17891da177e4SLinus Torvalds 	/* Get a free request frame and save the message context.
17901da177e4SLinus Torvalds 	 */
17911da177e4SLinus Torvalds         if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
17921da177e4SLinus Torvalds                 return -EAGAIN;
17931da177e4SLinus Torvalds 
17941da177e4SLinus Torvalds 	hdr = (MPIHeader_t *) mf;
17951da177e4SLinus Torvalds 	msgContext = le32_to_cpu(hdr->MsgContext);
17961da177e4SLinus Torvalds 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
17971da177e4SLinus Torvalds 
17981da177e4SLinus Torvalds 	/* Copy the request frame
17991da177e4SLinus Torvalds 	 * Reset the saved message context.
18001da177e4SLinus Torvalds 	 * Request frame in user space
18011da177e4SLinus Torvalds 	 */
18021da177e4SLinus Torvalds 	if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) {
180329dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
18041da177e4SLinus Torvalds 			"Unable to read MF from mpt_ioctl_command struct @ %p\n",
180529dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, mfPtr);
1806ea2a788dSKashyap, Desai 		function = -1;
18071da177e4SLinus Torvalds 		rc = -EFAULT;
18081da177e4SLinus Torvalds 		goto done_free_mem;
18091da177e4SLinus Torvalds 	}
18101da177e4SLinus Torvalds 	hdr->MsgContext = cpu_to_le32(msgContext);
1811ea2a788dSKashyap, Desai 	function = hdr->Function;
18121da177e4SLinus Torvalds 
18131da177e4SLinus Torvalds 
18141da177e4SLinus Torvalds 	/* Verify that this request is allowed.
18151da177e4SLinus Torvalds 	 */
181609120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
181709120a8cSPrakash, Sathya 	    ioc->name, hdr->Function, mf));
181809120a8cSPrakash, Sathya 
1819ea2a788dSKashyap, Desai 	switch (function) {
18201da177e4SLinus Torvalds 	case MPI_FUNCTION_IOC_FACTS:
18211da177e4SLinus Torvalds 	case MPI_FUNCTION_PORT_FACTS:
18221da177e4SLinus Torvalds 		karg.dataOutSize  = karg.dataInSize = 0;
18231da177e4SLinus Torvalds 		break;
18241da177e4SLinus Torvalds 
18251da177e4SLinus Torvalds 	case MPI_FUNCTION_CONFIG:
182609120a8cSPrakash, Sathya 	{
182709120a8cSPrakash, Sathya 		Config_t *config_frame;
182809120a8cSPrakash, Sathya 		config_frame = (Config_t *)mf;
182909120a8cSPrakash, Sathya 		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\ttype=0x%02x ext_type=0x%02x "
183009120a8cSPrakash, Sathya 		    "number=0x%02x action=0x%02x\n", ioc->name,
183109120a8cSPrakash, Sathya 		    config_frame->Header.PageType,
183209120a8cSPrakash, Sathya 		    config_frame->ExtPageType,
183309120a8cSPrakash, Sathya 		    config_frame->Header.PageNumber,
183409120a8cSPrakash, Sathya 		    config_frame->Action));
183509120a8cSPrakash, Sathya 		break;
183609120a8cSPrakash, Sathya 	}
183709120a8cSPrakash, Sathya 
18381da177e4SLinus Torvalds 	case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
18391da177e4SLinus Torvalds 	case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
18401da177e4SLinus Torvalds 	case MPI_FUNCTION_FW_UPLOAD:
18411da177e4SLinus Torvalds 	case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
18421da177e4SLinus Torvalds 	case MPI_FUNCTION_FW_DOWNLOAD:
18431da177e4SLinus Torvalds 	case MPI_FUNCTION_FC_PRIMITIVE_SEND:
1844096f7a2aSMoore, Eric 	case MPI_FUNCTION_TOOLBOX:
1845096f7a2aSMoore, Eric 	case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
18461da177e4SLinus Torvalds 		break;
18471da177e4SLinus Torvalds 
18481da177e4SLinus Torvalds 	case MPI_FUNCTION_SCSI_IO_REQUEST:
18491da177e4SLinus Torvalds 		if (ioc->sh) {
18501da177e4SLinus Torvalds 			SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
18511da177e4SLinus Torvalds 			int qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
18521da177e4SLinus Torvalds 			int scsidir = 0;
18531da177e4SLinus Torvalds 			int dataSize;
1854793955f5SEric Moore 			u32 id;
18551da177e4SLinus Torvalds 
1856793955f5SEric Moore 			id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus;
1857793955f5SEric Moore 			if (pScsiReq->TargetID > id) {
185829dd3609SEric Moore 				printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
18591da177e4SLinus Torvalds 					"Target ID out of bounds. \n",
186029dd3609SEric Moore 					ioc->name, __FILE__, __LINE__);
18611da177e4SLinus Torvalds 				rc = -ENODEV;
18621da177e4SLinus Torvalds 				goto done_free_mem;
18631da177e4SLinus Torvalds 			}
18641da177e4SLinus Torvalds 
1865793955f5SEric Moore 			if (pScsiReq->Bus >= ioc->number_of_buses) {
186629dd3609SEric Moore 				printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
1867793955f5SEric Moore 					"Target Bus out of bounds. \n",
186829dd3609SEric Moore 					ioc->name, __FILE__, __LINE__);
1869793955f5SEric Moore 				rc = -ENODEV;
1870793955f5SEric Moore 				goto done_free_mem;
1871793955f5SEric Moore 			}
1872793955f5SEric Moore 
18735f07e249SMoore, Eric 			pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
187414d0f0b0SKashyap, Desai 			pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
18755f07e249SMoore, Eric 
18761da177e4SLinus Torvalds 
18771da177e4SLinus Torvalds 			/* verify that app has not requested
18781da177e4SLinus Torvalds 			 *	more sense data than driver
18791da177e4SLinus Torvalds 			 *	can provide, if so, reset this parameter
18801da177e4SLinus Torvalds 			 * set the sense buffer pointer low address
18811da177e4SLinus Torvalds 			 * update the control field to specify Q type
18821da177e4SLinus Torvalds 			 */
18831da177e4SLinus Torvalds 			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
18841da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
18851da177e4SLinus Torvalds 			else
18861da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = karg.maxSenseBytes;
18871da177e4SLinus Torvalds 
18881da177e4SLinus Torvalds 			pScsiReq->SenseBufferLowAddr =
18891da177e4SLinus Torvalds 				cpu_to_le32(ioc->sense_buf_low_dma
18901da177e4SLinus Torvalds 				   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
18911da177e4SLinus Torvalds 
1892793955f5SEric Moore 			shost_for_each_device(sdev, ioc->sh) {
1893793955f5SEric Moore 				struct scsi_target *starget = scsi_target(sdev);
1894793955f5SEric Moore 				VirtTarget *vtarget = starget->hostdata;
18951da177e4SLinus Torvalds 
189608f5c5c2SKashyap, Desai 				if (vtarget == NULL)
189708f5c5c2SKashyap, Desai 					continue;
189808f5c5c2SKashyap, Desai 
1899793955f5SEric Moore 				if ((pScsiReq->TargetID == vtarget->id) &&
1900793955f5SEric Moore 				    (pScsiReq->Bus == vtarget->channel) &&
1901793955f5SEric Moore 				    (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
19021da177e4SLinus Torvalds 					qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
1903793955f5SEric Moore 			}
19041da177e4SLinus Torvalds 
19051da177e4SLinus Torvalds 			/* Have the IOCTL driver set the direction based
19061da177e4SLinus Torvalds 			 * on the dataOutSize (ordering issue with Sparc).
19071da177e4SLinus Torvalds 			 */
19081da177e4SLinus Torvalds 			if (karg.dataOutSize > 0) {
19091da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_WRITE;
19101da177e4SLinus Torvalds 				dataSize = karg.dataOutSize;
19111da177e4SLinus Torvalds 			} else {
19121da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_READ;
19131da177e4SLinus Torvalds 				dataSize = karg.dataInSize;
19141da177e4SLinus Torvalds 			}
19151da177e4SLinus Torvalds 
19161da177e4SLinus Torvalds 			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
19171da177e4SLinus Torvalds 			pScsiReq->DataLength = cpu_to_le32(dataSize);
19181da177e4SLinus Torvalds 
19191da177e4SLinus Torvalds 
19201da177e4SLinus Torvalds 		} else {
192129dd3609SEric Moore 			printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
19221da177e4SLinus Torvalds 				"SCSI driver is not loaded. \n",
192329dd3609SEric Moore 				ioc->name, __FILE__, __LINE__);
19241da177e4SLinus Torvalds 			rc = -EFAULT;
19251da177e4SLinus Torvalds 			goto done_free_mem;
19261da177e4SLinus Torvalds 		}
19271da177e4SLinus Torvalds 		break;
19281da177e4SLinus Torvalds 
1929096f7a2aSMoore, Eric 	case MPI_FUNCTION_SMP_PASSTHROUGH:
1930096f7a2aSMoore, Eric 		/* Check mf->PassthruFlags to determine if
1931096f7a2aSMoore, Eric 		 * transfer is ImmediateMode or not.
1932096f7a2aSMoore, Eric 		 * Immediate mode returns data in the ReplyFrame.
1933096f7a2aSMoore, Eric 		 * Else, we are sending request and response data
1934096f7a2aSMoore, Eric 		 * in two SGLs at the end of the mf.
1935096f7a2aSMoore, Eric 		 */
1936096f7a2aSMoore, Eric 		break;
1937096f7a2aSMoore, Eric 
1938096f7a2aSMoore, Eric 	case MPI_FUNCTION_SATA_PASSTHROUGH:
1939096f7a2aSMoore, Eric 		if (!ioc->sh) {
194029dd3609SEric Moore 			printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
1941096f7a2aSMoore, Eric 				"SCSI driver is not loaded. \n",
194229dd3609SEric Moore 				ioc->name, __FILE__, __LINE__);
1943096f7a2aSMoore, Eric 			rc = -EFAULT;
1944096f7a2aSMoore, Eric 			goto done_free_mem;
1945096f7a2aSMoore, Eric 		}
1946096f7a2aSMoore, Eric 		break;
1947096f7a2aSMoore, Eric 
19481da177e4SLinus Torvalds 	case MPI_FUNCTION_RAID_ACTION:
19491da177e4SLinus Torvalds 		/* Just add a SGE
19501da177e4SLinus Torvalds 		 */
19511da177e4SLinus Torvalds 		break;
19521da177e4SLinus Torvalds 
19531da177e4SLinus Torvalds 	case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
19541da177e4SLinus Torvalds 		if (ioc->sh) {
19551da177e4SLinus Torvalds 			SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
19561da177e4SLinus Torvalds 			int qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
19571da177e4SLinus Torvalds 			int scsidir = MPI_SCSIIO_CONTROL_READ;
19581da177e4SLinus Torvalds 			int dataSize;
19591da177e4SLinus Torvalds 
19605f07e249SMoore, Eric 			pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
196114d0f0b0SKashyap, Desai 			pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
19625f07e249SMoore, Eric 
19631da177e4SLinus Torvalds 
19641da177e4SLinus Torvalds 			/* verify that app has not requested
19651da177e4SLinus Torvalds 			 *	more sense data than driver
19661da177e4SLinus Torvalds 			 *	can provide, if so, reset this parameter
19671da177e4SLinus Torvalds 			 * set the sense buffer pointer low address
19681da177e4SLinus Torvalds 			 * update the control field to specify Q type
19691da177e4SLinus Torvalds 			 */
19701da177e4SLinus Torvalds 			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
19711da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
19721da177e4SLinus Torvalds 			else
19731da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = karg.maxSenseBytes;
19741da177e4SLinus Torvalds 
19751da177e4SLinus Torvalds 			pScsiReq->SenseBufferLowAddr =
19761da177e4SLinus Torvalds 				cpu_to_le32(ioc->sense_buf_low_dma
19771da177e4SLinus Torvalds 				   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
19781da177e4SLinus Torvalds 
19791da177e4SLinus Torvalds 			/* All commands to physical devices are tagged
19801da177e4SLinus Torvalds 			 */
19811da177e4SLinus Torvalds 
19821da177e4SLinus Torvalds 			/* Have the IOCTL driver set the direction based
19831da177e4SLinus Torvalds 			 * on the dataOutSize (ordering issue with Sparc).
19841da177e4SLinus Torvalds 			 */
19851da177e4SLinus Torvalds 			if (karg.dataOutSize > 0) {
19861da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_WRITE;
19871da177e4SLinus Torvalds 				dataSize = karg.dataOutSize;
19881da177e4SLinus Torvalds 			} else {
19891da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_READ;
19901da177e4SLinus Torvalds 				dataSize = karg.dataInSize;
19911da177e4SLinus Torvalds 			}
19921da177e4SLinus Torvalds 
19931da177e4SLinus Torvalds 			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
19941da177e4SLinus Torvalds 			pScsiReq->DataLength = cpu_to_le32(dataSize);
19951da177e4SLinus Torvalds 
19961da177e4SLinus Torvalds 		} else {
199729dd3609SEric Moore 			printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
19981da177e4SLinus Torvalds 				"SCSI driver is not loaded. \n",
199929dd3609SEric Moore 				ioc->name, __FILE__, __LINE__);
20001da177e4SLinus Torvalds 			rc = -EFAULT;
20011da177e4SLinus Torvalds 			goto done_free_mem;
20021da177e4SLinus Torvalds 		}
20031da177e4SLinus Torvalds 		break;
20041da177e4SLinus Torvalds 
20051da177e4SLinus Torvalds 	case MPI_FUNCTION_SCSI_TASK_MGMT:
20061da177e4SLinus Torvalds 	{
2007ea2a788dSKashyap, Desai 		SCSITaskMgmt_t	*pScsiTm;
2008ea2a788dSKashyap, Desai 		pScsiTm = (SCSITaskMgmt_t *)mf;
2009ea2a788dSKashyap, Desai 		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2010ea2a788dSKashyap, Desai 			"\tTaskType=0x%x MsgFlags=0x%x "
2011ea2a788dSKashyap, Desai 			"TaskMsgContext=0x%x id=%d channel=%d\n",
2012ea2a788dSKashyap, Desai 			ioc->name, pScsiTm->TaskType, le32_to_cpu
2013ea2a788dSKashyap, Desai 			(pScsiTm->TaskMsgContext), pScsiTm->MsgFlags,
2014ea2a788dSKashyap, Desai 			pScsiTm->TargetID, pScsiTm->Bus));
20151da177e4SLinus Torvalds 		break;
2016ea2a788dSKashyap, Desai 	}
20171da177e4SLinus Torvalds 
20181da177e4SLinus Torvalds 	case MPI_FUNCTION_IOC_INIT:
20191da177e4SLinus Torvalds 		{
20201da177e4SLinus Torvalds 			IOCInit_t	*pInit = (IOCInit_t *) mf;
20211da177e4SLinus Torvalds 			u32		high_addr, sense_high;
20221da177e4SLinus Torvalds 
20231da177e4SLinus Torvalds 			/* Verify that all entries in the IOC INIT match
20241da177e4SLinus Torvalds 			 * existing setup (and in LE format).
20251da177e4SLinus Torvalds 			 */
20261da177e4SLinus Torvalds 			if (sizeof(dma_addr_t) == sizeof(u64)) {
20271da177e4SLinus Torvalds 				high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32));
20281da177e4SLinus Torvalds 				sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
20291da177e4SLinus Torvalds 			} else {
20301da177e4SLinus Torvalds 				high_addr = 0;
20311da177e4SLinus Torvalds 				sense_high= 0;
20321da177e4SLinus Torvalds 			}
20331da177e4SLinus Torvalds 
20341da177e4SLinus Torvalds 			if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) ||
20351da177e4SLinus Torvalds 				(pInit->MaxBuses != ioc->facts.MaxBuses) ||
20361da177e4SLinus Torvalds 				(pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
20371da177e4SLinus Torvalds 				(pInit->HostMfaHighAddr != high_addr) ||
20381da177e4SLinus Torvalds 				(pInit->SenseBufferHighAddr != sense_high)) {
203929dd3609SEric Moore 				printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
20401da177e4SLinus Torvalds 					"IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n",
204129dd3609SEric Moore 					ioc->name, __FILE__, __LINE__);
20421da177e4SLinus Torvalds 				rc = -EFAULT;
20431da177e4SLinus Torvalds 				goto done_free_mem;
20441da177e4SLinus Torvalds 			}
20451da177e4SLinus Torvalds 		}
20461da177e4SLinus Torvalds 		break;
20471da177e4SLinus Torvalds 	default:
20481da177e4SLinus Torvalds 		/*
20491da177e4SLinus Torvalds 		 * MPI_FUNCTION_PORT_ENABLE
20501da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_CMD_BUFFER_POST
20511da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_ASSIST
20521da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_STATUS_SEND
20531da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_MODE_ABORT
20541da177e4SLinus Torvalds 		 * MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET
20551da177e4SLinus Torvalds 		 * MPI_FUNCTION_IO_UNIT_RESET
20561da177e4SLinus Torvalds 		 * MPI_FUNCTION_HANDSHAKE
20571da177e4SLinus Torvalds 		 * MPI_FUNCTION_REPLY_FRAME_REMOVAL
20581da177e4SLinus Torvalds 		 * MPI_FUNCTION_EVENT_NOTIFICATION
20591da177e4SLinus Torvalds 		 *  (driver handles event notification)
20601da177e4SLinus Torvalds 		 * MPI_FUNCTION_EVENT_ACK
20611da177e4SLinus Torvalds 		 */
20621da177e4SLinus Torvalds 
20631da177e4SLinus Torvalds 		/*  What to do with these???  CHECK ME!!!
20641da177e4SLinus Torvalds 			MPI_FUNCTION_FC_LINK_SRVC_BUF_POST
20651da177e4SLinus Torvalds 			MPI_FUNCTION_FC_LINK_SRVC_RSP
20661da177e4SLinus Torvalds 			MPI_FUNCTION_FC_ABORT
20671da177e4SLinus Torvalds 			MPI_FUNCTION_LAN_SEND
20681da177e4SLinus Torvalds 			MPI_FUNCTION_LAN_RECEIVE
20691da177e4SLinus Torvalds 		 	MPI_FUNCTION_LAN_RESET
20701da177e4SLinus Torvalds 		*/
20711da177e4SLinus Torvalds 
207229dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
20731da177e4SLinus Torvalds 			"Illegal request (function 0x%x) \n",
207429dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, hdr->Function);
20751da177e4SLinus Torvalds 		rc = -EFAULT;
20761da177e4SLinus Torvalds 		goto done_free_mem;
20771da177e4SLinus Torvalds 	}
20781da177e4SLinus Torvalds 
20791da177e4SLinus Torvalds 	/* Add the SGL ( at most one data in SGE and one data out SGE )
20801da177e4SLinus Torvalds 	 * In the case of two SGE's - the data out (write) will always
20811da177e4SLinus Torvalds 	 * preceede the data in (read) SGE. psgList is used to free the
20821da177e4SLinus Torvalds 	 * allocated memory.
20831da177e4SLinus Torvalds 	 */
20841da177e4SLinus Torvalds 	psge = (char *) (((int *) mf) + karg.dataSgeOffset);
20851da177e4SLinus Torvalds 	flagsLength = 0;
20861da177e4SLinus Torvalds 
20871da177e4SLinus Torvalds 	if (karg.dataOutSize > 0)
20881da177e4SLinus Torvalds 		sgSize ++;
20891da177e4SLinus Torvalds 
20901da177e4SLinus Torvalds 	if (karg.dataInSize > 0)
20911da177e4SLinus Torvalds 		sgSize ++;
20921da177e4SLinus Torvalds 
20931da177e4SLinus Torvalds 	if (sgSize > 0) {
20941da177e4SLinus Torvalds 
20951da177e4SLinus Torvalds 		/* Set up the dataOut memory allocation */
20961da177e4SLinus Torvalds 		if (karg.dataOutSize > 0) {
20971da177e4SLinus Torvalds 			if (karg.dataInSize > 0) {
20981da177e4SLinus Torvalds 				flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
20991da177e4SLinus Torvalds 						MPI_SGE_FLAGS_END_OF_BUFFER |
210014d0f0b0SKashyap, Desai 						MPI_SGE_FLAGS_DIRECTION)
21011da177e4SLinus Torvalds 						<< MPI_SGE_FLAGS_SHIFT;
21021da177e4SLinus Torvalds 			} else {
21031da177e4SLinus Torvalds 				flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
21041da177e4SLinus Torvalds 			}
21051da177e4SLinus Torvalds 			flagsLength |= karg.dataOutSize;
21061da177e4SLinus Torvalds 			bufOut.len = karg.dataOutSize;
2107706dc3b9SChristophe JAILLET 			bufOut.kptr = dma_alloc_coherent(&ioc->pcidev->dev,
2108706dc3b9SChristophe JAILLET 							 bufOut.len,
2109706dc3b9SChristophe JAILLET 							 &dma_addr_out, GFP_KERNEL);
21101da177e4SLinus Torvalds 
21111da177e4SLinus Torvalds 			if (bufOut.kptr == NULL) {
21121da177e4SLinus Torvalds 				rc = -ENOMEM;
21131da177e4SLinus Torvalds 				goto done_free_mem;
21141da177e4SLinus Torvalds 			} else {
21151da177e4SLinus Torvalds 				/* Set up this SGE.
21161da177e4SLinus Torvalds 				 * Copy to MF and to sglbuf
21171da177e4SLinus Torvalds 				 */
211814d0f0b0SKashyap, Desai 				ioc->add_sge(psge, flagsLength, dma_addr_out);
211914d0f0b0SKashyap, Desai 				psge += ioc->SGE_size;
21201da177e4SLinus Torvalds 
21211da177e4SLinus Torvalds 				/* Copy user data to kernel space.
21221da177e4SLinus Torvalds 				 */
21231da177e4SLinus Torvalds 				if (copy_from_user(bufOut.kptr,
21241da177e4SLinus Torvalds 						karg.dataOutBufPtr,
21251da177e4SLinus Torvalds 						bufOut.len)) {
212629dd3609SEric Moore 					printk(MYIOC_s_ERR_FMT
21271da177e4SLinus Torvalds 						"%s@%d::mptctl_do_mpt_command - Unable "
21281da177e4SLinus Torvalds 						"to read user data "
21291da177e4SLinus Torvalds 						"struct @ %p\n",
213029dd3609SEric Moore 						ioc->name, __FILE__, __LINE__,karg.dataOutBufPtr);
21311da177e4SLinus Torvalds 					rc =  -EFAULT;
21321da177e4SLinus Torvalds 					goto done_free_mem;
21331da177e4SLinus Torvalds 				}
21341da177e4SLinus Torvalds 			}
21351da177e4SLinus Torvalds 		}
21361da177e4SLinus Torvalds 
21371da177e4SLinus Torvalds 		if (karg.dataInSize > 0) {
21381da177e4SLinus Torvalds 			flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
21391da177e4SLinus Torvalds 			flagsLength |= karg.dataInSize;
21401da177e4SLinus Torvalds 
21411da177e4SLinus Torvalds 			bufIn.len = karg.dataInSize;
2142706dc3b9SChristophe JAILLET 			bufIn.kptr = dma_alloc_coherent(&ioc->pcidev->dev,
2143706dc3b9SChristophe JAILLET 							bufIn.len,
2144706dc3b9SChristophe JAILLET 							&dma_addr_in, GFP_KERNEL);
21451da177e4SLinus Torvalds 
21461da177e4SLinus Torvalds 			if (bufIn.kptr == NULL) {
21471da177e4SLinus Torvalds 				rc = -ENOMEM;
21481da177e4SLinus Torvalds 				goto done_free_mem;
21491da177e4SLinus Torvalds 			} else {
21501da177e4SLinus Torvalds 				/* Set up this SGE
21511da177e4SLinus Torvalds 				 * Copy to MF and to sglbuf
21521da177e4SLinus Torvalds 				 */
215314d0f0b0SKashyap, Desai 				ioc->add_sge(psge, flagsLength, dma_addr_in);
21541da177e4SLinus Torvalds 			}
21551da177e4SLinus Torvalds 		}
21561da177e4SLinus Torvalds 	} else  {
21571da177e4SLinus Torvalds 		/* Add a NULL SGE
21581da177e4SLinus Torvalds 		 */
215914d0f0b0SKashyap, Desai 		ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
21601da177e4SLinus Torvalds 	}
21611da177e4SLinus Torvalds 
2162ea2a788dSKashyap, Desai 	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext);
2163ea2a788dSKashyap, Desai 	INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
21641da177e4SLinus Torvalds 	if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
21651da177e4SLinus Torvalds 
2166ea2a788dSKashyap, Desai 		mutex_lock(&ioc->taskmgmt_cmds.mutex);
2167ea2a788dSKashyap, Desai 		if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
2168ea2a788dSKashyap, Desai 			mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2169ea2a788dSKashyap, Desai 			goto done_free_mem;
2170ea2a788dSKashyap, Desai 		}
2171ea2a788dSKashyap, Desai 
217209120a8cSPrakash, Sathya 		DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
21731da177e4SLinus Torvalds 
21747a195f46SPrakash, Sathya 		if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
21757a195f46SPrakash, Sathya 		    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
21767a195f46SPrakash, Sathya 			mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf);
21777a195f46SPrakash, Sathya 		else {
21787a195f46SPrakash, Sathya 			rc =mpt_send_handshake_request(mptctl_id, ioc,
21797a195f46SPrakash, Sathya 				sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
21807a195f46SPrakash, Sathya 			if (rc != 0) {
21817a195f46SPrakash, Sathya 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
2182ea2a788dSKashyap, Desai 				    "send_handshake FAILED! (ioc %p, mf %p)\n",
21837a195f46SPrakash, Sathya 				    ioc->name, ioc, mf));
2184ea2a788dSKashyap, Desai 				mpt_clear_taskmgmt_in_progress_flag(ioc);
21851da177e4SLinus Torvalds 				rc = -ENODATA;
2186ea2a788dSKashyap, Desai 				mutex_unlock(&ioc->taskmgmt_cmds.mutex);
21871da177e4SLinus Torvalds 				goto done_free_mem;
21881da177e4SLinus Torvalds 			}
21897a195f46SPrakash, Sathya 		}
21901da177e4SLinus Torvalds 
21911da177e4SLinus Torvalds 	} else
21921da177e4SLinus Torvalds 		mpt_put_msg_frame(mptctl_id, ioc, mf);
21931da177e4SLinus Torvalds 
21941da177e4SLinus Torvalds 	/* Now wait for the command to complete */
21951da177e4SLinus Torvalds 	timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
2196ea2a788dSKashyap, Desai retry_wait:
2197ea2a788dSKashyap, Desai 	timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
21981da177e4SLinus Torvalds 				HZ*timeout);
2199ea2a788dSKashyap, Desai 	if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2200ea2a788dSKashyap, Desai 		rc = -ETIME;
2201ea2a788dSKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n",
2202ea2a788dSKashyap, Desai 		    ioc->name, __func__));
2203ea2a788dSKashyap, Desai 		if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2204ea2a788dSKashyap, Desai 			if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2205ea2a788dSKashyap, Desai 				mutex_unlock(&ioc->taskmgmt_cmds.mutex);
22061da177e4SLinus Torvalds 			goto done_free_mem;
22071da177e4SLinus Torvalds 		}
2208ea2a788dSKashyap, Desai 		if (!timeleft) {
220997009a29SKei Tokunaga 			printk(MYIOC_s_WARN_FMT
221097009a29SKei Tokunaga 			       "mpt cmd timeout, doorbell=0x%08x"
221197009a29SKei Tokunaga 			       " function=0x%x\n",
221297009a29SKei Tokunaga 			       ioc->name, mpt_GetIocState(ioc, 0), function);
2213ea2a788dSKashyap, Desai 			if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2214ea2a788dSKashyap, Desai 				mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2215ea2a788dSKashyap, Desai 			mptctl_timeout_expired(ioc, mf);
2216ea2a788dSKashyap, Desai 			mf = NULL;
2217ea2a788dSKashyap, Desai 		} else
2218ea2a788dSKashyap, Desai 			goto retry_wait;
2219ea2a788dSKashyap, Desai 		goto done_free_mem;
2220ea2a788dSKashyap, Desai 	}
2221ea2a788dSKashyap, Desai 
2222ea2a788dSKashyap, Desai 	if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2223ea2a788dSKashyap, Desai 		mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2224ea2a788dSKashyap, Desai 
22251da177e4SLinus Torvalds 
22261da177e4SLinus Torvalds 	mf = NULL;
22271da177e4SLinus Torvalds 
22281da177e4SLinus Torvalds 	/* If a valid reply frame, copy to the user.
22291da177e4SLinus Torvalds 	 * Offset 2: reply length in U32's
22301da177e4SLinus Torvalds 	 */
2231ea2a788dSKashyap, Desai 	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
22321da177e4SLinus Torvalds 		if (karg.maxReplyBytes < ioc->reply_sz) {
2233ea2a788dSKashyap, Desai 			sz = min(karg.maxReplyBytes,
2234ea2a788dSKashyap, Desai 				4*ioc->ioctl_cmds.reply[2]);
22351da177e4SLinus Torvalds 		} else {
2236ea2a788dSKashyap, Desai 			 sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]);
22371da177e4SLinus Torvalds 		}
22381da177e4SLinus Torvalds 		if (sz > 0) {
22391da177e4SLinus Torvalds 			if (copy_to_user(karg.replyFrameBufPtr,
2240ea2a788dSKashyap, Desai 				 ioc->ioctl_cmds.reply, sz)){
224129dd3609SEric Moore 				 printk(MYIOC_s_ERR_FMT
22421da177e4SLinus Torvalds 				     "%s@%d::mptctl_do_mpt_command - "
22431da177e4SLinus Torvalds 				 "Unable to write out reply frame %p\n",
224429dd3609SEric Moore 				 ioc->name, __FILE__, __LINE__, karg.replyFrameBufPtr);
22451da177e4SLinus Torvalds 				 rc =  -ENODATA;
22461da177e4SLinus Torvalds 				 goto done_free_mem;
22471da177e4SLinus Torvalds 			}
22481da177e4SLinus Torvalds 		}
22491da177e4SLinus Torvalds 	}
22501da177e4SLinus Torvalds 
22511da177e4SLinus Torvalds 	/* If valid sense data, copy to user.
22521da177e4SLinus Torvalds 	 */
2253ea2a788dSKashyap, Desai 	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) {
22541da177e4SLinus Torvalds 		sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
22551da177e4SLinus Torvalds 		if (sz > 0) {
2256ea2a788dSKashyap, Desai 			if (copy_to_user(karg.senseDataPtr,
2257ea2a788dSKashyap, Desai 				ioc->ioctl_cmds.sense, sz)) {
225829dd3609SEric Moore 				printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
22591da177e4SLinus Torvalds 				"Unable to write sense data to user %p\n",
226029dd3609SEric Moore 				ioc->name, __FILE__, __LINE__,
22611da177e4SLinus Torvalds 				karg.senseDataPtr);
22621da177e4SLinus Torvalds 				rc =  -ENODATA;
22631da177e4SLinus Torvalds 				goto done_free_mem;
22641da177e4SLinus Torvalds 			}
22651da177e4SLinus Torvalds 		}
22661da177e4SLinus Torvalds 	}
22671da177e4SLinus Torvalds 
22681da177e4SLinus Torvalds 	/* If the overall status is _GOOD and data in, copy data
22691da177e4SLinus Torvalds 	 * to user.
22701da177e4SLinus Torvalds 	 */
2271ea2a788dSKashyap, Desai 	if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) &&
22721da177e4SLinus Torvalds 				(karg.dataInSize > 0) && (bufIn.kptr)) {
22731da177e4SLinus Torvalds 
22741da177e4SLinus Torvalds 		if (copy_to_user(karg.dataInBufPtr,
22751da177e4SLinus Torvalds 				 bufIn.kptr, karg.dataInSize)) {
227629dd3609SEric Moore 			printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
22771da177e4SLinus Torvalds 				"Unable to write data to user %p\n",
227829dd3609SEric Moore 				ioc->name, __FILE__, __LINE__,
22791da177e4SLinus Torvalds 				karg.dataInBufPtr);
22801da177e4SLinus Torvalds 			rc =  -ENODATA;
22811da177e4SLinus Torvalds 		}
22821da177e4SLinus Torvalds 	}
22831da177e4SLinus Torvalds 
22841da177e4SLinus Torvalds done_free_mem:
22851da177e4SLinus Torvalds 
2286ea2a788dSKashyap, Desai 	CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
2287ea2a788dSKashyap, Desai 	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
22881da177e4SLinus Torvalds 
22891da177e4SLinus Torvalds 	/* Free the allocated memory.
22901da177e4SLinus Torvalds 	 */
22911da177e4SLinus Torvalds 	if (bufOut.kptr != NULL) {
2292b114dda6SChristophe JAILLET 		dma_free_coherent(&ioc->pcidev->dev, bufOut.len,
2293b114dda6SChristophe JAILLET 				  (void *)bufOut.kptr, dma_addr_out);
22941da177e4SLinus Torvalds 	}
22951da177e4SLinus Torvalds 
22961da177e4SLinus Torvalds 	if (bufIn.kptr != NULL) {
2297b114dda6SChristophe JAILLET 		dma_free_coherent(&ioc->pcidev->dev, bufIn.len,
2298b114dda6SChristophe JAILLET 				  (void *)bufIn.kptr, dma_addr_in);
22991da177e4SLinus Torvalds 	}
23001da177e4SLinus Torvalds 
23011da177e4SLinus Torvalds 	/* mf is null if command issued successfully
230225985edcSLucas De Marchi 	 * otherwise, failure occurred after mf acquired.
23031da177e4SLinus Torvalds 	 */
23041da177e4SLinus Torvalds 	if (mf)
23051da177e4SLinus Torvalds 		mpt_free_msg_frame(ioc, mf);
23061da177e4SLinus Torvalds 
23071da177e4SLinus Torvalds 	return rc;
23081da177e4SLinus Torvalds }
23091da177e4SLinus Torvalds 
23101da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2311ba856d32SEric Moore /* Prototype Routine for the HOST INFO command.
23121da177e4SLinus Torvalds  *
23131da177e4SLinus Torvalds  * Outputs:	None.
23141da177e4SLinus Torvalds  * Return:	0 if successful
23151da177e4SLinus Torvalds  *		-EFAULT if data unavailable
2316fc1323bbSJoe Perches  *		-EBUSY  if previous command timeout and IOC reset is not complete.
23171da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
23181da177e4SLinus Torvalds  *		-ETIME	if timer expires
23191da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
23201da177e4SLinus Torvalds  */
23211da177e4SLinus Torvalds static int
mptctl_hp_hostinfo(MPT_ADAPTER * ioc,unsigned long arg,unsigned int data_size)232228d76df1SDan Carpenter mptctl_hp_hostinfo(MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size)
23231da177e4SLinus Torvalds {
23241da177e4SLinus Torvalds 	hp_host_info_t	__user *uarg = (void __user *) arg;
23251da177e4SLinus Torvalds 	struct pci_dev		*pdev;
2326592f9c2fSMoore, Eric 	char                    *pbuf=NULL;
23271da177e4SLinus Torvalds 	dma_addr_t		buf_dma;
23281da177e4SLinus Torvalds 	hp_host_info_t		karg;
23291da177e4SLinus Torvalds 	CONFIGPARMS		cfg;
23301da177e4SLinus Torvalds 	ConfigPageHeader_t	hdr;
23311da177e4SLinus Torvalds 	int			rc, cim_rev;
2332592f9c2fSMoore, Eric 	ToolboxIstwiReadWriteRequest_t	*IstwiRWRequest;
2333592f9c2fSMoore, Eric 	MPT_FRAME_HDR		*mf = NULL;
2334ea2a788dSKashyap, Desai 	unsigned long		timeleft;
233573d02c20STomas Henzl 	u32			msgcontext;
23361da177e4SLinus Torvalds 
23371da177e4SLinus Torvalds 	/* Reset long to int. Should affect IA64 and SPARC only
23381da177e4SLinus Torvalds 	 */
23391da177e4SLinus Torvalds 	if (data_size == sizeof(hp_host_info_t))
23401da177e4SLinus Torvalds 		cim_rev = 1;
23411da177e4SLinus Torvalds 	else if (data_size == sizeof(hp_host_info_rev0_t))
23421da177e4SLinus Torvalds 		cim_rev = 0;	/* obsolete */
23431da177e4SLinus Torvalds 	else
23441da177e4SLinus Torvalds 		return -EFAULT;
23451da177e4SLinus Torvalds 
23461da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
234729dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_host_info - "
23481da177e4SLinus Torvalds 			"Unable to read in hp_host_info struct @ %p\n",
23491da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
23501da177e4SLinus Torvalds 		return -EFAULT;
23511da177e4SLinus Torvalds 	}
23521da177e4SLinus Torvalds 
235309120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
235409120a8cSPrakash, Sathya 	    ioc->name));
23551da177e4SLinus Torvalds 
23561da177e4SLinus Torvalds 	/* Fill in the data and return the structure to the calling
23571da177e4SLinus Torvalds 	 * program
23581da177e4SLinus Torvalds 	 */
23591da177e4SLinus Torvalds 	pdev = (struct pci_dev *) ioc->pcidev;
23601da177e4SLinus Torvalds 
23611da177e4SLinus Torvalds 	karg.vendor = pdev->vendor;
23621da177e4SLinus Torvalds 	karg.device = pdev->device;
23631da177e4SLinus Torvalds 	karg.subsystem_id = pdev->subsystem_device;
23641da177e4SLinus Torvalds 	karg.subsystem_vendor = pdev->subsystem_vendor;
23651da177e4SLinus Torvalds 	karg.devfn = pdev->devfn;
23661da177e4SLinus Torvalds 	karg.bus = pdev->bus->number;
23671da177e4SLinus Torvalds 
23681da177e4SLinus Torvalds 	/* Save the SCSI host no. if
23691da177e4SLinus Torvalds 	 * SCSI driver loaded
23701da177e4SLinus Torvalds 	 */
23711da177e4SLinus Torvalds 	if (ioc->sh != NULL)
23721da177e4SLinus Torvalds 		karg.host_no = ioc->sh->host_no;
23731da177e4SLinus Torvalds 	else
23741da177e4SLinus Torvalds 		karg.host_no =  -1;
23751da177e4SLinus Torvalds 
2376332b4b2aSAndy Shevchenko 	/* Reformat the fw_version into a string */
2377332b4b2aSAndy Shevchenko 	snprintf(karg.fw_version, sizeof(karg.fw_version),
2378332b4b2aSAndy Shevchenko 		 "%.2hhu.%.2hhu.%.2hhu.%.2hhu",
2379332b4b2aSAndy Shevchenko 		 ioc->facts.FWVersion.Struct.Major,
2380332b4b2aSAndy Shevchenko 		 ioc->facts.FWVersion.Struct.Minor,
2381332b4b2aSAndy Shevchenko 		 ioc->facts.FWVersion.Struct.Unit,
2382332b4b2aSAndy Shevchenko 		 ioc->facts.FWVersion.Struct.Dev);
23831da177e4SLinus Torvalds 
23841da177e4SLinus Torvalds 	/* Issue a config request to get the device serial number
23851da177e4SLinus Torvalds 	 */
23861da177e4SLinus Torvalds 	hdr.PageVersion = 0;
23871da177e4SLinus Torvalds 	hdr.PageLength = 0;
23881da177e4SLinus Torvalds 	hdr.PageNumber = 0;
23891da177e4SLinus Torvalds 	hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
239069218ee5SChristoph Hellwig 	cfg.cfghdr.hdr = &hdr;
23911da177e4SLinus Torvalds 	cfg.physAddr = -1;
23921da177e4SLinus Torvalds 	cfg.pageAddr = 0;
23931da177e4SLinus Torvalds 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
23941da177e4SLinus Torvalds 	cfg.dir = 0;	/* read */
23951da177e4SLinus Torvalds 	cfg.timeout = 10;
23961da177e4SLinus Torvalds 
23971da177e4SLinus Torvalds 	strncpy(karg.serial_number, " ", 24);
23981da177e4SLinus Torvalds 	if (mpt_config(ioc, &cfg) == 0) {
239969218ee5SChristoph Hellwig 		if (cfg.cfghdr.hdr->PageLength > 0) {
24001da177e4SLinus Torvalds 			/* Issue the second config page request */
24011da177e4SLinus Torvalds 			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
24021da177e4SLinus Torvalds 
2403706dc3b9SChristophe JAILLET 			pbuf = dma_alloc_coherent(&ioc->pcidev->dev,
2404706dc3b9SChristophe JAILLET 						  hdr.PageLength * 4,
2405706dc3b9SChristophe JAILLET 						  &buf_dma, GFP_KERNEL);
24061da177e4SLinus Torvalds 			if (pbuf) {
24071da177e4SLinus Torvalds 				cfg.physAddr = buf_dma;
24081da177e4SLinus Torvalds 				if (mpt_config(ioc, &cfg) == 0) {
24091da177e4SLinus Torvalds 					ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
24101da177e4SLinus Torvalds 					if (strlen(pdata->BoardTracerNumber) > 1) {
2411*dbe37c71SAzeem Shaikh 						strscpy(karg.serial_number,
24127bd1d615SDominique Martinet 							pdata->BoardTracerNumber, 24);
24131da177e4SLinus Torvalds 					}
24141da177e4SLinus Torvalds 				}
2415b114dda6SChristophe JAILLET 				dma_free_coherent(&ioc->pcidev->dev,
2416b114dda6SChristophe JAILLET 						  hdr.PageLength * 4, pbuf,
2417b114dda6SChristophe JAILLET 						  buf_dma);
24181da177e4SLinus Torvalds 				pbuf = NULL;
24191da177e4SLinus Torvalds 			}
24201da177e4SLinus Torvalds 		}
24211da177e4SLinus Torvalds 	}
24221da177e4SLinus Torvalds 	rc = mpt_GetIocState(ioc, 1);
24231da177e4SLinus Torvalds 	switch (rc) {
24241da177e4SLinus Torvalds 	case MPI_IOC_STATE_OPERATIONAL:
24251da177e4SLinus Torvalds 		karg.ioc_status =  HP_STATUS_OK;
24261da177e4SLinus Torvalds 		break;
24271da177e4SLinus Torvalds 
24281da177e4SLinus Torvalds 	case MPI_IOC_STATE_FAULT:
24291da177e4SLinus Torvalds 		karg.ioc_status =  HP_STATUS_FAILED;
24301da177e4SLinus Torvalds 		break;
24311da177e4SLinus Torvalds 
24321da177e4SLinus Torvalds 	case MPI_IOC_STATE_RESET:
24331da177e4SLinus Torvalds 	case MPI_IOC_STATE_READY:
24341da177e4SLinus Torvalds 	default:
24351da177e4SLinus Torvalds 		karg.ioc_status =  HP_STATUS_OTHER;
24361da177e4SLinus Torvalds 		break;
24371da177e4SLinus Torvalds 	}
24381da177e4SLinus Torvalds 
24391da177e4SLinus Torvalds 	karg.base_io_addr = pci_resource_start(pdev, 0);
24401da177e4SLinus Torvalds 
24419cc1cfbcSMoore, Eric 	if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
24421da177e4SLinus Torvalds 		karg.bus_phys_width = HP_BUS_WIDTH_UNK;
24431da177e4SLinus Torvalds 	else
24441da177e4SLinus Torvalds 		karg.bus_phys_width = HP_BUS_WIDTH_16;
24451da177e4SLinus Torvalds 
24461da177e4SLinus Torvalds 	karg.hard_resets = 0;
24471da177e4SLinus Torvalds 	karg.soft_resets = 0;
24481da177e4SLinus Torvalds 	karg.timeouts = 0;
24491da177e4SLinus Torvalds 	if (ioc->sh != NULL) {
2450e7eae9f6SEric Moore 		MPT_SCSI_HOST *hd =  shost_priv(ioc->sh);
24511da177e4SLinus Torvalds 
24521da177e4SLinus Torvalds 		if (hd && (cim_rev == 1)) {
24532f187862SKashyap, Desai 			karg.hard_resets = ioc->hard_resets;
24542f187862SKashyap, Desai 			karg.soft_resets = ioc->soft_resets;
24552f187862SKashyap, Desai 			karg.timeouts = ioc->timeouts;
24561da177e4SLinus Torvalds 		}
24571da177e4SLinus Torvalds 	}
24581da177e4SLinus Torvalds 
2459592f9c2fSMoore, Eric 	/*
2460592f9c2fSMoore, Eric 	 * Gather ISTWI(Industry Standard Two Wire Interface) Data
2461592f9c2fSMoore, Eric 	 */
2462592f9c2fSMoore, Eric 	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
2463ea2a788dSKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
2464ea2a788dSKashyap, Desai 			"%s, no msg frames!!\n", ioc->name, __func__));
2465592f9c2fSMoore, Eric 		goto out;
2466592f9c2fSMoore, Eric 	}
2467592f9c2fSMoore, Eric 
2468592f9c2fSMoore, Eric 	IstwiRWRequest = (ToolboxIstwiReadWriteRequest_t *)mf;
246973d02c20STomas Henzl 	msgcontext = IstwiRWRequest->MsgContext;
2470592f9c2fSMoore, Eric 	memset(IstwiRWRequest,0,sizeof(ToolboxIstwiReadWriteRequest_t));
247173d02c20STomas Henzl 	IstwiRWRequest->MsgContext = msgcontext;
2472592f9c2fSMoore, Eric 	IstwiRWRequest->Function = MPI_FUNCTION_TOOLBOX;
2473592f9c2fSMoore, Eric 	IstwiRWRequest->Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL;
2474592f9c2fSMoore, Eric 	IstwiRWRequest->Flags = MPI_TB_ISTWI_FLAGS_READ;
2475592f9c2fSMoore, Eric 	IstwiRWRequest->NumAddressBytes = 0x01;
2476592f9c2fSMoore, Eric 	IstwiRWRequest->DataLength = cpu_to_le16(0x04);
2477592f9c2fSMoore, Eric 	if (pdev->devfn & 1)
2478592f9c2fSMoore, Eric 		IstwiRWRequest->DeviceAddr = 0xB2;
2479592f9c2fSMoore, Eric 	else
2480592f9c2fSMoore, Eric 		IstwiRWRequest->DeviceAddr = 0xB0;
2481592f9c2fSMoore, Eric 
2482706dc3b9SChristophe JAILLET 	pbuf = dma_alloc_coherent(&ioc->pcidev->dev, 4, &buf_dma, GFP_KERNEL);
2483592f9c2fSMoore, Eric 	if (!pbuf)
2484592f9c2fSMoore, Eric 		goto out;
248514d0f0b0SKashyap, Desai 	ioc->add_sge((char *)&IstwiRWRequest->SGL,
2486592f9c2fSMoore, Eric 	    (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
2487592f9c2fSMoore, Eric 
2488ea2a788dSKashyap, Desai 	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
2489ea2a788dSKashyap, Desai 				IstwiRWRequest->MsgContext);
2490ea2a788dSKashyap, Desai 	INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
2491592f9c2fSMoore, Eric 	mpt_put_msg_frame(mptctl_id, ioc, mf);
2492592f9c2fSMoore, Eric 
2493ea2a788dSKashyap, Desai retry_wait:
2494ea2a788dSKashyap, Desai 	timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
2495ea2a788dSKashyap, Desai 			HZ*MPT_IOCTL_DEFAULT_TIMEOUT);
2496ea2a788dSKashyap, Desai 	if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2497ea2a788dSKashyap, Desai 		printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __func__);
2498ea2a788dSKashyap, Desai 		if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2499592f9c2fSMoore, Eric 			mpt_free_msg_frame(ioc, mf);
2500ea2a788dSKashyap, Desai 			goto out;
2501ea2a788dSKashyap, Desai 		}
250297009a29SKei Tokunaga 		if (!timeleft) {
250397009a29SKei Tokunaga 			printk(MYIOC_s_WARN_FMT
250497009a29SKei Tokunaga 			       "HOST INFO command timeout, doorbell=0x%08x\n",
250597009a29SKei Tokunaga 			       ioc->name, mpt_GetIocState(ioc, 0));
2506ea2a788dSKashyap, Desai 			mptctl_timeout_expired(ioc, mf);
250797009a29SKei Tokunaga 		} else
2508ea2a788dSKashyap, Desai 			goto retry_wait;
2509592f9c2fSMoore, Eric 		goto out;
2510592f9c2fSMoore, Eric 	}
2511592f9c2fSMoore, Eric 
2512592f9c2fSMoore, Eric 	/*
2513592f9c2fSMoore, Eric 	 *ISTWI Data Definition
2514592f9c2fSMoore, Eric 	 * pbuf[0] = FW_VERSION = 0x4
2515592f9c2fSMoore, Eric 	 * pbuf[1] = Bay Count = 6 or 4 or 2, depending on
2516592f9c2fSMoore, Eric 	 *  the config, you should be seeing one out of these three values
2517592f9c2fSMoore, Eric 	 * pbuf[2] = Drive Installed Map = bit pattern depend on which
2518592f9c2fSMoore, Eric 	 *   bays have drives in them
2519592f9c2fSMoore, Eric 	 * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3)
2520592f9c2fSMoore, Eric 	 */
2521ea2a788dSKashyap, Desai 	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)
25221da177e4SLinus Torvalds 		karg.rsvd = *(u32 *)pbuf;
2523592f9c2fSMoore, Eric 
2524592f9c2fSMoore, Eric  out:
2525ea2a788dSKashyap, Desai 	CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
2526ea2a788dSKashyap, Desai 	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
2527ea2a788dSKashyap, Desai 
2528592f9c2fSMoore, Eric 	if (pbuf)
2529b114dda6SChristophe JAILLET 		dma_free_coherent(&ioc->pcidev->dev, 4, pbuf, buf_dma);
25301da177e4SLinus Torvalds 
25311da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
25321da177e4SLinus Torvalds 	 */
25331da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) {
253429dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hpgethostinfo - "
25351da177e4SLinus Torvalds 			"Unable to write out hp_host_info @ %p\n",
253629dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, uarg);
25371da177e4SLinus Torvalds 		return -EFAULT;
25381da177e4SLinus Torvalds 	}
25391da177e4SLinus Torvalds 
25401da177e4SLinus Torvalds 	return 0;
25411da177e4SLinus Torvalds 
25421da177e4SLinus Torvalds }
25431da177e4SLinus Torvalds 
25441da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2545ba856d32SEric Moore /* Prototype Routine for the TARGET INFO command.
25461da177e4SLinus Torvalds  *
25471da177e4SLinus Torvalds  * Outputs:	None.
25481da177e4SLinus Torvalds  * Return:	0 if successful
25491da177e4SLinus Torvalds  *		-EFAULT if data unavailable
2550fc1323bbSJoe Perches  *		-EBUSY  if previous command timeout and IOC reset is not complete.
25511da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
25521da177e4SLinus Torvalds  *		-ETIME	if timer expires
25531da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
25541da177e4SLinus Torvalds  */
25551da177e4SLinus Torvalds static int
mptctl_hp_targetinfo(MPT_ADAPTER * ioc,unsigned long arg)255628d76df1SDan Carpenter mptctl_hp_targetinfo(MPT_ADAPTER *ioc, unsigned long arg)
25571da177e4SLinus Torvalds {
25581da177e4SLinus Torvalds 	hp_target_info_t __user *uarg = (void __user *) arg;
25591da177e4SLinus Torvalds 	SCSIDevicePage0_t	*pg0_alloc;
25601da177e4SLinus Torvalds 	SCSIDevicePage3_t	*pg3_alloc;
25611da177e4SLinus Torvalds 	MPT_SCSI_HOST 		*hd = NULL;
25621da177e4SLinus Torvalds 	hp_target_info_t	karg;
25631da177e4SLinus Torvalds 	int			data_sz;
25641da177e4SLinus Torvalds 	dma_addr_t		page_dma;
25651da177e4SLinus Torvalds 	CONFIGPARMS	 	cfg;
25661da177e4SLinus Torvalds 	ConfigPageHeader_t	hdr;
25671da177e4SLinus Torvalds 	int			tmp, np, rc = 0;
25681da177e4SLinus Torvalds 
25691da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
257029dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_targetinfo - "
25711da177e4SLinus Torvalds 			"Unable to read in hp_host_targetinfo struct @ %p\n",
25721da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
25731da177e4SLinus Torvalds 		return -EFAULT;
25741da177e4SLinus Torvalds 	}
25751da177e4SLinus Torvalds 
2576a7043e95SDan Carpenter 	if (karg.hdr.id >= MPT_MAX_FC_DEVICES)
2577a7043e95SDan Carpenter 		return -EINVAL;
257829dd3609SEric Moore 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
257909120a8cSPrakash, Sathya 	    ioc->name));
25801da177e4SLinus Torvalds 
25811da177e4SLinus Torvalds 	/*  There is nothing to do for FCP parts.
25821da177e4SLinus Torvalds 	 */
25839cc1cfbcSMoore, Eric 	if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
25841da177e4SLinus Torvalds 		return 0;
25851da177e4SLinus Torvalds 
25861da177e4SLinus Torvalds 	if ((ioc->spi_data.sdp0length == 0) || (ioc->sh == NULL))
25871da177e4SLinus Torvalds 		return 0;
25881da177e4SLinus Torvalds 
25891da177e4SLinus Torvalds 	if (ioc->sh->host_no != karg.hdr.host)
25901da177e4SLinus Torvalds 		return -ENODEV;
25911da177e4SLinus Torvalds 
25921da177e4SLinus Torvalds        /* Get the data transfer speeds
25931da177e4SLinus Torvalds         */
25941da177e4SLinus Torvalds 	data_sz = ioc->spi_data.sdp0length * 4;
2595706dc3b9SChristophe JAILLET 	pg0_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz, &page_dma,
2596706dc3b9SChristophe JAILLET 				       GFP_KERNEL);
25971da177e4SLinus Torvalds 	if (pg0_alloc) {
25981da177e4SLinus Torvalds 		hdr.PageVersion = ioc->spi_data.sdp0version;
25991da177e4SLinus Torvalds 		hdr.PageLength = data_sz;
26001da177e4SLinus Torvalds 		hdr.PageNumber = 0;
26011da177e4SLinus Torvalds 		hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
26021da177e4SLinus Torvalds 
260369218ee5SChristoph Hellwig 		cfg.cfghdr.hdr = &hdr;
26041da177e4SLinus Torvalds 		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
26051da177e4SLinus Torvalds 		cfg.dir = 0;
26061da177e4SLinus Torvalds 		cfg.timeout = 0;
26071da177e4SLinus Torvalds 		cfg.physAddr = page_dma;
26081da177e4SLinus Torvalds 
26091da177e4SLinus Torvalds 		cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
26101da177e4SLinus Torvalds 
26111da177e4SLinus Torvalds 		if ((rc = mpt_config(ioc, &cfg)) == 0) {
26121da177e4SLinus Torvalds 			np = le32_to_cpu(pg0_alloc->NegotiatedParameters);
26131da177e4SLinus Torvalds 			karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ?
26141da177e4SLinus Torvalds 					HP_BUS_WIDTH_16 : HP_BUS_WIDTH_8;
26151da177e4SLinus Torvalds 
26161da177e4SLinus Torvalds 			if (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) {
26171da177e4SLinus Torvalds 				tmp = (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
26181da177e4SLinus Torvalds 				if (tmp < 0x09)
26191da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA320;
26201da177e4SLinus Torvalds 				else if (tmp <= 0x09)
26211da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA160;
26221da177e4SLinus Torvalds 				else if (tmp <= 0x0A)
26231da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA2;
26241da177e4SLinus Torvalds 				else if (tmp <= 0x0C)
26251da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA;
26261da177e4SLinus Torvalds 				else if (tmp <= 0x25)
26271da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_FAST;
26281da177e4SLinus Torvalds 				else
26291da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
26301da177e4SLinus Torvalds 			} else
26311da177e4SLinus Torvalds 				karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
26321da177e4SLinus Torvalds 		}
26331da177e4SLinus Torvalds 
2634b114dda6SChristophe JAILLET 		dma_free_coherent(&ioc->pcidev->dev, data_sz, (u8 *)pg0_alloc,
2635b114dda6SChristophe JAILLET 				  page_dma);
26361da177e4SLinus Torvalds 	}
26371da177e4SLinus Torvalds 
26381da177e4SLinus Torvalds 	/* Set defaults
26391da177e4SLinus Torvalds 	 */
26401da177e4SLinus Torvalds 	karg.message_rejects = -1;
26411da177e4SLinus Torvalds 	karg.phase_errors = -1;
26421da177e4SLinus Torvalds 	karg.parity_errors = -1;
26431da177e4SLinus Torvalds 	karg.select_timeouts = -1;
26441da177e4SLinus Torvalds 
26451da177e4SLinus Torvalds 	/* Get the target error parameters
26461da177e4SLinus Torvalds 	 */
26471da177e4SLinus Torvalds 	hdr.PageVersion = 0;
26481da177e4SLinus Torvalds 	hdr.PageLength = 0;
26491da177e4SLinus Torvalds 	hdr.PageNumber = 3;
26501da177e4SLinus Torvalds 	hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
26511da177e4SLinus Torvalds 
265269218ee5SChristoph Hellwig 	cfg.cfghdr.hdr = &hdr;
26531da177e4SLinus Torvalds 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
26541da177e4SLinus Torvalds 	cfg.dir = 0;
26551da177e4SLinus Torvalds 	cfg.timeout = 0;
26561da177e4SLinus Torvalds 	cfg.physAddr = -1;
265769218ee5SChristoph Hellwig 	if ((mpt_config(ioc, &cfg) == 0) && (cfg.cfghdr.hdr->PageLength > 0)) {
26581da177e4SLinus Torvalds 		/* Issue the second config page request */
26591da177e4SLinus Torvalds 		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
266069218ee5SChristoph Hellwig 		data_sz = (int) cfg.cfghdr.hdr->PageLength * 4;
2661706dc3b9SChristophe JAILLET 		pg3_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz,
2662706dc3b9SChristophe JAILLET 					       &page_dma, GFP_KERNEL);
26631da177e4SLinus Torvalds 		if (pg3_alloc) {
26641da177e4SLinus Torvalds 			cfg.physAddr = page_dma;
26651da177e4SLinus Torvalds 			cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
26661da177e4SLinus Torvalds 			if ((rc = mpt_config(ioc, &cfg)) == 0) {
26671da177e4SLinus Torvalds 				karg.message_rejects = (u32) le16_to_cpu(pg3_alloc->MsgRejectCount);
26681da177e4SLinus Torvalds 				karg.phase_errors = (u32) le16_to_cpu(pg3_alloc->PhaseErrorCount);
26691da177e4SLinus Torvalds 				karg.parity_errors = (u32) le16_to_cpu(pg3_alloc->ParityErrorCount);
26701da177e4SLinus Torvalds 			}
2671b114dda6SChristophe JAILLET 			dma_free_coherent(&ioc->pcidev->dev, data_sz,
2672b114dda6SChristophe JAILLET 					  (u8 *)pg3_alloc, page_dma);
26731da177e4SLinus Torvalds 		}
26741da177e4SLinus Torvalds 	}
2675e7eae9f6SEric Moore 	hd = shost_priv(ioc->sh);
26761da177e4SLinus Torvalds 	if (hd != NULL)
26771da177e4SLinus Torvalds 		karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
26781da177e4SLinus Torvalds 
26791da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
26801da177e4SLinus Torvalds 	 */
26811da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) {
268229dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hp_target_info - "
26831da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
268429dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, uarg);
26851da177e4SLinus Torvalds 		return -EFAULT;
26861da177e4SLinus Torvalds 	}
26871da177e4SLinus Torvalds 
26881da177e4SLinus Torvalds 	return 0;
26891da177e4SLinus Torvalds }
26901da177e4SLinus Torvalds 
26911da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26921da177e4SLinus Torvalds 
2693fa027c2aSArjan van de Ven static const struct file_operations mptctl_fops = {
26941da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
26951da177e4SLinus Torvalds 	.llseek =	no_llseek,
2696ea5a7a82SMoore, Eric 	.fasync = 	mptctl_fasync,
26971da177e4SLinus Torvalds 	.unlocked_ioctl = mptctl_ioctl,
26981da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
26991da177e4SLinus Torvalds 	.compat_ioctl = compat_mpctl_ioctl,
27001da177e4SLinus Torvalds #endif
27011da177e4SLinus Torvalds };
27021da177e4SLinus Torvalds 
27031da177e4SLinus Torvalds static struct miscdevice mptctl_miscdev = {
27041da177e4SLinus Torvalds 	MPT_MINOR,
27051da177e4SLinus Torvalds 	MYNAM,
27061da177e4SLinus Torvalds 	&mptctl_fops
27071da177e4SLinus Torvalds };
27081da177e4SLinus Torvalds 
27091da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
27101da177e4SLinus Torvalds 
27111da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
27121da177e4SLinus Torvalds 
27131da177e4SLinus Torvalds static int
compat_mptfwxfer_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)27141da177e4SLinus Torvalds compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
27151da177e4SLinus Torvalds 			unsigned long arg)
27161da177e4SLinus Torvalds {
27171da177e4SLinus Torvalds 	struct mpt_fw_xfer32 kfw32;
27181da177e4SLinus Torvalds 	struct mpt_fw_xfer kfw;
27191da177e4SLinus Torvalds 	MPT_ADAPTER *iocp = NULL;
27201da177e4SLinus Torvalds 	int iocnum, iocnumX;
27211da177e4SLinus Torvalds 	int nonblock = (filp->f_flags & O_NONBLOCK);
27221da177e4SLinus Torvalds 	int ret;
27231da177e4SLinus Torvalds 
27241da177e4SLinus Torvalds 
27251da177e4SLinus Torvalds 	if (copy_from_user(&kfw32, (char __user *)arg, sizeof(kfw32)))
27261da177e4SLinus Torvalds 		return -EFAULT;
27271da177e4SLinus Torvalds 
27281da177e4SLinus Torvalds 	/* Verify intended MPT adapter */
27291da177e4SLinus Torvalds 	iocnumX = kfw32.iocnum & 0xFF;
27301da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
27311da177e4SLinus Torvalds 	    (iocp == NULL)) {
273209120a8cSPrakash, Sathya 		printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
273309120a8cSPrakash, Sathya 			__LINE__, iocnumX);
27341da177e4SLinus Torvalds 		return -ENODEV;
27351da177e4SLinus Torvalds 	}
27361da177e4SLinus Torvalds 
27371da177e4SLinus Torvalds 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
27381da177e4SLinus Torvalds 		return ret;
27391da177e4SLinus Torvalds 
274009120a8cSPrakash, Sathya 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mptfwxfer_ioctl() called\n",
274109120a8cSPrakash, Sathya 	    iocp->name));
27421da177e4SLinus Torvalds 	kfw.iocnum = iocnum;
27431da177e4SLinus Torvalds 	kfw.fwlen = kfw32.fwlen;
27441da177e4SLinus Torvalds 	kfw.bufp = compat_ptr(kfw32.bufp);
27451da177e4SLinus Torvalds 
274628d76df1SDan Carpenter 	ret = mptctl_do_fw_download(iocp, kfw.bufp, kfw.fwlen);
27471da177e4SLinus Torvalds 
2748ea2a788dSKashyap, Desai 	mutex_unlock(&iocp->ioctl_cmds.mutex);
27491da177e4SLinus Torvalds 
27501da177e4SLinus Torvalds 	return ret;
27511da177e4SLinus Torvalds }
27521da177e4SLinus Torvalds 
27531da177e4SLinus Torvalds static int
compat_mpt_command(struct file * filp,unsigned int cmd,unsigned long arg)27541da177e4SLinus Torvalds compat_mpt_command(struct file *filp, unsigned int cmd,
27551da177e4SLinus Torvalds 			unsigned long arg)
27561da177e4SLinus Torvalds {
27571da177e4SLinus Torvalds 	struct mpt_ioctl_command32 karg32;
27581da177e4SLinus Torvalds 	struct mpt_ioctl_command32 __user *uarg = (struct mpt_ioctl_command32 __user *) arg;
27591da177e4SLinus Torvalds 	struct mpt_ioctl_command karg;
27601da177e4SLinus Torvalds 	MPT_ADAPTER *iocp = NULL;
27611da177e4SLinus Torvalds 	int iocnum, iocnumX;
27621da177e4SLinus Torvalds 	int nonblock = (filp->f_flags & O_NONBLOCK);
27631da177e4SLinus Torvalds 	int ret;
27641da177e4SLinus Torvalds 
27651da177e4SLinus Torvalds 	if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32)))
27661da177e4SLinus Torvalds 		return -EFAULT;
27671da177e4SLinus Torvalds 
27681da177e4SLinus Torvalds 	/* Verify intended MPT adapter */
27691da177e4SLinus Torvalds 	iocnumX = karg32.hdr.iocnum & 0xFF;
27701da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
27711da177e4SLinus Torvalds 	    (iocp == NULL)) {
277209120a8cSPrakash, Sathya 		printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
277309120a8cSPrakash, Sathya 			__LINE__, iocnumX);
27741da177e4SLinus Torvalds 		return -ENODEV;
27751da177e4SLinus Torvalds 	}
27761da177e4SLinus Torvalds 
27771da177e4SLinus Torvalds 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
27781da177e4SLinus Torvalds 		return ret;
27791da177e4SLinus Torvalds 
278009120a8cSPrakash, Sathya 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mpt_command() called\n",
278109120a8cSPrakash, Sathya 	    iocp->name));
27821da177e4SLinus Torvalds 	/* Copy data to karg */
27831da177e4SLinus Torvalds 	karg.hdr.iocnum = karg32.hdr.iocnum;
27841da177e4SLinus Torvalds 	karg.hdr.port = karg32.hdr.port;
27851da177e4SLinus Torvalds 	karg.timeout = karg32.timeout;
27861da177e4SLinus Torvalds 	karg.maxReplyBytes = karg32.maxReplyBytes;
27871da177e4SLinus Torvalds 
27881da177e4SLinus Torvalds 	karg.dataInSize = karg32.dataInSize;
27891da177e4SLinus Torvalds 	karg.dataOutSize = karg32.dataOutSize;
27901da177e4SLinus Torvalds 	karg.maxSenseBytes = karg32.maxSenseBytes;
27911da177e4SLinus Torvalds 	karg.dataSgeOffset = karg32.dataSgeOffset;
27921da177e4SLinus Torvalds 
27931da177e4SLinus Torvalds 	karg.replyFrameBufPtr = (char __user *)(unsigned long)karg32.replyFrameBufPtr;
27941da177e4SLinus Torvalds 	karg.dataInBufPtr = (char __user *)(unsigned long)karg32.dataInBufPtr;
27951da177e4SLinus Torvalds 	karg.dataOutBufPtr = (char __user *)(unsigned long)karg32.dataOutBufPtr;
27961da177e4SLinus Torvalds 	karg.senseDataPtr = (char __user *)(unsigned long)karg32.senseDataPtr;
27971da177e4SLinus Torvalds 
27981da177e4SLinus Torvalds 	/* Pass new structure to do_mpt_command
27991da177e4SLinus Torvalds 	 */
280028d76df1SDan Carpenter 	ret = mptctl_do_mpt_command (iocp, karg, &uarg->MF);
28011da177e4SLinus Torvalds 
2802ea2a788dSKashyap, Desai 	mutex_unlock(&iocp->ioctl_cmds.mutex);
28031da177e4SLinus Torvalds 
28041da177e4SLinus Torvalds 	return ret;
28051da177e4SLinus Torvalds }
28061da177e4SLinus Torvalds 
compat_mpctl_ioctl(struct file * f,unsigned int cmd,unsigned long arg)28071da177e4SLinus Torvalds static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
28081da177e4SLinus Torvalds {
28091da177e4SLinus Torvalds 	long ret;
2810c45d15d2SArnd Bergmann 	mutex_lock(&mpctl_mutex);
28111da177e4SLinus Torvalds 	switch (cmd) {
28121da177e4SLinus Torvalds 	case MPTIOCINFO:
28131da177e4SLinus Torvalds 	case MPTIOCINFO1:
28141da177e4SLinus Torvalds 	case MPTIOCINFO2:
28151da177e4SLinus Torvalds 	case MPTTARGETINFO:
28161da177e4SLinus Torvalds 	case MPTEVENTQUERY:
28171da177e4SLinus Torvalds 	case MPTEVENTENABLE:
28181da177e4SLinus Torvalds 	case MPTEVENTREPORT:
28191da177e4SLinus Torvalds 	case MPTHARDRESET:
28201da177e4SLinus Torvalds 	case HP_GETHOSTINFO:
28211da177e4SLinus Torvalds 	case HP_GETTARGETINFO:
28221da177e4SLinus Torvalds 	case MPTTEST:
28231da177e4SLinus Torvalds 		ret = __mptctl_ioctl(f, cmd, arg);
28241da177e4SLinus Torvalds 		break;
28251da177e4SLinus Torvalds 	case MPTCOMMAND32:
28261da177e4SLinus Torvalds 		ret = compat_mpt_command(f, cmd, arg);
28271da177e4SLinus Torvalds 		break;
28281da177e4SLinus Torvalds 	case MPTFWDOWNLOAD32:
28291da177e4SLinus Torvalds 		ret = compat_mptfwxfer_ioctl(f, cmd, arg);
28301da177e4SLinus Torvalds 		break;
28311da177e4SLinus Torvalds 	default:
28321da177e4SLinus Torvalds 		ret = -ENOIOCTLCMD;
28331da177e4SLinus Torvalds 		break;
28341da177e4SLinus Torvalds 	}
2835c45d15d2SArnd Bergmann 	mutex_unlock(&mpctl_mutex);
28361da177e4SLinus Torvalds 	return ret;
28371da177e4SLinus Torvalds }
28381da177e4SLinus Torvalds 
28391da177e4SLinus Torvalds #endif
28401da177e4SLinus Torvalds 
28411da177e4SLinus Torvalds 
28421da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
28431da177e4SLinus Torvalds /*
28441da177e4SLinus Torvalds  *	mptctl_probe - Installs ioctl devices per bus.
28451da177e4SLinus Torvalds  *	@pdev: Pointer to pci_dev structure
28461da177e4SLinus Torvalds  *
28471da177e4SLinus Torvalds  *	Returns 0 for success, non-zero for failure.
28481da177e4SLinus Torvalds  *
28491da177e4SLinus Torvalds  */
28501da177e4SLinus Torvalds 
28511da177e4SLinus Torvalds static int
mptctl_probe(struct pci_dev * pdev)2852a534ff3fSUwe Kleine-König mptctl_probe(struct pci_dev *pdev)
28531da177e4SLinus Torvalds {
28541da177e4SLinus Torvalds 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
28551da177e4SLinus Torvalds 
2856ea2a788dSKashyap, Desai 	mutex_init(&ioc->ioctl_cmds.mutex);
2857ea2a788dSKashyap, Desai 	init_completion(&ioc->ioctl_cmds.done);
28581da177e4SLinus Torvalds 	return 0;
28591da177e4SLinus Torvalds }
28601da177e4SLinus Torvalds 
28611da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
28621da177e4SLinus Torvalds /*
28631da177e4SLinus Torvalds  *	mptctl_remove - Removed ioctl devices
28641da177e4SLinus Torvalds  *	@pdev: Pointer to pci_dev structure
28651da177e4SLinus Torvalds  *
28661da177e4SLinus Torvalds  *
28671da177e4SLinus Torvalds  */
28681da177e4SLinus Torvalds static void
mptctl_remove(struct pci_dev * pdev)28691da177e4SLinus Torvalds mptctl_remove(struct pci_dev *pdev)
28701da177e4SLinus Torvalds {
28711da177e4SLinus Torvalds }
28721da177e4SLinus Torvalds 
28731da177e4SLinus Torvalds static struct mpt_pci_driver mptctl_driver = {
28741da177e4SLinus Torvalds   .probe		= mptctl_probe,
28751da177e4SLinus Torvalds   .remove		= mptctl_remove,
28761da177e4SLinus Torvalds };
28771da177e4SLinus Torvalds 
28781da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
mptctl_init(void)28791da177e4SLinus Torvalds static int __init mptctl_init(void)
28801da177e4SLinus Torvalds {
28811da177e4SLinus Torvalds 	int err;
28821da177e4SLinus Torvalds 
28831da177e4SLinus Torvalds 	show_mptmod_ver(my_NAME, my_VERSION);
28841da177e4SLinus Torvalds 
288509120a8cSPrakash, Sathya 	mpt_device_driver_register(&mptctl_driver, MPTCTL_DRIVER);
28861da177e4SLinus Torvalds 
28871da177e4SLinus Torvalds 	/* Register this device */
28881da177e4SLinus Torvalds 	err = misc_register(&mptctl_miscdev);
28891da177e4SLinus Torvalds 	if (err < 0) {
28901da177e4SLinus Torvalds 		printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
28911da177e4SLinus Torvalds 		goto out_fail;
28921da177e4SLinus Torvalds 	}
28931da177e4SLinus Torvalds 	printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
28941da177e4SLinus Torvalds 	printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
28951da177e4SLinus Torvalds 			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
28961da177e4SLinus Torvalds 
28971da177e4SLinus Torvalds 	/*
28981da177e4SLinus Torvalds 	 *  Install our handler
28991da177e4SLinus Torvalds 	 */
2900213aaca3SKashyap, Desai 	mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER,
2901213aaca3SKashyap, Desai 	    "mptctl_reply");
2902f606f571SPrakash, Sathya 	if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) {
29031da177e4SLinus Torvalds 		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
29041da177e4SLinus Torvalds 		misc_deregister(&mptctl_miscdev);
29051da177e4SLinus Torvalds 		err = -EBUSY;
29061da177e4SLinus Torvalds 		goto out_fail;
29071da177e4SLinus Torvalds 	}
29081da177e4SLinus Torvalds 
2909213aaca3SKashyap, Desai 	mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER,
2910213aaca3SKashyap, Desai 	    "mptctl_taskmgmt_reply");
291165c054f2SKei Tokunaga 	if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) {
291265c054f2SKei Tokunaga 		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
291365c054f2SKei Tokunaga 		mpt_deregister(mptctl_id);
291465c054f2SKei Tokunaga 		misc_deregister(&mptctl_miscdev);
291565c054f2SKei Tokunaga 		err = -EBUSY;
291665c054f2SKei Tokunaga 		goto out_fail;
291765c054f2SKei Tokunaga 	}
291865c054f2SKei Tokunaga 
291909120a8cSPrakash, Sathya 	mpt_reset_register(mptctl_id, mptctl_ioc_reset);
292009120a8cSPrakash, Sathya 	mpt_event_register(mptctl_id, mptctl_event_process);
2921ea5a7a82SMoore, Eric 
29221da177e4SLinus Torvalds 	return 0;
29231da177e4SLinus Torvalds 
29241da177e4SLinus Torvalds out_fail:
29251da177e4SLinus Torvalds 
29261da177e4SLinus Torvalds 	mpt_device_driver_deregister(MPTCTL_DRIVER);
29271da177e4SLinus Torvalds 
29281da177e4SLinus Torvalds 	return err;
29291da177e4SLinus Torvalds }
29301da177e4SLinus Torvalds 
29311da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
mptctl_exit(void)29321da177e4SLinus Torvalds static void mptctl_exit(void)
29331da177e4SLinus Torvalds {
29341da177e4SLinus Torvalds 	misc_deregister(&mptctl_miscdev);
29351da177e4SLinus Torvalds 	printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",
29361da177e4SLinus Torvalds 			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
29371da177e4SLinus Torvalds 
293865c054f2SKei Tokunaga 	/* De-register event handler from base module */
293965c054f2SKei Tokunaga 	mpt_event_deregister(mptctl_id);
294065c054f2SKei Tokunaga 
29411da177e4SLinus Torvalds 	/* De-register reset handler from base module */
29421da177e4SLinus Torvalds 	mpt_reset_deregister(mptctl_id);
29431da177e4SLinus Torvalds 
29441da177e4SLinus Torvalds 	/* De-register callback handler from base module */
294565c054f2SKei Tokunaga 	mpt_deregister(mptctl_taskmgmt_id);
29461da177e4SLinus Torvalds 	mpt_deregister(mptctl_id);
29471da177e4SLinus Torvalds 
29481da177e4SLinus Torvalds         mpt_device_driver_deregister(MPTCTL_DRIVER);
29491da177e4SLinus Torvalds 
29501da177e4SLinus Torvalds }
29511da177e4SLinus Torvalds 
29521da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
29531da177e4SLinus Torvalds 
29541da177e4SLinus Torvalds module_init(mptctl_init);
29551da177e4SLinus Torvalds module_exit(mptctl_exit);
2956