xref: /linux/drivers/message/fusion/mptctl.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
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 	 */
1331*4280a0a7SJustin Stitt 	strscpy_pad(karg->driverVersion, MPT_LINUX_PACKAGE_NAME,
1332*4280a0a7SJustin Stitt 		    sizeof(karg->driverVersion));
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
1496*4280a0a7SJustin Stitt 	strscpy_pad(karg.name, ioc->name, sizeof(karg.name));
1497*4280a0a7SJustin Stitt 	strscpy_pad(karg.product, ioc->prod_name, sizeof(karg.product));
14981da177e4SLinus Torvalds 
14991da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
15001da177e4SLinus Torvalds 	 */
15011da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) {
150229dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_readtest - "
15031da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_test struct @ %p\n",
150429dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, uarg);
15051da177e4SLinus Torvalds 		return -EFAULT;
15061da177e4SLinus Torvalds 	}
15071da177e4SLinus Torvalds 
15081da177e4SLinus Torvalds 	return 0;
15091da177e4SLinus Torvalds }
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
15121da177e4SLinus Torvalds /*
15131da177e4SLinus Torvalds  *	mptctl_eventquery - Query the host adapter for the event types
15141da177e4SLinus Torvalds  *	that are being logged.
15151da177e4SLinus Torvalds  *	@arg: User space argument
15161da177e4SLinus Torvalds  *
15171da177e4SLinus Torvalds  * Outputs:	None.
15181da177e4SLinus Torvalds  * Return:	0 if successful
15191da177e4SLinus Torvalds  *		-EFAULT if data unavailable
15201da177e4SLinus Torvalds  *		-ENODEV  if no such device/adapter
15211da177e4SLinus Torvalds  */
15221da177e4SLinus Torvalds static int
mptctl_eventquery(MPT_ADAPTER * ioc,unsigned long arg)152328d76df1SDan Carpenter mptctl_eventquery (MPT_ADAPTER *ioc, unsigned long arg)
15241da177e4SLinus Torvalds {
15251da177e4SLinus Torvalds 	struct mpt_ioctl_eventquery __user *uarg = (void __user *) arg;
15261da177e4SLinus Torvalds 	struct mpt_ioctl_eventquery	 karg;
15271da177e4SLinus Torvalds 
15281da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
152929dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - "
15301da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_eventquery struct @ %p\n",
15311da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
15321da177e4SLinus Torvalds 		return -EFAULT;
15331da177e4SLinus Torvalds 	}
15341da177e4SLinus Torvalds 
153509120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n",
153609120a8cSPrakash, Sathya 	    ioc->name));
15375b5ef4f6SMoore, Eric 	karg.eventEntries = MPTCTL_EVENT_LOG_SIZE;
15381da177e4SLinus Torvalds 	karg.eventTypes = ioc->eventTypes;
15391da177e4SLinus Torvalds 
15401da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
15411da177e4SLinus Torvalds 	 */
15421da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) {
154329dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventquery - "
15441da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_eventquery struct @ %p\n",
154529dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, uarg);
15461da177e4SLinus Torvalds 		return -EFAULT;
15471da177e4SLinus Torvalds 	}
15481da177e4SLinus Torvalds 	return 0;
15491da177e4SLinus Torvalds }
15501da177e4SLinus Torvalds 
15511da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
15521da177e4SLinus Torvalds static int
mptctl_eventenable(MPT_ADAPTER * ioc,unsigned long arg)155328d76df1SDan Carpenter mptctl_eventenable (MPT_ADAPTER *ioc, unsigned long arg)
15541da177e4SLinus Torvalds {
15551da177e4SLinus Torvalds 	struct mpt_ioctl_eventenable __user *uarg = (void __user *) arg;
15561da177e4SLinus Torvalds 	struct mpt_ioctl_eventenable	 karg;
15571da177e4SLinus Torvalds 
15581da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
155929dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - "
15601da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_eventenable struct @ %p\n",
15611da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
15621da177e4SLinus Torvalds 		return -EFAULT;
15631da177e4SLinus Torvalds 	}
15641da177e4SLinus Torvalds 
156509120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n",
156609120a8cSPrakash, Sathya 	    ioc->name));
15671da177e4SLinus Torvalds 	if (ioc->events == NULL) {
15681da177e4SLinus Torvalds 		/* Have not yet allocated memory - do so now.
15691da177e4SLinus Torvalds 		 */
15701da177e4SLinus Torvalds 		int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
1571d7383a23SMariusz Kozlowski 		ioc->events = kzalloc(sz, GFP_KERNEL);
1572d7383a23SMariusz Kozlowski 		if (!ioc->events) {
157329dd3609SEric Moore 			printk(MYIOC_s_ERR_FMT
157429dd3609SEric Moore 			    ": ERROR - Insufficient memory to add adapter!\n",
157529dd3609SEric Moore 			    ioc->name);
15761da177e4SLinus Torvalds 			return -ENOMEM;
15771da177e4SLinus Torvalds 		}
15781da177e4SLinus Torvalds 		ioc->alloc_total += sz;
15791da177e4SLinus Torvalds 
15801da177e4SLinus Torvalds 		ioc->eventContext = 0;
15811da177e4SLinus Torvalds         }
15821da177e4SLinus Torvalds 
15831da177e4SLinus Torvalds 	/* Update the IOC event logging flag.
15841da177e4SLinus Torvalds 	 */
15851da177e4SLinus Torvalds 	ioc->eventTypes = karg.eventTypes;
15861da177e4SLinus Torvalds 
15871da177e4SLinus Torvalds 	return 0;
15881da177e4SLinus Torvalds }
15891da177e4SLinus Torvalds 
15901da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
15911da177e4SLinus Torvalds static int
mptctl_eventreport(MPT_ADAPTER * ioc,unsigned long arg)159228d76df1SDan Carpenter mptctl_eventreport (MPT_ADAPTER *ioc, unsigned long arg)
15931da177e4SLinus Torvalds {
15941da177e4SLinus Torvalds 	struct mpt_ioctl_eventreport __user *uarg = (void __user *) arg;
15951da177e4SLinus Torvalds 	struct mpt_ioctl_eventreport	 karg;
15961da177e4SLinus Torvalds 	int			 numBytes, maxEvents, max;
15971da177e4SLinus Torvalds 
15981da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
159929dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_eventreport - "
16001da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_eventreport struct @ %p\n",
16011da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
16021da177e4SLinus Torvalds 		return -EFAULT;
16031da177e4SLinus Torvalds 	}
16041da177e4SLinus Torvalds 
160509120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
160609120a8cSPrakash, Sathya 	    ioc->name));
16071da177e4SLinus Torvalds 
16081da177e4SLinus Torvalds 	numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
16091da177e4SLinus Torvalds 	maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
16101da177e4SLinus Torvalds 
16111da177e4SLinus Torvalds 
16125b5ef4f6SMoore, Eric 	max = MPTCTL_EVENT_LOG_SIZE < maxEvents ? MPTCTL_EVENT_LOG_SIZE : maxEvents;
16131da177e4SLinus Torvalds 
16141da177e4SLinus Torvalds 	/* If fewer than 1 event is requested, there must have
16151da177e4SLinus Torvalds 	 * been some type of error.
16161da177e4SLinus Torvalds 	 */
16171da177e4SLinus Torvalds 	if ((max < 1) || !ioc->events)
16181da177e4SLinus Torvalds 		return -ENODATA;
16191da177e4SLinus Torvalds 
1620ea5a7a82SMoore, Eric 	/* reset this flag so SIGIO can restart */
1621ea5a7a82SMoore, Eric 	ioc->aen_event_read_flag=0;
1622ea5a7a82SMoore, Eric 
16231da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
16241da177e4SLinus Torvalds 	 */
16251da177e4SLinus Torvalds 	numBytes = max * sizeof(MPT_IOCTL_EVENTS);
16261da177e4SLinus Torvalds 	if (copy_to_user(uarg->eventData, ioc->events, numBytes)) {
162729dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventreport - "
16281da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_eventreport struct @ %p\n",
162929dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, ioc->events);
16301da177e4SLinus Torvalds 		return -EFAULT;
16311da177e4SLinus Torvalds 	}
16321da177e4SLinus Torvalds 
16331da177e4SLinus Torvalds 	return 0;
16341da177e4SLinus Torvalds }
16351da177e4SLinus Torvalds 
16361da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
16371da177e4SLinus Torvalds static int
mptctl_replace_fw(MPT_ADAPTER * ioc,unsigned long arg)163828d76df1SDan Carpenter mptctl_replace_fw (MPT_ADAPTER *ioc, unsigned long arg)
16391da177e4SLinus Torvalds {
16401da177e4SLinus Torvalds 	struct mpt_ioctl_replace_fw __user *uarg = (void __user *) arg;
16411da177e4SLinus Torvalds 	struct mpt_ioctl_replace_fw	 karg;
16421da177e4SLinus Torvalds 	int			 newFwSize;
16431da177e4SLinus Torvalds 
16441da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
164529dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_replace_fw - "
16461da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
16471da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
16481da177e4SLinus Torvalds 		return -EFAULT;
16491da177e4SLinus Torvalds 	}
16501da177e4SLinus Torvalds 
165109120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n",
165209120a8cSPrakash, Sathya 	    ioc->name));
16531da177e4SLinus Torvalds 	/* If caching FW, Free the old FW image
16541da177e4SLinus Torvalds 	 */
16551da177e4SLinus Torvalds 	if (ioc->cached_fw == NULL)
16561da177e4SLinus Torvalds 		return 0;
16571da177e4SLinus Torvalds 
16581da177e4SLinus Torvalds 	mpt_free_fw_memory(ioc);
16591da177e4SLinus Torvalds 
16601da177e4SLinus Torvalds 	/* Allocate memory for the new FW image
16611da177e4SLinus Torvalds 	 */
1662f6e495a2SRasmus Villemoes 	newFwSize = ALIGN(karg.newImageSize, 4);
16631da177e4SLinus Torvalds 
16641da177e4SLinus Torvalds 	mpt_alloc_fw_memory(ioc, newFwSize);
16651da177e4SLinus Torvalds 	if (ioc->cached_fw == NULL)
16661da177e4SLinus Torvalds 		return -ENOMEM;
16671da177e4SLinus Torvalds 
16681da177e4SLinus Torvalds 	/* Copy the data from user memory to kernel space
16691da177e4SLinus Torvalds 	 */
16701da177e4SLinus Torvalds 	if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
167129dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - "
16721da177e4SLinus Torvalds 				"Unable to read in mpt_ioctl_replace_fw image "
167329dd3609SEric Moore 				"@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
16741da177e4SLinus Torvalds 		mpt_free_fw_memory(ioc);
16751da177e4SLinus Torvalds 		return -EFAULT;
16761da177e4SLinus Torvalds 	}
16771da177e4SLinus Torvalds 
16781da177e4SLinus Torvalds 	/* Update IOCFactsReply
16791da177e4SLinus Torvalds 	 */
16801da177e4SLinus Torvalds 	ioc->facts.FWImageSize = newFwSize;
16811da177e4SLinus Torvalds 	return 0;
16821da177e4SLinus Torvalds }
16831da177e4SLinus Torvalds 
16841da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
16851da177e4SLinus Torvalds /* MPT IOCTL MPTCOMMAND function.
16861da177e4SLinus Torvalds  * Cast the arg into the mpt_ioctl_mpt_command structure.
16871da177e4SLinus Torvalds  *
16881da177e4SLinus Torvalds  * Outputs:	None.
16891da177e4SLinus Torvalds  * Return:	0 if successful
1690fc1323bbSJoe Perches  *		-EBUSY  if previous command timeout and IOC reset is not complete.
16911da177e4SLinus Torvalds  *		-EFAULT if data unavailable
16921da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
16931da177e4SLinus Torvalds  *		-ETIME	if timer expires
16941da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
16951da177e4SLinus Torvalds  */
16961da177e4SLinus Torvalds static int
mptctl_mpt_command(MPT_ADAPTER * ioc,unsigned long arg)169728d76df1SDan Carpenter mptctl_mpt_command (MPT_ADAPTER *ioc, unsigned long arg)
16981da177e4SLinus Torvalds {
16991da177e4SLinus Torvalds 	struct mpt_ioctl_command __user *uarg = (void __user *) arg;
17001da177e4SLinus Torvalds 	struct mpt_ioctl_command  karg;
17011da177e4SLinus Torvalds 	int		rc;
17021da177e4SLinus Torvalds 
17031da177e4SLinus Torvalds 
17041da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
170529dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_mpt_command - "
17061da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_command struct @ %p\n",
17071da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
17081da177e4SLinus Torvalds 		return -EFAULT;
17091da177e4SLinus Torvalds 	}
17101da177e4SLinus Torvalds 
171128d76df1SDan Carpenter 	rc = mptctl_do_mpt_command (ioc, karg, &uarg->MF);
17121da177e4SLinus Torvalds 
17131da177e4SLinus Torvalds 	return rc;
17141da177e4SLinus Torvalds }
17151da177e4SLinus Torvalds 
17161da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
17171da177e4SLinus Torvalds /* Worker routine for the IOCTL MPTCOMMAND and MPTCOMMAND32 (sparc) commands.
17181da177e4SLinus Torvalds  *
17191da177e4SLinus Torvalds  * Outputs:	None.
17201da177e4SLinus Torvalds  * Return:	0 if successful
1721fc1323bbSJoe Perches  *		-EBUSY  if previous command timeout and IOC reset is not complete.
17221da177e4SLinus Torvalds  *		-EFAULT if data unavailable
17231da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
17241da177e4SLinus Torvalds  *		-ETIME	if timer expires
17251da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
17261da177e4SLinus Torvalds  *		-EPERM if SCSI I/O and target is untagged
17271da177e4SLinus Torvalds  */
17281da177e4SLinus Torvalds static int
mptctl_do_mpt_command(MPT_ADAPTER * ioc,struct mpt_ioctl_command karg,void __user * mfPtr)172928d76df1SDan Carpenter mptctl_do_mpt_command (MPT_ADAPTER *ioc, struct mpt_ioctl_command karg, void __user *mfPtr)
17301da177e4SLinus Torvalds {
17311da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf = NULL;
17321da177e4SLinus Torvalds 	MPIHeader_t	*hdr;
17331da177e4SLinus Torvalds 	char		*psge;
17341da177e4SLinus Torvalds 	struct buflist	bufIn;	/* data In buffer */
17351da177e4SLinus Torvalds 	struct buflist	bufOut; /* data Out buffer */
17361da177e4SLinus Torvalds 	dma_addr_t	dma_addr_in;
17371da177e4SLinus Torvalds 	dma_addr_t	dma_addr_out;
17381da177e4SLinus Torvalds 	int		sgSize = 0;	/* Num SG elements */
173928d76df1SDan Carpenter 	int		flagsLength;
17401da177e4SLinus Torvalds 	int		sz, rc = 0;
17411da177e4SLinus Torvalds 	int		msgContext;
17421da177e4SLinus Torvalds 	u16		req_idx;
17431da177e4SLinus Torvalds 	ulong 		timeout;
1744ea2a788dSKashyap, Desai 	unsigned long	timeleft;
1745793955f5SEric Moore 	struct scsi_device *sdev;
1746ea2a788dSKashyap, Desai 	unsigned long	 flags;
1747ea2a788dSKashyap, Desai 	u8		 function;
17481da177e4SLinus Torvalds 
1749ab371287SEric Moore 	/* bufIn and bufOut are used for user to kernel space transfers
1750ab371287SEric Moore 	 */
17511da177e4SLinus Torvalds 	bufIn.kptr = bufOut.kptr = NULL;
1752ab371287SEric Moore 	bufIn.len = bufOut.len = 0;
17531da177e4SLinus Torvalds 
1754ea2a788dSKashyap, Desai 	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
1755ea2a788dSKashyap, Desai 	if (ioc->ioc_reset_in_progress) {
1756ea2a788dSKashyap, Desai 		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
175729dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
1758ea2a788dSKashyap, Desai 			"Busy with diagnostic reset\n", __FILE__, __LINE__);
17591da177e4SLinus Torvalds 		return -EBUSY;
17601da177e4SLinus Torvalds 	}
1761ea2a788dSKashyap, Desai 	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
17621da177e4SLinus Torvalds 
1763e819cdb1SDan Carpenter 	/* Basic sanity checks to prevent underflows or integer overflows */
1764e819cdb1SDan Carpenter 	if (karg.maxReplyBytes < 0 ||
1765e819cdb1SDan Carpenter 	    karg.dataInSize < 0 ||
1766e819cdb1SDan Carpenter 	    karg.dataOutSize < 0 ||
1767e819cdb1SDan Carpenter 	    karg.dataSgeOffset < 0 ||
1768e819cdb1SDan Carpenter 	    karg.maxSenseBytes < 0 ||
1769e819cdb1SDan Carpenter 	    karg.dataSgeOffset > ioc->req_sz / 4)
1770e819cdb1SDan Carpenter 		return -EINVAL;
1771e819cdb1SDan Carpenter 
17721da177e4SLinus Torvalds 	/* Verify that the final request frame will not be too large.
17731da177e4SLinus Torvalds 	 */
17741da177e4SLinus Torvalds 	sz = karg.dataSgeOffset * 4;
17751da177e4SLinus Torvalds 	if (karg.dataInSize > 0)
177614d0f0b0SKashyap, Desai 		sz += ioc->SGE_size;
17771da177e4SLinus Torvalds 	if (karg.dataOutSize > 0)
177814d0f0b0SKashyap, Desai 		sz += ioc->SGE_size;
17791da177e4SLinus Torvalds 
17801da177e4SLinus Torvalds 	if (sz > ioc->req_sz) {
178129dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
17821da177e4SLinus Torvalds 			"Request frame too large (%d) maximum (%d)\n",
178329dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, sz, ioc->req_sz);
17841da177e4SLinus Torvalds 		return -EFAULT;
17851da177e4SLinus Torvalds 	}
17861da177e4SLinus Torvalds 
17871da177e4SLinus Torvalds 	/* Get a free request frame and save the message context.
17881da177e4SLinus Torvalds 	 */
17891da177e4SLinus Torvalds         if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
17901da177e4SLinus Torvalds                 return -EAGAIN;
17911da177e4SLinus Torvalds 
17921da177e4SLinus Torvalds 	hdr = (MPIHeader_t *) mf;
17931da177e4SLinus Torvalds 	msgContext = le32_to_cpu(hdr->MsgContext);
17941da177e4SLinus Torvalds 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
17951da177e4SLinus Torvalds 
17961da177e4SLinus Torvalds 	/* Copy the request frame
17971da177e4SLinus Torvalds 	 * Reset the saved message context.
17981da177e4SLinus Torvalds 	 * Request frame in user space
17991da177e4SLinus Torvalds 	 */
18001da177e4SLinus Torvalds 	if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) {
180129dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
18021da177e4SLinus Torvalds 			"Unable to read MF from mpt_ioctl_command struct @ %p\n",
180329dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, mfPtr);
1804ea2a788dSKashyap, Desai 		function = -1;
18051da177e4SLinus Torvalds 		rc = -EFAULT;
18061da177e4SLinus Torvalds 		goto done_free_mem;
18071da177e4SLinus Torvalds 	}
18081da177e4SLinus Torvalds 	hdr->MsgContext = cpu_to_le32(msgContext);
1809ea2a788dSKashyap, Desai 	function = hdr->Function;
18101da177e4SLinus Torvalds 
18111da177e4SLinus Torvalds 
18121da177e4SLinus Torvalds 	/* Verify that this request is allowed.
18131da177e4SLinus Torvalds 	 */
181409120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
181509120a8cSPrakash, Sathya 	    ioc->name, hdr->Function, mf));
181609120a8cSPrakash, Sathya 
1817ea2a788dSKashyap, Desai 	switch (function) {
18181da177e4SLinus Torvalds 	case MPI_FUNCTION_IOC_FACTS:
18191da177e4SLinus Torvalds 	case MPI_FUNCTION_PORT_FACTS:
18201da177e4SLinus Torvalds 		karg.dataOutSize  = karg.dataInSize = 0;
18211da177e4SLinus Torvalds 		break;
18221da177e4SLinus Torvalds 
18231da177e4SLinus Torvalds 	case MPI_FUNCTION_CONFIG:
182409120a8cSPrakash, Sathya 	{
182509120a8cSPrakash, Sathya 		Config_t *config_frame;
182609120a8cSPrakash, Sathya 		config_frame = (Config_t *)mf;
182709120a8cSPrakash, Sathya 		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\ttype=0x%02x ext_type=0x%02x "
182809120a8cSPrakash, Sathya 		    "number=0x%02x action=0x%02x\n", ioc->name,
182909120a8cSPrakash, Sathya 		    config_frame->Header.PageType,
183009120a8cSPrakash, Sathya 		    config_frame->ExtPageType,
183109120a8cSPrakash, Sathya 		    config_frame->Header.PageNumber,
183209120a8cSPrakash, Sathya 		    config_frame->Action));
183309120a8cSPrakash, Sathya 		break;
183409120a8cSPrakash, Sathya 	}
183509120a8cSPrakash, Sathya 
18361da177e4SLinus Torvalds 	case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
18371da177e4SLinus Torvalds 	case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
18381da177e4SLinus Torvalds 	case MPI_FUNCTION_FW_UPLOAD:
18391da177e4SLinus Torvalds 	case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
18401da177e4SLinus Torvalds 	case MPI_FUNCTION_FW_DOWNLOAD:
18411da177e4SLinus Torvalds 	case MPI_FUNCTION_FC_PRIMITIVE_SEND:
1842096f7a2aSMoore, Eric 	case MPI_FUNCTION_TOOLBOX:
1843096f7a2aSMoore, Eric 	case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
18441da177e4SLinus Torvalds 		break;
18451da177e4SLinus Torvalds 
18461da177e4SLinus Torvalds 	case MPI_FUNCTION_SCSI_IO_REQUEST:
18471da177e4SLinus Torvalds 		if (ioc->sh) {
18481da177e4SLinus Torvalds 			SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
18491da177e4SLinus Torvalds 			int qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
18501da177e4SLinus Torvalds 			int scsidir = 0;
18511da177e4SLinus Torvalds 			int dataSize;
1852793955f5SEric Moore 			u32 id;
18531da177e4SLinus Torvalds 
1854793955f5SEric Moore 			id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus;
1855793955f5SEric Moore 			if (pScsiReq->TargetID > id) {
185629dd3609SEric Moore 				printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
18571da177e4SLinus Torvalds 					"Target ID out of bounds. \n",
185829dd3609SEric Moore 					ioc->name, __FILE__, __LINE__);
18591da177e4SLinus Torvalds 				rc = -ENODEV;
18601da177e4SLinus Torvalds 				goto done_free_mem;
18611da177e4SLinus Torvalds 			}
18621da177e4SLinus Torvalds 
1863793955f5SEric Moore 			if (pScsiReq->Bus >= ioc->number_of_buses) {
186429dd3609SEric Moore 				printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
1865793955f5SEric Moore 					"Target Bus out of bounds. \n",
186629dd3609SEric Moore 					ioc->name, __FILE__, __LINE__);
1867793955f5SEric Moore 				rc = -ENODEV;
1868793955f5SEric Moore 				goto done_free_mem;
1869793955f5SEric Moore 			}
1870793955f5SEric Moore 
18715f07e249SMoore, Eric 			pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
187214d0f0b0SKashyap, Desai 			pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
18735f07e249SMoore, Eric 
18741da177e4SLinus Torvalds 
18751da177e4SLinus Torvalds 			/* verify that app has not requested
18761da177e4SLinus Torvalds 			 *	more sense data than driver
18771da177e4SLinus Torvalds 			 *	can provide, if so, reset this parameter
18781da177e4SLinus Torvalds 			 * set the sense buffer pointer low address
18791da177e4SLinus Torvalds 			 * update the control field to specify Q type
18801da177e4SLinus Torvalds 			 */
18811da177e4SLinus Torvalds 			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
18821da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
18831da177e4SLinus Torvalds 			else
18841da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = karg.maxSenseBytes;
18851da177e4SLinus Torvalds 
18861da177e4SLinus Torvalds 			pScsiReq->SenseBufferLowAddr =
18871da177e4SLinus Torvalds 				cpu_to_le32(ioc->sense_buf_low_dma
18881da177e4SLinus Torvalds 				   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
18891da177e4SLinus Torvalds 
1890793955f5SEric Moore 			shost_for_each_device(sdev, ioc->sh) {
1891793955f5SEric Moore 				struct scsi_target *starget = scsi_target(sdev);
1892793955f5SEric Moore 				VirtTarget *vtarget = starget->hostdata;
18931da177e4SLinus Torvalds 
189408f5c5c2SKashyap, Desai 				if (vtarget == NULL)
189508f5c5c2SKashyap, Desai 					continue;
189608f5c5c2SKashyap, Desai 
1897793955f5SEric Moore 				if ((pScsiReq->TargetID == vtarget->id) &&
1898793955f5SEric Moore 				    (pScsiReq->Bus == vtarget->channel) &&
1899793955f5SEric Moore 				    (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
19001da177e4SLinus Torvalds 					qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
1901793955f5SEric Moore 			}
19021da177e4SLinus Torvalds 
19031da177e4SLinus Torvalds 			/* Have the IOCTL driver set the direction based
19041da177e4SLinus Torvalds 			 * on the dataOutSize (ordering issue with Sparc).
19051da177e4SLinus Torvalds 			 */
19061da177e4SLinus Torvalds 			if (karg.dataOutSize > 0) {
19071da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_WRITE;
19081da177e4SLinus Torvalds 				dataSize = karg.dataOutSize;
19091da177e4SLinus Torvalds 			} else {
19101da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_READ;
19111da177e4SLinus Torvalds 				dataSize = karg.dataInSize;
19121da177e4SLinus Torvalds 			}
19131da177e4SLinus Torvalds 
19141da177e4SLinus Torvalds 			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
19151da177e4SLinus Torvalds 			pScsiReq->DataLength = cpu_to_le32(dataSize);
19161da177e4SLinus Torvalds 
19171da177e4SLinus Torvalds 
19181da177e4SLinus Torvalds 		} else {
191929dd3609SEric Moore 			printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
19201da177e4SLinus Torvalds 				"SCSI driver is not loaded. \n",
192129dd3609SEric Moore 				ioc->name, __FILE__, __LINE__);
19221da177e4SLinus Torvalds 			rc = -EFAULT;
19231da177e4SLinus Torvalds 			goto done_free_mem;
19241da177e4SLinus Torvalds 		}
19251da177e4SLinus Torvalds 		break;
19261da177e4SLinus Torvalds 
1927096f7a2aSMoore, Eric 	case MPI_FUNCTION_SMP_PASSTHROUGH:
1928096f7a2aSMoore, Eric 		/* Check mf->PassthruFlags to determine if
1929096f7a2aSMoore, Eric 		 * transfer is ImmediateMode or not.
1930096f7a2aSMoore, Eric 		 * Immediate mode returns data in the ReplyFrame.
1931096f7a2aSMoore, Eric 		 * Else, we are sending request and response data
1932096f7a2aSMoore, Eric 		 * in two SGLs at the end of the mf.
1933096f7a2aSMoore, Eric 		 */
1934096f7a2aSMoore, Eric 		break;
1935096f7a2aSMoore, Eric 
1936096f7a2aSMoore, Eric 	case MPI_FUNCTION_SATA_PASSTHROUGH:
1937096f7a2aSMoore, Eric 		if (!ioc->sh) {
193829dd3609SEric Moore 			printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
1939096f7a2aSMoore, Eric 				"SCSI driver is not loaded. \n",
194029dd3609SEric Moore 				ioc->name, __FILE__, __LINE__);
1941096f7a2aSMoore, Eric 			rc = -EFAULT;
1942096f7a2aSMoore, Eric 			goto done_free_mem;
1943096f7a2aSMoore, Eric 		}
1944096f7a2aSMoore, Eric 		break;
1945096f7a2aSMoore, Eric 
19461da177e4SLinus Torvalds 	case MPI_FUNCTION_RAID_ACTION:
19471da177e4SLinus Torvalds 		/* Just add a SGE
19481da177e4SLinus Torvalds 		 */
19491da177e4SLinus Torvalds 		break;
19501da177e4SLinus Torvalds 
19511da177e4SLinus Torvalds 	case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
19521da177e4SLinus Torvalds 		if (ioc->sh) {
19531da177e4SLinus Torvalds 			SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
19541da177e4SLinus Torvalds 			int qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
19551da177e4SLinus Torvalds 			int scsidir = MPI_SCSIIO_CONTROL_READ;
19561da177e4SLinus Torvalds 			int dataSize;
19571da177e4SLinus Torvalds 
19585f07e249SMoore, Eric 			pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
195914d0f0b0SKashyap, Desai 			pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
19605f07e249SMoore, Eric 
19611da177e4SLinus Torvalds 
19621da177e4SLinus Torvalds 			/* verify that app has not requested
19631da177e4SLinus Torvalds 			 *	more sense data than driver
19641da177e4SLinus Torvalds 			 *	can provide, if so, reset this parameter
19651da177e4SLinus Torvalds 			 * set the sense buffer pointer low address
19661da177e4SLinus Torvalds 			 * update the control field to specify Q type
19671da177e4SLinus Torvalds 			 */
19681da177e4SLinus Torvalds 			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
19691da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
19701da177e4SLinus Torvalds 			else
19711da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = karg.maxSenseBytes;
19721da177e4SLinus Torvalds 
19731da177e4SLinus Torvalds 			pScsiReq->SenseBufferLowAddr =
19741da177e4SLinus Torvalds 				cpu_to_le32(ioc->sense_buf_low_dma
19751da177e4SLinus Torvalds 				   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
19761da177e4SLinus Torvalds 
19771da177e4SLinus Torvalds 			/* All commands to physical devices are tagged
19781da177e4SLinus Torvalds 			 */
19791da177e4SLinus Torvalds 
19801da177e4SLinus Torvalds 			/* Have the IOCTL driver set the direction based
19811da177e4SLinus Torvalds 			 * on the dataOutSize (ordering issue with Sparc).
19821da177e4SLinus Torvalds 			 */
19831da177e4SLinus Torvalds 			if (karg.dataOutSize > 0) {
19841da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_WRITE;
19851da177e4SLinus Torvalds 				dataSize = karg.dataOutSize;
19861da177e4SLinus Torvalds 			} else {
19871da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_READ;
19881da177e4SLinus Torvalds 				dataSize = karg.dataInSize;
19891da177e4SLinus Torvalds 			}
19901da177e4SLinus Torvalds 
19911da177e4SLinus Torvalds 			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
19921da177e4SLinus Torvalds 			pScsiReq->DataLength = cpu_to_le32(dataSize);
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds 		} else {
199529dd3609SEric Moore 			printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
19961da177e4SLinus Torvalds 				"SCSI driver is not loaded. \n",
199729dd3609SEric Moore 				ioc->name, __FILE__, __LINE__);
19981da177e4SLinus Torvalds 			rc = -EFAULT;
19991da177e4SLinus Torvalds 			goto done_free_mem;
20001da177e4SLinus Torvalds 		}
20011da177e4SLinus Torvalds 		break;
20021da177e4SLinus Torvalds 
20031da177e4SLinus Torvalds 	case MPI_FUNCTION_SCSI_TASK_MGMT:
20041da177e4SLinus Torvalds 	{
2005ea2a788dSKashyap, Desai 		SCSITaskMgmt_t	*pScsiTm;
2006ea2a788dSKashyap, Desai 		pScsiTm = (SCSITaskMgmt_t *)mf;
2007ea2a788dSKashyap, Desai 		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2008ea2a788dSKashyap, Desai 			"\tTaskType=0x%x MsgFlags=0x%x "
2009ea2a788dSKashyap, Desai 			"TaskMsgContext=0x%x id=%d channel=%d\n",
2010ea2a788dSKashyap, Desai 			ioc->name, pScsiTm->TaskType, le32_to_cpu
2011ea2a788dSKashyap, Desai 			(pScsiTm->TaskMsgContext), pScsiTm->MsgFlags,
2012ea2a788dSKashyap, Desai 			pScsiTm->TargetID, pScsiTm->Bus));
20131da177e4SLinus Torvalds 		break;
2014ea2a788dSKashyap, Desai 	}
20151da177e4SLinus Torvalds 
20161da177e4SLinus Torvalds 	case MPI_FUNCTION_IOC_INIT:
20171da177e4SLinus Torvalds 		{
20181da177e4SLinus Torvalds 			IOCInit_t	*pInit = (IOCInit_t *) mf;
20191da177e4SLinus Torvalds 			u32		high_addr, sense_high;
20201da177e4SLinus Torvalds 
20211da177e4SLinus Torvalds 			/* Verify that all entries in the IOC INIT match
20221da177e4SLinus Torvalds 			 * existing setup (and in LE format).
20231da177e4SLinus Torvalds 			 */
20241da177e4SLinus Torvalds 			if (sizeof(dma_addr_t) == sizeof(u64)) {
20251da177e4SLinus Torvalds 				high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32));
20261da177e4SLinus Torvalds 				sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
20271da177e4SLinus Torvalds 			} else {
20281da177e4SLinus Torvalds 				high_addr = 0;
20291da177e4SLinus Torvalds 				sense_high= 0;
20301da177e4SLinus Torvalds 			}
20311da177e4SLinus Torvalds 
20321da177e4SLinus Torvalds 			if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) ||
20331da177e4SLinus Torvalds 				(pInit->MaxBuses != ioc->facts.MaxBuses) ||
20341da177e4SLinus Torvalds 				(pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
20351da177e4SLinus Torvalds 				(pInit->HostMfaHighAddr != high_addr) ||
20361da177e4SLinus Torvalds 				(pInit->SenseBufferHighAddr != sense_high)) {
203729dd3609SEric Moore 				printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
20381da177e4SLinus Torvalds 					"IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n",
203929dd3609SEric Moore 					ioc->name, __FILE__, __LINE__);
20401da177e4SLinus Torvalds 				rc = -EFAULT;
20411da177e4SLinus Torvalds 				goto done_free_mem;
20421da177e4SLinus Torvalds 			}
20431da177e4SLinus Torvalds 		}
20441da177e4SLinus Torvalds 		break;
20451da177e4SLinus Torvalds 	default:
20461da177e4SLinus Torvalds 		/*
20471da177e4SLinus Torvalds 		 * MPI_FUNCTION_PORT_ENABLE
20481da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_CMD_BUFFER_POST
20491da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_ASSIST
20501da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_STATUS_SEND
20511da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_MODE_ABORT
20521da177e4SLinus Torvalds 		 * MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET
20531da177e4SLinus Torvalds 		 * MPI_FUNCTION_IO_UNIT_RESET
20541da177e4SLinus Torvalds 		 * MPI_FUNCTION_HANDSHAKE
20551da177e4SLinus Torvalds 		 * MPI_FUNCTION_REPLY_FRAME_REMOVAL
20561da177e4SLinus Torvalds 		 * MPI_FUNCTION_EVENT_NOTIFICATION
20571da177e4SLinus Torvalds 		 *  (driver handles event notification)
20581da177e4SLinus Torvalds 		 * MPI_FUNCTION_EVENT_ACK
20591da177e4SLinus Torvalds 		 */
20601da177e4SLinus Torvalds 
20611da177e4SLinus Torvalds 		/*  What to do with these???  CHECK ME!!!
20621da177e4SLinus Torvalds 			MPI_FUNCTION_FC_LINK_SRVC_BUF_POST
20631da177e4SLinus Torvalds 			MPI_FUNCTION_FC_LINK_SRVC_RSP
20641da177e4SLinus Torvalds 			MPI_FUNCTION_FC_ABORT
20651da177e4SLinus Torvalds 			MPI_FUNCTION_LAN_SEND
20661da177e4SLinus Torvalds 			MPI_FUNCTION_LAN_RECEIVE
20671da177e4SLinus Torvalds 		 	MPI_FUNCTION_LAN_RESET
20681da177e4SLinus Torvalds 		*/
20691da177e4SLinus Torvalds 
207029dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
20711da177e4SLinus Torvalds 			"Illegal request (function 0x%x) \n",
207229dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, hdr->Function);
20731da177e4SLinus Torvalds 		rc = -EFAULT;
20741da177e4SLinus Torvalds 		goto done_free_mem;
20751da177e4SLinus Torvalds 	}
20761da177e4SLinus Torvalds 
20771da177e4SLinus Torvalds 	/* Add the SGL ( at most one data in SGE and one data out SGE )
20781da177e4SLinus Torvalds 	 * In the case of two SGE's - the data out (write) will always
20791da177e4SLinus Torvalds 	 * preceede the data in (read) SGE. psgList is used to free the
20801da177e4SLinus Torvalds 	 * allocated memory.
20811da177e4SLinus Torvalds 	 */
20821da177e4SLinus Torvalds 	psge = (char *) (((int *) mf) + karg.dataSgeOffset);
20831da177e4SLinus Torvalds 	flagsLength = 0;
20841da177e4SLinus Torvalds 
20851da177e4SLinus Torvalds 	if (karg.dataOutSize > 0)
20861da177e4SLinus Torvalds 		sgSize ++;
20871da177e4SLinus Torvalds 
20881da177e4SLinus Torvalds 	if (karg.dataInSize > 0)
20891da177e4SLinus Torvalds 		sgSize ++;
20901da177e4SLinus Torvalds 
20911da177e4SLinus Torvalds 	if (sgSize > 0) {
20921da177e4SLinus Torvalds 
20931da177e4SLinus Torvalds 		/* Set up the dataOut memory allocation */
20941da177e4SLinus Torvalds 		if (karg.dataOutSize > 0) {
20951da177e4SLinus Torvalds 			if (karg.dataInSize > 0) {
20961da177e4SLinus Torvalds 				flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
20971da177e4SLinus Torvalds 						MPI_SGE_FLAGS_END_OF_BUFFER |
209814d0f0b0SKashyap, Desai 						MPI_SGE_FLAGS_DIRECTION)
20991da177e4SLinus Torvalds 						<< MPI_SGE_FLAGS_SHIFT;
21001da177e4SLinus Torvalds 			} else {
21011da177e4SLinus Torvalds 				flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
21021da177e4SLinus Torvalds 			}
21031da177e4SLinus Torvalds 			flagsLength |= karg.dataOutSize;
21041da177e4SLinus Torvalds 			bufOut.len = karg.dataOutSize;
2105706dc3b9SChristophe JAILLET 			bufOut.kptr = dma_alloc_coherent(&ioc->pcidev->dev,
2106706dc3b9SChristophe JAILLET 							 bufOut.len,
2107706dc3b9SChristophe JAILLET 							 &dma_addr_out, GFP_KERNEL);
21081da177e4SLinus Torvalds 
21091da177e4SLinus Torvalds 			if (bufOut.kptr == NULL) {
21101da177e4SLinus Torvalds 				rc = -ENOMEM;
21111da177e4SLinus Torvalds 				goto done_free_mem;
21121da177e4SLinus Torvalds 			} else {
21131da177e4SLinus Torvalds 				/* Set up this SGE.
21141da177e4SLinus Torvalds 				 * Copy to MF and to sglbuf
21151da177e4SLinus Torvalds 				 */
211614d0f0b0SKashyap, Desai 				ioc->add_sge(psge, flagsLength, dma_addr_out);
211714d0f0b0SKashyap, Desai 				psge += ioc->SGE_size;
21181da177e4SLinus Torvalds 
21191da177e4SLinus Torvalds 				/* Copy user data to kernel space.
21201da177e4SLinus Torvalds 				 */
21211da177e4SLinus Torvalds 				if (copy_from_user(bufOut.kptr,
21221da177e4SLinus Torvalds 						karg.dataOutBufPtr,
21231da177e4SLinus Torvalds 						bufOut.len)) {
212429dd3609SEric Moore 					printk(MYIOC_s_ERR_FMT
21251da177e4SLinus Torvalds 						"%s@%d::mptctl_do_mpt_command - Unable "
21261da177e4SLinus Torvalds 						"to read user data "
21271da177e4SLinus Torvalds 						"struct @ %p\n",
212829dd3609SEric Moore 						ioc->name, __FILE__, __LINE__,karg.dataOutBufPtr);
21291da177e4SLinus Torvalds 					rc =  -EFAULT;
21301da177e4SLinus Torvalds 					goto done_free_mem;
21311da177e4SLinus Torvalds 				}
21321da177e4SLinus Torvalds 			}
21331da177e4SLinus Torvalds 		}
21341da177e4SLinus Torvalds 
21351da177e4SLinus Torvalds 		if (karg.dataInSize > 0) {
21361da177e4SLinus Torvalds 			flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
21371da177e4SLinus Torvalds 			flagsLength |= karg.dataInSize;
21381da177e4SLinus Torvalds 
21391da177e4SLinus Torvalds 			bufIn.len = karg.dataInSize;
2140706dc3b9SChristophe JAILLET 			bufIn.kptr = dma_alloc_coherent(&ioc->pcidev->dev,
2141706dc3b9SChristophe JAILLET 							bufIn.len,
2142706dc3b9SChristophe JAILLET 							&dma_addr_in, GFP_KERNEL);
21431da177e4SLinus Torvalds 
21441da177e4SLinus Torvalds 			if (bufIn.kptr == NULL) {
21451da177e4SLinus Torvalds 				rc = -ENOMEM;
21461da177e4SLinus Torvalds 				goto done_free_mem;
21471da177e4SLinus Torvalds 			} else {
21481da177e4SLinus Torvalds 				/* Set up this SGE
21491da177e4SLinus Torvalds 				 * Copy to MF and to sglbuf
21501da177e4SLinus Torvalds 				 */
215114d0f0b0SKashyap, Desai 				ioc->add_sge(psge, flagsLength, dma_addr_in);
21521da177e4SLinus Torvalds 			}
21531da177e4SLinus Torvalds 		}
21541da177e4SLinus Torvalds 	} else  {
21551da177e4SLinus Torvalds 		/* Add a NULL SGE
21561da177e4SLinus Torvalds 		 */
215714d0f0b0SKashyap, Desai 		ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
21581da177e4SLinus Torvalds 	}
21591da177e4SLinus Torvalds 
2160ea2a788dSKashyap, Desai 	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext);
2161ea2a788dSKashyap, Desai 	INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
21621da177e4SLinus Torvalds 	if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
21631da177e4SLinus Torvalds 
2164ea2a788dSKashyap, Desai 		mutex_lock(&ioc->taskmgmt_cmds.mutex);
2165ea2a788dSKashyap, Desai 		if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
2166ea2a788dSKashyap, Desai 			mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2167ea2a788dSKashyap, Desai 			goto done_free_mem;
2168ea2a788dSKashyap, Desai 		}
2169ea2a788dSKashyap, Desai 
217009120a8cSPrakash, Sathya 		DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
21711da177e4SLinus Torvalds 
21727a195f46SPrakash, Sathya 		if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
21737a195f46SPrakash, Sathya 		    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
21747a195f46SPrakash, Sathya 			mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf);
21757a195f46SPrakash, Sathya 		else {
21767a195f46SPrakash, Sathya 			rc =mpt_send_handshake_request(mptctl_id, ioc,
21777a195f46SPrakash, Sathya 				sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
21787a195f46SPrakash, Sathya 			if (rc != 0) {
21797a195f46SPrakash, Sathya 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
2180ea2a788dSKashyap, Desai 				    "send_handshake FAILED! (ioc %p, mf %p)\n",
21817a195f46SPrakash, Sathya 				    ioc->name, ioc, mf));
2182ea2a788dSKashyap, Desai 				mpt_clear_taskmgmt_in_progress_flag(ioc);
21831da177e4SLinus Torvalds 				rc = -ENODATA;
2184ea2a788dSKashyap, Desai 				mutex_unlock(&ioc->taskmgmt_cmds.mutex);
21851da177e4SLinus Torvalds 				goto done_free_mem;
21861da177e4SLinus Torvalds 			}
21877a195f46SPrakash, Sathya 		}
21881da177e4SLinus Torvalds 
21891da177e4SLinus Torvalds 	} else
21901da177e4SLinus Torvalds 		mpt_put_msg_frame(mptctl_id, ioc, mf);
21911da177e4SLinus Torvalds 
21921da177e4SLinus Torvalds 	/* Now wait for the command to complete */
21931da177e4SLinus Torvalds 	timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
2194ea2a788dSKashyap, Desai retry_wait:
2195ea2a788dSKashyap, Desai 	timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
21961da177e4SLinus Torvalds 				HZ*timeout);
2197ea2a788dSKashyap, Desai 	if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2198ea2a788dSKashyap, Desai 		rc = -ETIME;
2199ea2a788dSKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n",
2200ea2a788dSKashyap, Desai 		    ioc->name, __func__));
2201ea2a788dSKashyap, Desai 		if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2202ea2a788dSKashyap, Desai 			if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2203ea2a788dSKashyap, Desai 				mutex_unlock(&ioc->taskmgmt_cmds.mutex);
22041da177e4SLinus Torvalds 			goto done_free_mem;
22051da177e4SLinus Torvalds 		}
2206ea2a788dSKashyap, Desai 		if (!timeleft) {
220797009a29SKei Tokunaga 			printk(MYIOC_s_WARN_FMT
220897009a29SKei Tokunaga 			       "mpt cmd timeout, doorbell=0x%08x"
220997009a29SKei Tokunaga 			       " function=0x%x\n",
221097009a29SKei Tokunaga 			       ioc->name, mpt_GetIocState(ioc, 0), function);
2211ea2a788dSKashyap, Desai 			if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2212ea2a788dSKashyap, Desai 				mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2213ea2a788dSKashyap, Desai 			mptctl_timeout_expired(ioc, mf);
2214ea2a788dSKashyap, Desai 			mf = NULL;
2215ea2a788dSKashyap, Desai 		} else
2216ea2a788dSKashyap, Desai 			goto retry_wait;
2217ea2a788dSKashyap, Desai 		goto done_free_mem;
2218ea2a788dSKashyap, Desai 	}
2219ea2a788dSKashyap, Desai 
2220ea2a788dSKashyap, Desai 	if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2221ea2a788dSKashyap, Desai 		mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2222ea2a788dSKashyap, Desai 
22231da177e4SLinus Torvalds 
22241da177e4SLinus Torvalds 	mf = NULL;
22251da177e4SLinus Torvalds 
22261da177e4SLinus Torvalds 	/* If a valid reply frame, copy to the user.
22271da177e4SLinus Torvalds 	 * Offset 2: reply length in U32's
22281da177e4SLinus Torvalds 	 */
2229ea2a788dSKashyap, Desai 	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
22301da177e4SLinus Torvalds 		if (karg.maxReplyBytes < ioc->reply_sz) {
2231ea2a788dSKashyap, Desai 			sz = min(karg.maxReplyBytes,
2232ea2a788dSKashyap, Desai 				4*ioc->ioctl_cmds.reply[2]);
22331da177e4SLinus Torvalds 		} else {
2234ea2a788dSKashyap, Desai 			 sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]);
22351da177e4SLinus Torvalds 		}
22361da177e4SLinus Torvalds 		if (sz > 0) {
22371da177e4SLinus Torvalds 			if (copy_to_user(karg.replyFrameBufPtr,
2238ea2a788dSKashyap, Desai 				 ioc->ioctl_cmds.reply, sz)){
223929dd3609SEric Moore 				 printk(MYIOC_s_ERR_FMT
22401da177e4SLinus Torvalds 				     "%s@%d::mptctl_do_mpt_command - "
22411da177e4SLinus Torvalds 				 "Unable to write out reply frame %p\n",
224229dd3609SEric Moore 				 ioc->name, __FILE__, __LINE__, karg.replyFrameBufPtr);
22431da177e4SLinus Torvalds 				 rc =  -ENODATA;
22441da177e4SLinus Torvalds 				 goto done_free_mem;
22451da177e4SLinus Torvalds 			}
22461da177e4SLinus Torvalds 		}
22471da177e4SLinus Torvalds 	}
22481da177e4SLinus Torvalds 
22491da177e4SLinus Torvalds 	/* If valid sense data, copy to user.
22501da177e4SLinus Torvalds 	 */
2251ea2a788dSKashyap, Desai 	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) {
22521da177e4SLinus Torvalds 		sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
22531da177e4SLinus Torvalds 		if (sz > 0) {
2254ea2a788dSKashyap, Desai 			if (copy_to_user(karg.senseDataPtr,
2255ea2a788dSKashyap, Desai 				ioc->ioctl_cmds.sense, sz)) {
225629dd3609SEric Moore 				printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
22571da177e4SLinus Torvalds 				"Unable to write sense data to user %p\n",
225829dd3609SEric Moore 				ioc->name, __FILE__, __LINE__,
22591da177e4SLinus Torvalds 				karg.senseDataPtr);
22601da177e4SLinus Torvalds 				rc =  -ENODATA;
22611da177e4SLinus Torvalds 				goto done_free_mem;
22621da177e4SLinus Torvalds 			}
22631da177e4SLinus Torvalds 		}
22641da177e4SLinus Torvalds 	}
22651da177e4SLinus Torvalds 
22661da177e4SLinus Torvalds 	/* If the overall status is _GOOD and data in, copy data
22671da177e4SLinus Torvalds 	 * to user.
22681da177e4SLinus Torvalds 	 */
2269ea2a788dSKashyap, Desai 	if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) &&
22701da177e4SLinus Torvalds 				(karg.dataInSize > 0) && (bufIn.kptr)) {
22711da177e4SLinus Torvalds 
22721da177e4SLinus Torvalds 		if (copy_to_user(karg.dataInBufPtr,
22731da177e4SLinus Torvalds 				 bufIn.kptr, karg.dataInSize)) {
227429dd3609SEric Moore 			printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
22751da177e4SLinus Torvalds 				"Unable to write data to user %p\n",
227629dd3609SEric Moore 				ioc->name, __FILE__, __LINE__,
22771da177e4SLinus Torvalds 				karg.dataInBufPtr);
22781da177e4SLinus Torvalds 			rc =  -ENODATA;
22791da177e4SLinus Torvalds 		}
22801da177e4SLinus Torvalds 	}
22811da177e4SLinus Torvalds 
22821da177e4SLinus Torvalds done_free_mem:
22831da177e4SLinus Torvalds 
2284ea2a788dSKashyap, Desai 	CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
2285ea2a788dSKashyap, Desai 	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
22861da177e4SLinus Torvalds 
22871da177e4SLinus Torvalds 	/* Free the allocated memory.
22881da177e4SLinus Torvalds 	 */
22891da177e4SLinus Torvalds 	if (bufOut.kptr != NULL) {
2290b114dda6SChristophe JAILLET 		dma_free_coherent(&ioc->pcidev->dev, bufOut.len,
2291b114dda6SChristophe JAILLET 				  (void *)bufOut.kptr, dma_addr_out);
22921da177e4SLinus Torvalds 	}
22931da177e4SLinus Torvalds 
22941da177e4SLinus Torvalds 	if (bufIn.kptr != NULL) {
2295b114dda6SChristophe JAILLET 		dma_free_coherent(&ioc->pcidev->dev, bufIn.len,
2296b114dda6SChristophe JAILLET 				  (void *)bufIn.kptr, dma_addr_in);
22971da177e4SLinus Torvalds 	}
22981da177e4SLinus Torvalds 
22991da177e4SLinus Torvalds 	/* mf is null if command issued successfully
230025985edcSLucas De Marchi 	 * otherwise, failure occurred after mf acquired.
23011da177e4SLinus Torvalds 	 */
23021da177e4SLinus Torvalds 	if (mf)
23031da177e4SLinus Torvalds 		mpt_free_msg_frame(ioc, mf);
23041da177e4SLinus Torvalds 
23051da177e4SLinus Torvalds 	return rc;
23061da177e4SLinus Torvalds }
23071da177e4SLinus Torvalds 
23081da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2309ba856d32SEric Moore /* Prototype Routine for the HOST INFO command.
23101da177e4SLinus Torvalds  *
23111da177e4SLinus Torvalds  * Outputs:	None.
23121da177e4SLinus Torvalds  * Return:	0 if successful
23131da177e4SLinus Torvalds  *		-EFAULT if data unavailable
2314fc1323bbSJoe Perches  *		-EBUSY  if previous command timeout and IOC reset is not complete.
23151da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
23161da177e4SLinus Torvalds  *		-ETIME	if timer expires
23171da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
23181da177e4SLinus Torvalds  */
23191da177e4SLinus Torvalds static int
mptctl_hp_hostinfo(MPT_ADAPTER * ioc,unsigned long arg,unsigned int data_size)232028d76df1SDan Carpenter mptctl_hp_hostinfo(MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size)
23211da177e4SLinus Torvalds {
23221da177e4SLinus Torvalds 	hp_host_info_t	__user *uarg = (void __user *) arg;
23231da177e4SLinus Torvalds 	struct pci_dev		*pdev;
2324592f9c2fSMoore, Eric 	char                    *pbuf=NULL;
23251da177e4SLinus Torvalds 	dma_addr_t		buf_dma;
23261da177e4SLinus Torvalds 	hp_host_info_t		karg;
23271da177e4SLinus Torvalds 	CONFIGPARMS		cfg;
23281da177e4SLinus Torvalds 	ConfigPageHeader_t	hdr;
23291da177e4SLinus Torvalds 	int			rc, cim_rev;
2330592f9c2fSMoore, Eric 	ToolboxIstwiReadWriteRequest_t	*IstwiRWRequest;
2331592f9c2fSMoore, Eric 	MPT_FRAME_HDR		*mf = NULL;
2332ea2a788dSKashyap, Desai 	unsigned long		timeleft;
233373d02c20STomas Henzl 	u32			msgcontext;
23341da177e4SLinus Torvalds 
23351da177e4SLinus Torvalds 	/* Reset long to int. Should affect IA64 and SPARC only
23361da177e4SLinus Torvalds 	 */
23371da177e4SLinus Torvalds 	if (data_size == sizeof(hp_host_info_t))
23381da177e4SLinus Torvalds 		cim_rev = 1;
23391da177e4SLinus Torvalds 	else if (data_size == sizeof(hp_host_info_rev0_t))
23401da177e4SLinus Torvalds 		cim_rev = 0;	/* obsolete */
23411da177e4SLinus Torvalds 	else
23421da177e4SLinus Torvalds 		return -EFAULT;
23431da177e4SLinus Torvalds 
23441da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
234529dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_host_info - "
23461da177e4SLinus Torvalds 			"Unable to read in hp_host_info struct @ %p\n",
23471da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
23481da177e4SLinus Torvalds 		return -EFAULT;
23491da177e4SLinus Torvalds 	}
23501da177e4SLinus Torvalds 
235109120a8cSPrakash, Sathya 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
235209120a8cSPrakash, Sathya 	    ioc->name));
23531da177e4SLinus Torvalds 
23541da177e4SLinus Torvalds 	/* Fill in the data and return the structure to the calling
23551da177e4SLinus Torvalds 	 * program
23561da177e4SLinus Torvalds 	 */
23571da177e4SLinus Torvalds 	pdev = (struct pci_dev *) ioc->pcidev;
23581da177e4SLinus Torvalds 
23591da177e4SLinus Torvalds 	karg.vendor = pdev->vendor;
23601da177e4SLinus Torvalds 	karg.device = pdev->device;
23611da177e4SLinus Torvalds 	karg.subsystem_id = pdev->subsystem_device;
23621da177e4SLinus Torvalds 	karg.subsystem_vendor = pdev->subsystem_vendor;
23631da177e4SLinus Torvalds 	karg.devfn = pdev->devfn;
23641da177e4SLinus Torvalds 	karg.bus = pdev->bus->number;
23651da177e4SLinus Torvalds 
23661da177e4SLinus Torvalds 	/* Save the SCSI host no. if
23671da177e4SLinus Torvalds 	 * SCSI driver loaded
23681da177e4SLinus Torvalds 	 */
23691da177e4SLinus Torvalds 	if (ioc->sh != NULL)
23701da177e4SLinus Torvalds 		karg.host_no = ioc->sh->host_no;
23711da177e4SLinus Torvalds 	else
23721da177e4SLinus Torvalds 		karg.host_no =  -1;
23731da177e4SLinus Torvalds 
2374332b4b2aSAndy Shevchenko 	/* Reformat the fw_version into a string */
2375332b4b2aSAndy Shevchenko 	snprintf(karg.fw_version, sizeof(karg.fw_version),
2376332b4b2aSAndy Shevchenko 		 "%.2hhu.%.2hhu.%.2hhu.%.2hhu",
2377332b4b2aSAndy Shevchenko 		 ioc->facts.FWVersion.Struct.Major,
2378332b4b2aSAndy Shevchenko 		 ioc->facts.FWVersion.Struct.Minor,
2379332b4b2aSAndy Shevchenko 		 ioc->facts.FWVersion.Struct.Unit,
2380332b4b2aSAndy Shevchenko 		 ioc->facts.FWVersion.Struct.Dev);
23811da177e4SLinus Torvalds 
23821da177e4SLinus Torvalds 	/* Issue a config request to get the device serial number
23831da177e4SLinus Torvalds 	 */
23841da177e4SLinus Torvalds 	hdr.PageVersion = 0;
23851da177e4SLinus Torvalds 	hdr.PageLength = 0;
23861da177e4SLinus Torvalds 	hdr.PageNumber = 0;
23871da177e4SLinus Torvalds 	hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
238869218ee5SChristoph Hellwig 	cfg.cfghdr.hdr = &hdr;
23891da177e4SLinus Torvalds 	cfg.physAddr = -1;
23901da177e4SLinus Torvalds 	cfg.pageAddr = 0;
23911da177e4SLinus Torvalds 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
23921da177e4SLinus Torvalds 	cfg.dir = 0;	/* read */
23931da177e4SLinus Torvalds 	cfg.timeout = 10;
23941da177e4SLinus Torvalds 
2395*4280a0a7SJustin Stitt 	strscpy_pad(karg.serial_number, " ", sizeof(karg.serial_number));
23961da177e4SLinus Torvalds 	if (mpt_config(ioc, &cfg) == 0) {
239769218ee5SChristoph Hellwig 		if (cfg.cfghdr.hdr->PageLength > 0) {
23981da177e4SLinus Torvalds 			/* Issue the second config page request */
23991da177e4SLinus Torvalds 			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
24001da177e4SLinus Torvalds 
2401706dc3b9SChristophe JAILLET 			pbuf = dma_alloc_coherent(&ioc->pcidev->dev,
2402706dc3b9SChristophe JAILLET 						  hdr.PageLength * 4,
2403706dc3b9SChristophe JAILLET 						  &buf_dma, GFP_KERNEL);
24041da177e4SLinus Torvalds 			if (pbuf) {
24051da177e4SLinus Torvalds 				cfg.physAddr = buf_dma;
24061da177e4SLinus Torvalds 				if (mpt_config(ioc, &cfg) == 0) {
24071da177e4SLinus Torvalds 					ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
24081da177e4SLinus Torvalds 					if (strlen(pdata->BoardTracerNumber) > 1) {
2409*4280a0a7SJustin Stitt 						strscpy_pad(karg.serial_number,
2410*4280a0a7SJustin Stitt 							pdata->BoardTracerNumber,
2411*4280a0a7SJustin Stitt 							sizeof(karg.serial_number));
24121da177e4SLinus Torvalds 					}
24131da177e4SLinus Torvalds 				}
2414b114dda6SChristophe JAILLET 				dma_free_coherent(&ioc->pcidev->dev,
2415b114dda6SChristophe JAILLET 						  hdr.PageLength * 4, pbuf,
2416b114dda6SChristophe JAILLET 						  buf_dma);
24171da177e4SLinus Torvalds 				pbuf = NULL;
24181da177e4SLinus Torvalds 			}
24191da177e4SLinus Torvalds 		}
24201da177e4SLinus Torvalds 	}
24211da177e4SLinus Torvalds 	rc = mpt_GetIocState(ioc, 1);
24221da177e4SLinus Torvalds 	switch (rc) {
24231da177e4SLinus Torvalds 	case MPI_IOC_STATE_OPERATIONAL:
24241da177e4SLinus Torvalds 		karg.ioc_status =  HP_STATUS_OK;
24251da177e4SLinus Torvalds 		break;
24261da177e4SLinus Torvalds 
24271da177e4SLinus Torvalds 	case MPI_IOC_STATE_FAULT:
24281da177e4SLinus Torvalds 		karg.ioc_status =  HP_STATUS_FAILED;
24291da177e4SLinus Torvalds 		break;
24301da177e4SLinus Torvalds 
24311da177e4SLinus Torvalds 	case MPI_IOC_STATE_RESET:
24321da177e4SLinus Torvalds 	case MPI_IOC_STATE_READY:
24331da177e4SLinus Torvalds 	default:
24341da177e4SLinus Torvalds 		karg.ioc_status =  HP_STATUS_OTHER;
24351da177e4SLinus Torvalds 		break;
24361da177e4SLinus Torvalds 	}
24371da177e4SLinus Torvalds 
24381da177e4SLinus Torvalds 	karg.base_io_addr = pci_resource_start(pdev, 0);
24391da177e4SLinus Torvalds 
24409cc1cfbcSMoore, Eric 	if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
24411da177e4SLinus Torvalds 		karg.bus_phys_width = HP_BUS_WIDTH_UNK;
24421da177e4SLinus Torvalds 	else
24431da177e4SLinus Torvalds 		karg.bus_phys_width = HP_BUS_WIDTH_16;
24441da177e4SLinus Torvalds 
24451da177e4SLinus Torvalds 	karg.hard_resets = 0;
24461da177e4SLinus Torvalds 	karg.soft_resets = 0;
24471da177e4SLinus Torvalds 	karg.timeouts = 0;
24481da177e4SLinus Torvalds 	if (ioc->sh != NULL) {
2449e7eae9f6SEric Moore 		MPT_SCSI_HOST *hd =  shost_priv(ioc->sh);
24501da177e4SLinus Torvalds 
24511da177e4SLinus Torvalds 		if (hd && (cim_rev == 1)) {
24522f187862SKashyap, Desai 			karg.hard_resets = ioc->hard_resets;
24532f187862SKashyap, Desai 			karg.soft_resets = ioc->soft_resets;
24542f187862SKashyap, Desai 			karg.timeouts = ioc->timeouts;
24551da177e4SLinus Torvalds 		}
24561da177e4SLinus Torvalds 	}
24571da177e4SLinus Torvalds 
2458592f9c2fSMoore, Eric 	/*
2459592f9c2fSMoore, Eric 	 * Gather ISTWI(Industry Standard Two Wire Interface) Data
2460592f9c2fSMoore, Eric 	 */
2461592f9c2fSMoore, Eric 	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
2462ea2a788dSKashyap, Desai 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
2463ea2a788dSKashyap, Desai 			"%s, no msg frames!!\n", ioc->name, __func__));
2464592f9c2fSMoore, Eric 		goto out;
2465592f9c2fSMoore, Eric 	}
2466592f9c2fSMoore, Eric 
2467592f9c2fSMoore, Eric 	IstwiRWRequest = (ToolboxIstwiReadWriteRequest_t *)mf;
246873d02c20STomas Henzl 	msgcontext = IstwiRWRequest->MsgContext;
2469592f9c2fSMoore, Eric 	memset(IstwiRWRequest,0,sizeof(ToolboxIstwiReadWriteRequest_t));
247073d02c20STomas Henzl 	IstwiRWRequest->MsgContext = msgcontext;
2471592f9c2fSMoore, Eric 	IstwiRWRequest->Function = MPI_FUNCTION_TOOLBOX;
2472592f9c2fSMoore, Eric 	IstwiRWRequest->Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL;
2473592f9c2fSMoore, Eric 	IstwiRWRequest->Flags = MPI_TB_ISTWI_FLAGS_READ;
2474592f9c2fSMoore, Eric 	IstwiRWRequest->NumAddressBytes = 0x01;
2475592f9c2fSMoore, Eric 	IstwiRWRequest->DataLength = cpu_to_le16(0x04);
2476592f9c2fSMoore, Eric 	if (pdev->devfn & 1)
2477592f9c2fSMoore, Eric 		IstwiRWRequest->DeviceAddr = 0xB2;
2478592f9c2fSMoore, Eric 	else
2479592f9c2fSMoore, Eric 		IstwiRWRequest->DeviceAddr = 0xB0;
2480592f9c2fSMoore, Eric 
2481706dc3b9SChristophe JAILLET 	pbuf = dma_alloc_coherent(&ioc->pcidev->dev, 4, &buf_dma, GFP_KERNEL);
2482592f9c2fSMoore, Eric 	if (!pbuf)
2483592f9c2fSMoore, Eric 		goto out;
248414d0f0b0SKashyap, Desai 	ioc->add_sge((char *)&IstwiRWRequest->SGL,
2485592f9c2fSMoore, Eric 	    (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
2486592f9c2fSMoore, Eric 
2487ea2a788dSKashyap, Desai 	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
2488ea2a788dSKashyap, Desai 				IstwiRWRequest->MsgContext);
2489ea2a788dSKashyap, Desai 	INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
2490592f9c2fSMoore, Eric 	mpt_put_msg_frame(mptctl_id, ioc, mf);
2491592f9c2fSMoore, Eric 
2492ea2a788dSKashyap, Desai retry_wait:
2493ea2a788dSKashyap, Desai 	timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
2494ea2a788dSKashyap, Desai 			HZ*MPT_IOCTL_DEFAULT_TIMEOUT);
2495ea2a788dSKashyap, Desai 	if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2496ea2a788dSKashyap, Desai 		printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __func__);
2497ea2a788dSKashyap, Desai 		if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2498592f9c2fSMoore, Eric 			mpt_free_msg_frame(ioc, mf);
2499ea2a788dSKashyap, Desai 			goto out;
2500ea2a788dSKashyap, Desai 		}
250197009a29SKei Tokunaga 		if (!timeleft) {
250297009a29SKei Tokunaga 			printk(MYIOC_s_WARN_FMT
250397009a29SKei Tokunaga 			       "HOST INFO command timeout, doorbell=0x%08x\n",
250497009a29SKei Tokunaga 			       ioc->name, mpt_GetIocState(ioc, 0));
2505ea2a788dSKashyap, Desai 			mptctl_timeout_expired(ioc, mf);
250697009a29SKei Tokunaga 		} else
2507ea2a788dSKashyap, Desai 			goto retry_wait;
2508592f9c2fSMoore, Eric 		goto out;
2509592f9c2fSMoore, Eric 	}
2510592f9c2fSMoore, Eric 
2511592f9c2fSMoore, Eric 	/*
2512592f9c2fSMoore, Eric 	 *ISTWI Data Definition
2513592f9c2fSMoore, Eric 	 * pbuf[0] = FW_VERSION = 0x4
2514592f9c2fSMoore, Eric 	 * pbuf[1] = Bay Count = 6 or 4 or 2, depending on
2515592f9c2fSMoore, Eric 	 *  the config, you should be seeing one out of these three values
2516592f9c2fSMoore, Eric 	 * pbuf[2] = Drive Installed Map = bit pattern depend on which
2517592f9c2fSMoore, Eric 	 *   bays have drives in them
2518592f9c2fSMoore, Eric 	 * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3)
2519592f9c2fSMoore, Eric 	 */
2520ea2a788dSKashyap, Desai 	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)
25211da177e4SLinus Torvalds 		karg.rsvd = *(u32 *)pbuf;
2522592f9c2fSMoore, Eric 
2523592f9c2fSMoore, Eric  out:
2524ea2a788dSKashyap, Desai 	CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
2525ea2a788dSKashyap, Desai 	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
2526ea2a788dSKashyap, Desai 
2527592f9c2fSMoore, Eric 	if (pbuf)
2528b114dda6SChristophe JAILLET 		dma_free_coherent(&ioc->pcidev->dev, 4, pbuf, buf_dma);
25291da177e4SLinus Torvalds 
25301da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
25311da177e4SLinus Torvalds 	 */
25321da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) {
253329dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hpgethostinfo - "
25341da177e4SLinus Torvalds 			"Unable to write out hp_host_info @ %p\n",
253529dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, uarg);
25361da177e4SLinus Torvalds 		return -EFAULT;
25371da177e4SLinus Torvalds 	}
25381da177e4SLinus Torvalds 
25391da177e4SLinus Torvalds 	return 0;
25401da177e4SLinus Torvalds 
25411da177e4SLinus Torvalds }
25421da177e4SLinus Torvalds 
25431da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2544ba856d32SEric Moore /* Prototype Routine for the TARGET INFO command.
25451da177e4SLinus Torvalds  *
25461da177e4SLinus Torvalds  * Outputs:	None.
25471da177e4SLinus Torvalds  * Return:	0 if successful
25481da177e4SLinus Torvalds  *		-EFAULT if data unavailable
2549fc1323bbSJoe Perches  *		-EBUSY  if previous command timeout and IOC reset is not complete.
25501da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
25511da177e4SLinus Torvalds  *		-ETIME	if timer expires
25521da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
25531da177e4SLinus Torvalds  */
25541da177e4SLinus Torvalds static int
mptctl_hp_targetinfo(MPT_ADAPTER * ioc,unsigned long arg)255528d76df1SDan Carpenter mptctl_hp_targetinfo(MPT_ADAPTER *ioc, unsigned long arg)
25561da177e4SLinus Torvalds {
25571da177e4SLinus Torvalds 	hp_target_info_t __user *uarg = (void __user *) arg;
25581da177e4SLinus Torvalds 	SCSIDevicePage0_t	*pg0_alloc;
25591da177e4SLinus Torvalds 	SCSIDevicePage3_t	*pg3_alloc;
25601da177e4SLinus Torvalds 	MPT_SCSI_HOST 		*hd = NULL;
25611da177e4SLinus Torvalds 	hp_target_info_t	karg;
25621da177e4SLinus Torvalds 	int			data_sz;
25631da177e4SLinus Torvalds 	dma_addr_t		page_dma;
25641da177e4SLinus Torvalds 	CONFIGPARMS	 	cfg;
25651da177e4SLinus Torvalds 	ConfigPageHeader_t	hdr;
25661da177e4SLinus Torvalds 	int			tmp, np, rc = 0;
25671da177e4SLinus Torvalds 
25681da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
256929dd3609SEric Moore 		printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_targetinfo - "
25701da177e4SLinus Torvalds 			"Unable to read in hp_host_targetinfo struct @ %p\n",
25711da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
25721da177e4SLinus Torvalds 		return -EFAULT;
25731da177e4SLinus Torvalds 	}
25741da177e4SLinus Torvalds 
2575a7043e95SDan Carpenter 	if (karg.hdr.id >= MPT_MAX_FC_DEVICES)
2576a7043e95SDan Carpenter 		return -EINVAL;
257729dd3609SEric Moore 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
257809120a8cSPrakash, Sathya 	    ioc->name));
25791da177e4SLinus Torvalds 
25801da177e4SLinus Torvalds 	/*  There is nothing to do for FCP parts.
25811da177e4SLinus Torvalds 	 */
25829cc1cfbcSMoore, Eric 	if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
25831da177e4SLinus Torvalds 		return 0;
25841da177e4SLinus Torvalds 
25851da177e4SLinus Torvalds 	if ((ioc->spi_data.sdp0length == 0) || (ioc->sh == NULL))
25861da177e4SLinus Torvalds 		return 0;
25871da177e4SLinus Torvalds 
25881da177e4SLinus Torvalds 	if (ioc->sh->host_no != karg.hdr.host)
25891da177e4SLinus Torvalds 		return -ENODEV;
25901da177e4SLinus Torvalds 
25911da177e4SLinus Torvalds        /* Get the data transfer speeds
25921da177e4SLinus Torvalds         */
25931da177e4SLinus Torvalds 	data_sz = ioc->spi_data.sdp0length * 4;
2594706dc3b9SChristophe JAILLET 	pg0_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz, &page_dma,
2595706dc3b9SChristophe JAILLET 				       GFP_KERNEL);
25961da177e4SLinus Torvalds 	if (pg0_alloc) {
25971da177e4SLinus Torvalds 		hdr.PageVersion = ioc->spi_data.sdp0version;
25981da177e4SLinus Torvalds 		hdr.PageLength = data_sz;
25991da177e4SLinus Torvalds 		hdr.PageNumber = 0;
26001da177e4SLinus Torvalds 		hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
26011da177e4SLinus Torvalds 
260269218ee5SChristoph Hellwig 		cfg.cfghdr.hdr = &hdr;
26031da177e4SLinus Torvalds 		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
26041da177e4SLinus Torvalds 		cfg.dir = 0;
26051da177e4SLinus Torvalds 		cfg.timeout = 0;
26061da177e4SLinus Torvalds 		cfg.physAddr = page_dma;
26071da177e4SLinus Torvalds 
26081da177e4SLinus Torvalds 		cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
26091da177e4SLinus Torvalds 
26101da177e4SLinus Torvalds 		if ((rc = mpt_config(ioc, &cfg)) == 0) {
26111da177e4SLinus Torvalds 			np = le32_to_cpu(pg0_alloc->NegotiatedParameters);
26121da177e4SLinus Torvalds 			karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ?
26131da177e4SLinus Torvalds 					HP_BUS_WIDTH_16 : HP_BUS_WIDTH_8;
26141da177e4SLinus Torvalds 
26151da177e4SLinus Torvalds 			if (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) {
26161da177e4SLinus Torvalds 				tmp = (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
26171da177e4SLinus Torvalds 				if (tmp < 0x09)
26181da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA320;
26191da177e4SLinus Torvalds 				else if (tmp <= 0x09)
26201da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA160;
26211da177e4SLinus Torvalds 				else if (tmp <= 0x0A)
26221da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA2;
26231da177e4SLinus Torvalds 				else if (tmp <= 0x0C)
26241da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA;
26251da177e4SLinus Torvalds 				else if (tmp <= 0x25)
26261da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_FAST;
26271da177e4SLinus Torvalds 				else
26281da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
26291da177e4SLinus Torvalds 			} else
26301da177e4SLinus Torvalds 				karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
26311da177e4SLinus Torvalds 		}
26321da177e4SLinus Torvalds 
2633b114dda6SChristophe JAILLET 		dma_free_coherent(&ioc->pcidev->dev, data_sz, (u8 *)pg0_alloc,
2634b114dda6SChristophe JAILLET 				  page_dma);
26351da177e4SLinus Torvalds 	}
26361da177e4SLinus Torvalds 
26371da177e4SLinus Torvalds 	/* Set defaults
26381da177e4SLinus Torvalds 	 */
26391da177e4SLinus Torvalds 	karg.message_rejects = -1;
26401da177e4SLinus Torvalds 	karg.phase_errors = -1;
26411da177e4SLinus Torvalds 	karg.parity_errors = -1;
26421da177e4SLinus Torvalds 	karg.select_timeouts = -1;
26431da177e4SLinus Torvalds 
26441da177e4SLinus Torvalds 	/* Get the target error parameters
26451da177e4SLinus Torvalds 	 */
26461da177e4SLinus Torvalds 	hdr.PageVersion = 0;
26471da177e4SLinus Torvalds 	hdr.PageLength = 0;
26481da177e4SLinus Torvalds 	hdr.PageNumber = 3;
26491da177e4SLinus Torvalds 	hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
26501da177e4SLinus Torvalds 
265169218ee5SChristoph Hellwig 	cfg.cfghdr.hdr = &hdr;
26521da177e4SLinus Torvalds 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
26531da177e4SLinus Torvalds 	cfg.dir = 0;
26541da177e4SLinus Torvalds 	cfg.timeout = 0;
26551da177e4SLinus Torvalds 	cfg.physAddr = -1;
265669218ee5SChristoph Hellwig 	if ((mpt_config(ioc, &cfg) == 0) && (cfg.cfghdr.hdr->PageLength > 0)) {
26571da177e4SLinus Torvalds 		/* Issue the second config page request */
26581da177e4SLinus Torvalds 		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
265969218ee5SChristoph Hellwig 		data_sz = (int) cfg.cfghdr.hdr->PageLength * 4;
2660706dc3b9SChristophe JAILLET 		pg3_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz,
2661706dc3b9SChristophe JAILLET 					       &page_dma, GFP_KERNEL);
26621da177e4SLinus Torvalds 		if (pg3_alloc) {
26631da177e4SLinus Torvalds 			cfg.physAddr = page_dma;
26641da177e4SLinus Torvalds 			cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
26651da177e4SLinus Torvalds 			if ((rc = mpt_config(ioc, &cfg)) == 0) {
26661da177e4SLinus Torvalds 				karg.message_rejects = (u32) le16_to_cpu(pg3_alloc->MsgRejectCount);
26671da177e4SLinus Torvalds 				karg.phase_errors = (u32) le16_to_cpu(pg3_alloc->PhaseErrorCount);
26681da177e4SLinus Torvalds 				karg.parity_errors = (u32) le16_to_cpu(pg3_alloc->ParityErrorCount);
26691da177e4SLinus Torvalds 			}
2670b114dda6SChristophe JAILLET 			dma_free_coherent(&ioc->pcidev->dev, data_sz,
2671b114dda6SChristophe JAILLET 					  (u8 *)pg3_alloc, page_dma);
26721da177e4SLinus Torvalds 		}
26731da177e4SLinus Torvalds 	}
2674e7eae9f6SEric Moore 	hd = shost_priv(ioc->sh);
26751da177e4SLinus Torvalds 	if (hd != NULL)
26761da177e4SLinus Torvalds 		karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
26771da177e4SLinus Torvalds 
26781da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
26791da177e4SLinus Torvalds 	 */
26801da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) {
268129dd3609SEric Moore 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hp_target_info - "
26821da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
268329dd3609SEric Moore 			ioc->name, __FILE__, __LINE__, uarg);
26841da177e4SLinus Torvalds 		return -EFAULT;
26851da177e4SLinus Torvalds 	}
26861da177e4SLinus Torvalds 
26871da177e4SLinus Torvalds 	return 0;
26881da177e4SLinus Torvalds }
26891da177e4SLinus Torvalds 
26901da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26911da177e4SLinus Torvalds 
2692fa027c2aSArjan van de Ven static const struct file_operations mptctl_fops = {
26931da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
26941da177e4SLinus Torvalds 	.llseek =	no_llseek,
2695ea5a7a82SMoore, Eric 	.fasync = 	mptctl_fasync,
26961da177e4SLinus Torvalds 	.unlocked_ioctl = mptctl_ioctl,
26971da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
26981da177e4SLinus Torvalds 	.compat_ioctl = compat_mpctl_ioctl,
26991da177e4SLinus Torvalds #endif
27001da177e4SLinus Torvalds };
27011da177e4SLinus Torvalds 
27021da177e4SLinus Torvalds static struct miscdevice mptctl_miscdev = {
27031da177e4SLinus Torvalds 	MPT_MINOR,
27041da177e4SLinus Torvalds 	MYNAM,
27051da177e4SLinus Torvalds 	&mptctl_fops
27061da177e4SLinus Torvalds };
27071da177e4SLinus Torvalds 
27081da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
27091da177e4SLinus Torvalds 
27101da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
27111da177e4SLinus Torvalds 
27121da177e4SLinus Torvalds static int
compat_mptfwxfer_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)27131da177e4SLinus Torvalds compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
27141da177e4SLinus Torvalds 			unsigned long arg)
27151da177e4SLinus Torvalds {
27161da177e4SLinus Torvalds 	struct mpt_fw_xfer32 kfw32;
27171da177e4SLinus Torvalds 	struct mpt_fw_xfer kfw;
27181da177e4SLinus Torvalds 	MPT_ADAPTER *iocp = NULL;
27191da177e4SLinus Torvalds 	int iocnum, iocnumX;
27201da177e4SLinus Torvalds 	int nonblock = (filp->f_flags & O_NONBLOCK);
27211da177e4SLinus Torvalds 	int ret;
27221da177e4SLinus Torvalds 
27231da177e4SLinus Torvalds 
27241da177e4SLinus Torvalds 	if (copy_from_user(&kfw32, (char __user *)arg, sizeof(kfw32)))
27251da177e4SLinus Torvalds 		return -EFAULT;
27261da177e4SLinus Torvalds 
27271da177e4SLinus Torvalds 	/* Verify intended MPT adapter */
27281da177e4SLinus Torvalds 	iocnumX = kfw32.iocnum & 0xFF;
27291da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
27301da177e4SLinus Torvalds 	    (iocp == NULL)) {
273109120a8cSPrakash, Sathya 		printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
273209120a8cSPrakash, Sathya 			__LINE__, iocnumX);
27331da177e4SLinus Torvalds 		return -ENODEV;
27341da177e4SLinus Torvalds 	}
27351da177e4SLinus Torvalds 
27361da177e4SLinus Torvalds 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
27371da177e4SLinus Torvalds 		return ret;
27381da177e4SLinus Torvalds 
273909120a8cSPrakash, Sathya 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mptfwxfer_ioctl() called\n",
274009120a8cSPrakash, Sathya 	    iocp->name));
27411da177e4SLinus Torvalds 	kfw.iocnum = iocnum;
27421da177e4SLinus Torvalds 	kfw.fwlen = kfw32.fwlen;
27431da177e4SLinus Torvalds 	kfw.bufp = compat_ptr(kfw32.bufp);
27441da177e4SLinus Torvalds 
274528d76df1SDan Carpenter 	ret = mptctl_do_fw_download(iocp, kfw.bufp, kfw.fwlen);
27461da177e4SLinus Torvalds 
2747ea2a788dSKashyap, Desai 	mutex_unlock(&iocp->ioctl_cmds.mutex);
27481da177e4SLinus Torvalds 
27491da177e4SLinus Torvalds 	return ret;
27501da177e4SLinus Torvalds }
27511da177e4SLinus Torvalds 
27521da177e4SLinus Torvalds static int
compat_mpt_command(struct file * filp,unsigned int cmd,unsigned long arg)27531da177e4SLinus Torvalds compat_mpt_command(struct file *filp, unsigned int cmd,
27541da177e4SLinus Torvalds 			unsigned long arg)
27551da177e4SLinus Torvalds {
27561da177e4SLinus Torvalds 	struct mpt_ioctl_command32 karg32;
27571da177e4SLinus Torvalds 	struct mpt_ioctl_command32 __user *uarg = (struct mpt_ioctl_command32 __user *) arg;
27581da177e4SLinus Torvalds 	struct mpt_ioctl_command karg;
27591da177e4SLinus Torvalds 	MPT_ADAPTER *iocp = NULL;
27601da177e4SLinus Torvalds 	int iocnum, iocnumX;
27611da177e4SLinus Torvalds 	int nonblock = (filp->f_flags & O_NONBLOCK);
27621da177e4SLinus Torvalds 	int ret;
27631da177e4SLinus Torvalds 
27641da177e4SLinus Torvalds 	if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32)))
27651da177e4SLinus Torvalds 		return -EFAULT;
27661da177e4SLinus Torvalds 
27671da177e4SLinus Torvalds 	/* Verify intended MPT adapter */
27681da177e4SLinus Torvalds 	iocnumX = karg32.hdr.iocnum & 0xFF;
27691da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
27701da177e4SLinus Torvalds 	    (iocp == NULL)) {
277109120a8cSPrakash, Sathya 		printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
277209120a8cSPrakash, Sathya 			__LINE__, iocnumX);
27731da177e4SLinus Torvalds 		return -ENODEV;
27741da177e4SLinus Torvalds 	}
27751da177e4SLinus Torvalds 
27761da177e4SLinus Torvalds 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
27771da177e4SLinus Torvalds 		return ret;
27781da177e4SLinus Torvalds 
277909120a8cSPrakash, Sathya 	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mpt_command() called\n",
278009120a8cSPrakash, Sathya 	    iocp->name));
27811da177e4SLinus Torvalds 	/* Copy data to karg */
27821da177e4SLinus Torvalds 	karg.hdr.iocnum = karg32.hdr.iocnum;
27831da177e4SLinus Torvalds 	karg.hdr.port = karg32.hdr.port;
27841da177e4SLinus Torvalds 	karg.timeout = karg32.timeout;
27851da177e4SLinus Torvalds 	karg.maxReplyBytes = karg32.maxReplyBytes;
27861da177e4SLinus Torvalds 
27871da177e4SLinus Torvalds 	karg.dataInSize = karg32.dataInSize;
27881da177e4SLinus Torvalds 	karg.dataOutSize = karg32.dataOutSize;
27891da177e4SLinus Torvalds 	karg.maxSenseBytes = karg32.maxSenseBytes;
27901da177e4SLinus Torvalds 	karg.dataSgeOffset = karg32.dataSgeOffset;
27911da177e4SLinus Torvalds 
27921da177e4SLinus Torvalds 	karg.replyFrameBufPtr = (char __user *)(unsigned long)karg32.replyFrameBufPtr;
27931da177e4SLinus Torvalds 	karg.dataInBufPtr = (char __user *)(unsigned long)karg32.dataInBufPtr;
27941da177e4SLinus Torvalds 	karg.dataOutBufPtr = (char __user *)(unsigned long)karg32.dataOutBufPtr;
27951da177e4SLinus Torvalds 	karg.senseDataPtr = (char __user *)(unsigned long)karg32.senseDataPtr;
27961da177e4SLinus Torvalds 
27971da177e4SLinus Torvalds 	/* Pass new structure to do_mpt_command
27981da177e4SLinus Torvalds 	 */
279928d76df1SDan Carpenter 	ret = mptctl_do_mpt_command (iocp, karg, &uarg->MF);
28001da177e4SLinus Torvalds 
2801ea2a788dSKashyap, Desai 	mutex_unlock(&iocp->ioctl_cmds.mutex);
28021da177e4SLinus Torvalds 
28031da177e4SLinus Torvalds 	return ret;
28041da177e4SLinus Torvalds }
28051da177e4SLinus Torvalds 
compat_mpctl_ioctl(struct file * f,unsigned int cmd,unsigned long arg)28061da177e4SLinus Torvalds static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
28071da177e4SLinus Torvalds {
28081da177e4SLinus Torvalds 	long ret;
2809c45d15d2SArnd Bergmann 	mutex_lock(&mpctl_mutex);
28101da177e4SLinus Torvalds 	switch (cmd) {
28111da177e4SLinus Torvalds 	case MPTIOCINFO:
28121da177e4SLinus Torvalds 	case MPTIOCINFO1:
28131da177e4SLinus Torvalds 	case MPTIOCINFO2:
28141da177e4SLinus Torvalds 	case MPTTARGETINFO:
28151da177e4SLinus Torvalds 	case MPTEVENTQUERY:
28161da177e4SLinus Torvalds 	case MPTEVENTENABLE:
28171da177e4SLinus Torvalds 	case MPTEVENTREPORT:
28181da177e4SLinus Torvalds 	case MPTHARDRESET:
28191da177e4SLinus Torvalds 	case HP_GETHOSTINFO:
28201da177e4SLinus Torvalds 	case HP_GETTARGETINFO:
28211da177e4SLinus Torvalds 	case MPTTEST:
28221da177e4SLinus Torvalds 		ret = __mptctl_ioctl(f, cmd, arg);
28231da177e4SLinus Torvalds 		break;
28241da177e4SLinus Torvalds 	case MPTCOMMAND32:
28251da177e4SLinus Torvalds 		ret = compat_mpt_command(f, cmd, arg);
28261da177e4SLinus Torvalds 		break;
28271da177e4SLinus Torvalds 	case MPTFWDOWNLOAD32:
28281da177e4SLinus Torvalds 		ret = compat_mptfwxfer_ioctl(f, cmd, arg);
28291da177e4SLinus Torvalds 		break;
28301da177e4SLinus Torvalds 	default:
28311da177e4SLinus Torvalds 		ret = -ENOIOCTLCMD;
28321da177e4SLinus Torvalds 		break;
28331da177e4SLinus Torvalds 	}
2834c45d15d2SArnd Bergmann 	mutex_unlock(&mpctl_mutex);
28351da177e4SLinus Torvalds 	return ret;
28361da177e4SLinus Torvalds }
28371da177e4SLinus Torvalds 
28381da177e4SLinus Torvalds #endif
28391da177e4SLinus Torvalds 
28401da177e4SLinus Torvalds 
28411da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
28421da177e4SLinus Torvalds /*
28431da177e4SLinus Torvalds  *	mptctl_probe - Installs ioctl devices per bus.
28441da177e4SLinus Torvalds  *	@pdev: Pointer to pci_dev structure
28451da177e4SLinus Torvalds  *
28461da177e4SLinus Torvalds  *	Returns 0 for success, non-zero for failure.
28471da177e4SLinus Torvalds  *
28481da177e4SLinus Torvalds  */
28491da177e4SLinus Torvalds 
28501da177e4SLinus Torvalds static int
mptctl_probe(struct pci_dev * pdev)2851a534ff3fSUwe Kleine-König mptctl_probe(struct pci_dev *pdev)
28521da177e4SLinus Torvalds {
28531da177e4SLinus Torvalds 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
28541da177e4SLinus Torvalds 
2855ea2a788dSKashyap, Desai 	mutex_init(&ioc->ioctl_cmds.mutex);
2856ea2a788dSKashyap, Desai 	init_completion(&ioc->ioctl_cmds.done);
28571da177e4SLinus Torvalds 	return 0;
28581da177e4SLinus Torvalds }
28591da177e4SLinus Torvalds 
28601da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
28611da177e4SLinus Torvalds /*
28621da177e4SLinus Torvalds  *	mptctl_remove - Removed ioctl devices
28631da177e4SLinus Torvalds  *	@pdev: Pointer to pci_dev structure
28641da177e4SLinus Torvalds  *
28651da177e4SLinus Torvalds  *
28661da177e4SLinus Torvalds  */
28671da177e4SLinus Torvalds static void
mptctl_remove(struct pci_dev * pdev)28681da177e4SLinus Torvalds mptctl_remove(struct pci_dev *pdev)
28691da177e4SLinus Torvalds {
28701da177e4SLinus Torvalds }
28711da177e4SLinus Torvalds 
28721da177e4SLinus Torvalds static struct mpt_pci_driver mptctl_driver = {
28731da177e4SLinus Torvalds   .probe		= mptctl_probe,
28741da177e4SLinus Torvalds   .remove		= mptctl_remove,
28751da177e4SLinus Torvalds };
28761da177e4SLinus Torvalds 
28771da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
mptctl_init(void)28781da177e4SLinus Torvalds static int __init mptctl_init(void)
28791da177e4SLinus Torvalds {
28801da177e4SLinus Torvalds 	int err;
28811da177e4SLinus Torvalds 
28821da177e4SLinus Torvalds 	show_mptmod_ver(my_NAME, my_VERSION);
28831da177e4SLinus Torvalds 
288409120a8cSPrakash, Sathya 	mpt_device_driver_register(&mptctl_driver, MPTCTL_DRIVER);
28851da177e4SLinus Torvalds 
28861da177e4SLinus Torvalds 	/* Register this device */
28871da177e4SLinus Torvalds 	err = misc_register(&mptctl_miscdev);
28881da177e4SLinus Torvalds 	if (err < 0) {
28891da177e4SLinus Torvalds 		printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
28901da177e4SLinus Torvalds 		goto out_fail;
28911da177e4SLinus Torvalds 	}
28921da177e4SLinus Torvalds 	printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
28931da177e4SLinus Torvalds 	printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
28941da177e4SLinus Torvalds 			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
28951da177e4SLinus Torvalds 
28961da177e4SLinus Torvalds 	/*
28971da177e4SLinus Torvalds 	 *  Install our handler
28981da177e4SLinus Torvalds 	 */
2899213aaca3SKashyap, Desai 	mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER,
2900213aaca3SKashyap, Desai 	    "mptctl_reply");
2901f606f571SPrakash, Sathya 	if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) {
29021da177e4SLinus Torvalds 		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
29031da177e4SLinus Torvalds 		misc_deregister(&mptctl_miscdev);
29041da177e4SLinus Torvalds 		err = -EBUSY;
29051da177e4SLinus Torvalds 		goto out_fail;
29061da177e4SLinus Torvalds 	}
29071da177e4SLinus Torvalds 
2908213aaca3SKashyap, Desai 	mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER,
2909213aaca3SKashyap, Desai 	    "mptctl_taskmgmt_reply");
291065c054f2SKei Tokunaga 	if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) {
291165c054f2SKei Tokunaga 		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
291265c054f2SKei Tokunaga 		mpt_deregister(mptctl_id);
291365c054f2SKei Tokunaga 		misc_deregister(&mptctl_miscdev);
291465c054f2SKei Tokunaga 		err = -EBUSY;
291565c054f2SKei Tokunaga 		goto out_fail;
291665c054f2SKei Tokunaga 	}
291765c054f2SKei Tokunaga 
291809120a8cSPrakash, Sathya 	mpt_reset_register(mptctl_id, mptctl_ioc_reset);
291909120a8cSPrakash, Sathya 	mpt_event_register(mptctl_id, mptctl_event_process);
2920ea5a7a82SMoore, Eric 
29211da177e4SLinus Torvalds 	return 0;
29221da177e4SLinus Torvalds 
29231da177e4SLinus Torvalds out_fail:
29241da177e4SLinus Torvalds 
29251da177e4SLinus Torvalds 	mpt_device_driver_deregister(MPTCTL_DRIVER);
29261da177e4SLinus Torvalds 
29271da177e4SLinus Torvalds 	return err;
29281da177e4SLinus Torvalds }
29291da177e4SLinus Torvalds 
29301da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
mptctl_exit(void)29311da177e4SLinus Torvalds static void mptctl_exit(void)
29321da177e4SLinus Torvalds {
29331da177e4SLinus Torvalds 	misc_deregister(&mptctl_miscdev);
29341da177e4SLinus Torvalds 	printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",
29351da177e4SLinus Torvalds 			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
29361da177e4SLinus Torvalds 
293765c054f2SKei Tokunaga 	/* De-register event handler from base module */
293865c054f2SKei Tokunaga 	mpt_event_deregister(mptctl_id);
293965c054f2SKei Tokunaga 
29401da177e4SLinus Torvalds 	/* De-register reset handler from base module */
29411da177e4SLinus Torvalds 	mpt_reset_deregister(mptctl_id);
29421da177e4SLinus Torvalds 
29431da177e4SLinus Torvalds 	/* De-register callback handler from base module */
294465c054f2SKei Tokunaga 	mpt_deregister(mptctl_taskmgmt_id);
29451da177e4SLinus Torvalds 	mpt_deregister(mptctl_id);
29461da177e4SLinus Torvalds 
29471da177e4SLinus Torvalds         mpt_device_driver_deregister(MPTCTL_DRIVER);
29481da177e4SLinus Torvalds 
29491da177e4SLinus Torvalds }
29501da177e4SLinus Torvalds 
29511da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
29521da177e4SLinus Torvalds 
29531da177e4SLinus Torvalds module_init(mptctl_init);
29541da177e4SLinus Torvalds module_exit(mptctl_exit);
2955