xref: /linux/drivers/message/fusion/mptctl.c (revision ba856d32f2cede67fd2a59a53bc662360f17c7b5)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/drivers/message/fusion/mptctl.c
3b6fe4ddcSMoore, Eric Dean   *      mpt Ioctl driver.
4b6fe4ddcSMoore, Eric Dean   *      For use with LSI Logic PCI chip/adapters
51da177e4SLinus Torvalds  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
61da177e4SLinus Torvalds  *
7b6fe4ddcSMoore, Eric Dean   *  Copyright (c) 1999-2005 LSI Logic Corporation
81da177e4SLinus Torvalds  *  (mailto:mpt_linux_developer@lsil.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>
571da177e4SLinus Torvalds #include <linux/smp_lock.h>
581da177e4SLinus Torvalds #include <linux/compat.h>
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds #include <asm/io.h>
611da177e4SLinus Torvalds #include <asm/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 
69b6fe4ddcSMoore, Eric Dean  #define COPYRIGHT	"Copyright (c) 1999-2005 LSI Logic Corporation"
70b6fe4ddcSMoore, Eric Dean  #define MODULEAUTHOR	"LSI Logic 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");
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds static int mptctl_id = -1;
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds struct buflist {
921da177e4SLinus Torvalds 	u8	*kptr;
931da177e4SLinus Torvalds 	int	 len;
941da177e4SLinus Torvalds };
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds /*
971da177e4SLinus Torvalds  * Function prototypes. Called from OS entry point mptctl_ioctl.
981da177e4SLinus Torvalds  * arg contents specific to function.
991da177e4SLinus Torvalds  */
1001da177e4SLinus Torvalds static int mptctl_fw_download(unsigned long arg);
1011da177e4SLinus Torvalds static int mptctl_getiocinfo(unsigned long arg, unsigned int cmd);
1021da177e4SLinus Torvalds static int mptctl_gettargetinfo(unsigned long arg);
1031da177e4SLinus Torvalds static int mptctl_readtest(unsigned long arg);
1041da177e4SLinus Torvalds static int mptctl_mpt_command(unsigned long arg);
1051da177e4SLinus Torvalds static int mptctl_eventquery(unsigned long arg);
1061da177e4SLinus Torvalds static int mptctl_eventenable(unsigned long arg);
1071da177e4SLinus Torvalds static int mptctl_eventreport(unsigned long arg);
1081da177e4SLinus Torvalds static int mptctl_replace_fw(unsigned long arg);
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds static int mptctl_do_reset(unsigned long arg);
1111da177e4SLinus Torvalds static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd);
1121da177e4SLinus Torvalds static int mptctl_hp_targetinfo(unsigned long arg);
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds static int  mptctl_probe(struct pci_dev *, const struct pci_device_id *);
1151da177e4SLinus Torvalds static void mptctl_remove(struct pci_dev *);
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
1181da177e4SLinus Torvalds static long compat_mpctl_ioctl(struct file *f, unsigned cmd, unsigned long arg);
1191da177e4SLinus Torvalds #endif
1201da177e4SLinus Torvalds /*
1211da177e4SLinus Torvalds  * Private function calls.
1221da177e4SLinus Torvalds  */
1231da177e4SLinus Torvalds static int mptctl_do_mpt_command(struct mpt_ioctl_command karg, void __user *mfPtr);
1241da177e4SLinus Torvalds static int mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen);
1251da177e4SLinus Torvalds static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags,
1261da177e4SLinus Torvalds 		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
1271da177e4SLinus Torvalds static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
1281da177e4SLinus Torvalds 		struct buflist *buflist, MPT_ADAPTER *ioc);
1291da177e4SLinus Torvalds static void mptctl_timeout_expired (MPT_IOCTL *ioctl);
1301da177e4SLinus Torvalds static int  mptctl_bus_reset(MPT_IOCTL *ioctl);
1311da177e4SLinus Torvalds static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd);
1321da177e4SLinus Torvalds static void mptctl_free_tm_flags(MPT_ADAPTER *ioc);
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds /*
1351da177e4SLinus Torvalds  * Reset Handler cleanup function
1361da177e4SLinus Torvalds  */
1371da177e4SLinus Torvalds static int  mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase);
1381da177e4SLinus Torvalds 
139ea5a7a82SMoore, Eric /*
140ea5a7a82SMoore, Eric  * Event Handler function
141ea5a7a82SMoore, Eric  */
142ea5a7a82SMoore, Eric static int mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
143c972c70fSMoore, Eric static struct fasync_struct *async_queue=NULL;
144ea5a7a82SMoore, Eric 
1451da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1461da177e4SLinus Torvalds /*
1471da177e4SLinus Torvalds  * Scatter gather list (SGL) sizes and limits...
1481da177e4SLinus Torvalds  */
1491da177e4SLinus Torvalds //#define MAX_SCSI_FRAGS	9
1501da177e4SLinus Torvalds #define MAX_FRAGS_SPILL1	9
1511da177e4SLinus Torvalds #define MAX_FRAGS_SPILL2	15
1521da177e4SLinus Torvalds #define FRAGS_PER_BUCKET	(MAX_FRAGS_SPILL2 + 1)
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds //#define MAX_CHAIN_FRAGS	64
1551da177e4SLinus Torvalds //#define MAX_CHAIN_FRAGS	(15+15+15+16)
1561da177e4SLinus Torvalds #define MAX_CHAIN_FRAGS		(4 * MAX_FRAGS_SPILL2 + 1)
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds //  Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each)
1591da177e4SLinus Torvalds //  Works out to: 592d bytes!     (9+1)*8 + 4*(15+1)*8
1601da177e4SLinus Torvalds //                  ^----------------- 80 + 512
1611da177e4SLinus Torvalds #define MAX_SGL_BYTES		((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8)
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds /* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */
1641da177e4SLinus Torvalds #define MAX_KMALLOC_SZ		(128*1024)
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds #define MPT_IOCTL_DEFAULT_TIMEOUT 10	/* Default timeout value (seconds) */
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1691da177e4SLinus Torvalds /**
1701da177e4SLinus Torvalds  *	mptctl_syscall_down - Down the MPT adapter syscall semaphore.
1711da177e4SLinus Torvalds  *	@ioc: Pointer to MPT adapter
1721da177e4SLinus Torvalds  *	@nonblock: boolean, non-zero if O_NONBLOCK is set
1731da177e4SLinus Torvalds  *
1741da177e4SLinus Torvalds  *	All of the ioctl commands can potentially sleep, which is illegal
1751da177e4SLinus Torvalds  *	with a spinlock held, thus we perform mutual exclusion here.
1761da177e4SLinus Torvalds  *
1771da177e4SLinus Torvalds  *	Returns negative errno on error, or zero for success.
1781da177e4SLinus Torvalds  */
1791da177e4SLinus Torvalds static inline int
1801da177e4SLinus Torvalds mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds 	int rc = 0;
1831da177e4SLinus Torvalds 	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 	if (nonblock) {
186eeb846ceSChristoph Hellwig 		if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
1871da177e4SLinus Torvalds 			rc = -EAGAIN;
1881da177e4SLinus Torvalds 	} else {
189eeb846ceSChristoph Hellwig 		if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
1901da177e4SLinus Torvalds 			rc = -ERESTARTSYS;
1911da177e4SLinus Torvalds 	}
1921da177e4SLinus Torvalds 	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc));
1931da177e4SLinus Torvalds 	return rc;
1941da177e4SLinus Torvalds }
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1971da177e4SLinus Torvalds /*
1981da177e4SLinus Torvalds  *  This is the callback for any message we have posted. The message itself
1991da177e4SLinus Torvalds  *  will be returned to the message pool when we return from the IRQ
2001da177e4SLinus Torvalds  *
2011da177e4SLinus Torvalds  *  This runs in irq context so be short and sweet.
2021da177e4SLinus Torvalds  */
2031da177e4SLinus Torvalds static int
2041da177e4SLinus Torvalds mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
2051da177e4SLinus Torvalds {
2061da177e4SLinus Torvalds 	char *sense_data;
2071da177e4SLinus Torvalds 	int sz, req_index;
2081da177e4SLinus Torvalds 	u16 iocStatus;
2091da177e4SLinus Torvalds 	u8 cmd;
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds 	dctlprintk(("mptctl_reply()!\n"));
2121da177e4SLinus Torvalds 	if (req)
2131da177e4SLinus Torvalds 		 cmd = req->u.hdr.Function;
2141da177e4SLinus Torvalds 	else
2151da177e4SLinus Torvalds 		return 1;
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	if (ioc->ioctl) {
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 		if (reply==NULL) {
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 			dctlprintk(("mptctl_reply() NULL Reply "
2221da177e4SLinus Torvalds 				"Function=%x!\n", cmd));
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds 			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
2251da177e4SLinus Torvalds 			ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds 			/* We are done, issue wake up
2281da177e4SLinus Torvalds 	 		*/
2291da177e4SLinus Torvalds 			ioc->ioctl->wait_done = 1;
2301da177e4SLinus Torvalds 			wake_up (&mptctl_wait);
2311da177e4SLinus Torvalds 			return 1;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 		}
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds 		dctlprintk(("mptctl_reply() with req=%p "
2361da177e4SLinus Torvalds 			"reply=%p Function=%x!\n", req, reply, cmd));
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds 		/* Copy the reply frame (which much exist
2391da177e4SLinus Torvalds 		 * for non-SCSI I/O) to the IOC structure.
2401da177e4SLinus Torvalds 		 */
2411da177e4SLinus Torvalds 		dctlprintk(("Copying Reply Frame @%p to ioc%d!\n",
2421da177e4SLinus Torvalds 			reply, ioc->id));
2431da177e4SLinus Torvalds 		memcpy(ioc->ioctl->ReplyFrame, reply,
2441da177e4SLinus Torvalds 			min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
2451da177e4SLinus Torvalds 		ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds 		/* Set the command status to GOOD if IOC Status is GOOD
2481da177e4SLinus Torvalds 		 * OR if SCSI I/O cmd and data underrun or recovered error.
2491da177e4SLinus Torvalds 		 */
250637fa99bSChristoph Hellwig 		iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK;
2511da177e4SLinus Torvalds 		if (iocStatus  == MPI_IOCSTATUS_SUCCESS)
2521da177e4SLinus Torvalds 			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 		if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2551da177e4SLinus Torvalds 			(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
2561da177e4SLinus Torvalds 			ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 			if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||
2591da177e4SLinus Torvalds 			(iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {
2601da177e4SLinus Torvalds 			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
2611da177e4SLinus Torvalds 			}
2621da177e4SLinus Torvalds 		}
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds 		/* Copy the sense data - if present
2651da177e4SLinus Torvalds 		 */
2661da177e4SLinus Torvalds 		if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) &&
2671da177e4SLinus Torvalds 			(reply->u.sreply.SCSIState &
2681da177e4SLinus Torvalds 			 MPI_SCSI_STATE_AUTOSENSE_VALID)){
2691da177e4SLinus Torvalds 			sz = req->u.scsireq.SenseBufferLength;
2701da177e4SLinus Torvalds 			req_index =
2711da177e4SLinus Torvalds 			    le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2721da177e4SLinus Torvalds 			sense_data =
2731da177e4SLinus Torvalds 			    ((u8 *)ioc->sense_buf_pool +
2741da177e4SLinus Torvalds 			     (req_index * MPT_SENSE_BUFFER_ALLOC));
2751da177e4SLinus Torvalds 			memcpy(ioc->ioctl->sense, sense_data, sz);
2761da177e4SLinus Torvalds 			ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID;
2771da177e4SLinus Torvalds 		}
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 		if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT)
2801da177e4SLinus Torvalds 			mptctl_free_tm_flags(ioc);
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 		/* We are done, issue wake up
2831da177e4SLinus Torvalds 		 */
2841da177e4SLinus Torvalds 		ioc->ioctl->wait_done = 1;
2851da177e4SLinus Torvalds 		wake_up (&mptctl_wait);
2861da177e4SLinus Torvalds 	}
2871da177e4SLinus Torvalds 	return 1;
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2911da177e4SLinus Torvalds /* mptctl_timeout_expired
2921da177e4SLinus Torvalds  *
2931da177e4SLinus Torvalds  * Expecting an interrupt, however timed out.
2941da177e4SLinus Torvalds  *
2951da177e4SLinus Torvalds  */
2961da177e4SLinus Torvalds static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
2971da177e4SLinus Torvalds {
2981da177e4SLinus Torvalds 	int rc = 1;
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	dctlprintk((KERN_NOTICE MYNAM ": Timeout Expired! Host %d\n",
3011da177e4SLinus Torvalds 				ioctl->ioc->id));
3021da177e4SLinus Torvalds 	if (ioctl == NULL)
3031da177e4SLinus Torvalds 		return;
3041da177e4SLinus Torvalds 
3051da177e4SLinus Torvalds 	ioctl->wait_done = 0;
3061da177e4SLinus Torvalds 	if (ioctl->reset & MPTCTL_RESET_OK)
3071da177e4SLinus Torvalds 		rc = mptctl_bus_reset(ioctl);
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds 	if (rc) {
3101da177e4SLinus Torvalds 		/* Issue a reset for this device.
3111da177e4SLinus Torvalds 		 * The IOC is not responding.
3121da177e4SLinus Torvalds 		 */
3131da177e4SLinus Torvalds 		dctlprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
3141da177e4SLinus Torvalds 			 ioctl->ioc->name));
3151da177e4SLinus Torvalds 		mpt_HardResetHandler(ioctl->ioc, NO_SLEEP);
3161da177e4SLinus Torvalds 	}
3171da177e4SLinus Torvalds 	return;
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds /* mptctl_bus_reset
3221da177e4SLinus Torvalds  *
3231da177e4SLinus Torvalds  * Bus reset code.
3241da177e4SLinus Torvalds  *
3251da177e4SLinus Torvalds  */
3261da177e4SLinus Torvalds static int mptctl_bus_reset(MPT_IOCTL *ioctl)
3271da177e4SLinus Torvalds {
3281da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf;
3291da177e4SLinus Torvalds 	SCSITaskMgmt_t	*pScsiTm;
3301da177e4SLinus Torvalds 	MPT_SCSI_HOST	*hd;
3311da177e4SLinus Torvalds 	int		 ii;
3321da177e4SLinus Torvalds 	int		 retval;
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	ioctl->reset &= ~MPTCTL_RESET_OK;
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	if (ioctl->ioc->sh == NULL)
3381da177e4SLinus Torvalds 		return -EPERM;
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata;
3411da177e4SLinus Torvalds 	if (hd == NULL)
3421da177e4SLinus Torvalds 		return -EPERM;
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds 	/* Single threading ....
3451da177e4SLinus Torvalds 	 */
3461da177e4SLinus Torvalds 	if (mptctl_set_tm_flags(hd) != 0)
3471da177e4SLinus Torvalds 		return -EPERM;
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 	/* Send request
3501da177e4SLinus Torvalds 	 */
3511da177e4SLinus Torvalds 	if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) {
3521da177e4SLinus Torvalds 		dctlprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
3531da177e4SLinus Torvalds 				ioctl->ioc->name));
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 		mptctl_free_tm_flags(ioctl->ioc);
3561da177e4SLinus Torvalds 		return -ENOMEM;
3571da177e4SLinus Torvalds 	}
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
3601da177e4SLinus Torvalds 			ioctl->ioc->name, mf));
3611da177e4SLinus Torvalds 
3621da177e4SLinus Torvalds 	pScsiTm = (SCSITaskMgmt_t *) mf;
3631da177e4SLinus Torvalds 	pScsiTm->TargetID = ioctl->target;
3641da177e4SLinus Torvalds 	pScsiTm->Bus = hd->port;	/* 0 */
3651da177e4SLinus Torvalds 	pScsiTm->ChainOffset = 0;
3661da177e4SLinus Torvalds 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
3671da177e4SLinus Torvalds 	pScsiTm->Reserved = 0;
3681da177e4SLinus Torvalds 	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
3691da177e4SLinus Torvalds 	pScsiTm->Reserved1 = 0;
3701da177e4SLinus Torvalds 	pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 	for (ii= 0; ii < 8; ii++)
3731da177e4SLinus Torvalds 		pScsiTm->LUN[ii] = 0;
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds 	for (ii=0; ii < 7; ii++)
3761da177e4SLinus Torvalds 		pScsiTm->Reserved2[ii] = 0;
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds 	pScsiTm->TaskMsgContext = 0;
3791da177e4SLinus Torvalds 	dtmprintk((MYIOC_s_INFO_FMT
3801da177e4SLinus Torvalds 		"mptctl_bus_reset: issued.\n", ioctl->ioc->name));
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf);
3831da177e4SLinus Torvalds 
3841da177e4SLinus Torvalds 	ioctl->wait_done=0;
3851da177e4SLinus Torvalds 	if ((retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
3861da177e4SLinus Torvalds 	     sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
3871da177e4SLinus Torvalds 		dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
3881da177e4SLinus Torvalds 			" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
3891da177e4SLinus Torvalds 			hd->ioc, mf));
3901da177e4SLinus Torvalds 		goto mptctl_bus_reset_done;
3911da177e4SLinus Torvalds 	}
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	/* Now wait for the command to complete */
39486a7dcaaSMoore, Eric 	ii = wait_event_timeout(mptctl_wait,
3951da177e4SLinus Torvalds 	     ioctl->wait_done == 1,
3961da177e4SLinus Torvalds 	     HZ*5 /* 5 second timeout */);
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 	if(ii <=0 && (ioctl->wait_done != 1 ))  {
39986a7dcaaSMoore, Eric 		mpt_free_msg_frame(hd->ioc, mf);
4001da177e4SLinus Torvalds 		ioctl->wait_done = 0;
4011da177e4SLinus Torvalds 		retval = -1; /* return failure */
4021da177e4SLinus Torvalds 	}
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds mptctl_bus_reset_done:
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds 	mptctl_free_tm_flags(ioctl->ioc);
4071da177e4SLinus Torvalds 	return retval;
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds static int
4111da177e4SLinus Torvalds mptctl_set_tm_flags(MPT_SCSI_HOST *hd) {
4121da177e4SLinus Torvalds 	unsigned long flags;
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds 	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
4151da177e4SLinus Torvalds 
4161da177e4SLinus Torvalds 	if (hd->tmState == TM_STATE_NONE) {
4171da177e4SLinus Torvalds 		hd->tmState = TM_STATE_IN_PROGRESS;
4181da177e4SLinus Torvalds 		hd->tmPending = 1;
4191da177e4SLinus Torvalds 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
4201da177e4SLinus Torvalds 	} else {
4211da177e4SLinus Torvalds 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
4221da177e4SLinus Torvalds 		return -EBUSY;
4231da177e4SLinus Torvalds 	}
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 	return 0;
4261da177e4SLinus Torvalds }
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds static void
4291da177e4SLinus Torvalds mptctl_free_tm_flags(MPT_ADAPTER *ioc)
4301da177e4SLinus Torvalds {
4311da177e4SLinus Torvalds 	MPT_SCSI_HOST * hd;
4321da177e4SLinus Torvalds 	unsigned long flags;
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
4351da177e4SLinus Torvalds 	if (hd == NULL)
4361da177e4SLinus Torvalds 		return;
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds 	spin_lock_irqsave(&ioc->FreeQlock, flags);
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds 	hd->tmState = TM_STATE_NONE;
4411da177e4SLinus Torvalds 	hd->tmPending = 0;
4421da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	return;
4451da177e4SLinus Torvalds }
4461da177e4SLinus Torvalds 
4471da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4481da177e4SLinus Torvalds /* mptctl_ioc_reset
4491da177e4SLinus Torvalds  *
4501da177e4SLinus Torvalds  * Clean-up functionality. Used only if there has been a
4511da177e4SLinus Torvalds  * reload of the FW due.
4521da177e4SLinus Torvalds  *
4531da177e4SLinus Torvalds  */
4541da177e4SLinus Torvalds static int
4551da177e4SLinus Torvalds mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
4561da177e4SLinus Torvalds {
4571da177e4SLinus Torvalds 	MPT_IOCTL *ioctl = ioc->ioctl;
4581da177e4SLinus Torvalds 	dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n",
4591da177e4SLinus Torvalds 		reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
4601da177e4SLinus Torvalds 		reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	if(ioctl == NULL)
4631da177e4SLinus Torvalds 		return 1;
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds 	switch(reset_phase) {
4661da177e4SLinus Torvalds 	case MPT_IOC_SETUP_RESET:
4671da177e4SLinus Torvalds 		ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET;
4681da177e4SLinus Torvalds 		break;
4691da177e4SLinus Torvalds 	case MPT_IOC_POST_RESET:
4701da177e4SLinus Torvalds 		ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET;
4711da177e4SLinus Torvalds 		break;
4721da177e4SLinus Torvalds 	case MPT_IOC_PRE_RESET:
4731da177e4SLinus Torvalds 	default:
4741da177e4SLinus Torvalds 		break;
4751da177e4SLinus Torvalds 	}
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 	return 1;
4781da177e4SLinus Torvalds }
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
481ea5a7a82SMoore, Eric /* ASYNC Event Notification Support */
482ea5a7a82SMoore, Eric static int
483ea5a7a82SMoore, Eric mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
484ea5a7a82SMoore, Eric {
485ea5a7a82SMoore, Eric 	u8 event;
486ea5a7a82SMoore, Eric 
487ea5a7a82SMoore, Eric 	event = le32_to_cpu(pEvReply->Event) & 0xFF;
488ea5a7a82SMoore, Eric 
489ea5a7a82SMoore, Eric 	dctlprintk(("%s() called\n", __FUNCTION__));
490ea5a7a82SMoore, Eric 	if(async_queue == NULL)
491ea5a7a82SMoore, Eric 		return 1;
492ea5a7a82SMoore, Eric 
493ea5a7a82SMoore, Eric 	/* Raise SIGIO for persistent events.
494ea5a7a82SMoore, Eric 	 * TODO - this define is not in MPI spec yet,
495ea5a7a82SMoore, Eric 	 * but they plan to set it to 0x21
496ea5a7a82SMoore, Eric 	 */
497ea5a7a82SMoore, Eric 	 if (event == 0x21 ) {
498ea5a7a82SMoore, Eric 		ioc->aen_event_read_flag=1;
499ea5a7a82SMoore, Eric 		dctlprintk(("Raised SIGIO to application\n"));
5003a892befSMoore, Eric 		devtverboseprintk(("Raised SIGIO to application\n"));
501ea5a7a82SMoore, Eric 		kill_fasync(&async_queue, SIGIO, POLL_IN);
502ea5a7a82SMoore, Eric 		return 1;
503ea5a7a82SMoore, Eric 	 }
504ea5a7a82SMoore, Eric 
505ea5a7a82SMoore, Eric 	/* This flag is set after SIGIO was raised, and
506ea5a7a82SMoore, Eric 	 * remains set until the application has read
507ea5a7a82SMoore, Eric 	 * the event log via ioctl=MPTEVENTREPORT
508ea5a7a82SMoore, Eric 	 */
509ea5a7a82SMoore, Eric 	if(ioc->aen_event_read_flag)
510ea5a7a82SMoore, Eric 		return 1;
511ea5a7a82SMoore, Eric 
512ea5a7a82SMoore, Eric 	/* Signal only for the events that are
513ea5a7a82SMoore, Eric 	 * requested for by the application
514ea5a7a82SMoore, Eric 	 */
515ea5a7a82SMoore, Eric 	if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
516ea5a7a82SMoore, Eric 		ioc->aen_event_read_flag=1;
517ea5a7a82SMoore, Eric 		dctlprintk(("Raised SIGIO to application\n"));
5183a892befSMoore, Eric 		devtverboseprintk(("Raised SIGIO to application\n"));
519ea5a7a82SMoore, Eric 		kill_fasync(&async_queue, SIGIO, POLL_IN);
520ea5a7a82SMoore, Eric 	}
521ea5a7a82SMoore, Eric 	return 1;
522ea5a7a82SMoore, Eric }
523ea5a7a82SMoore, Eric 
524ea5a7a82SMoore, Eric static int
525ea5a7a82SMoore, Eric mptctl_fasync(int fd, struct file *filep, int mode)
526ea5a7a82SMoore, Eric {
527ea5a7a82SMoore, Eric 	MPT_ADAPTER	*ioc;
528ea5a7a82SMoore, Eric 
529ea5a7a82SMoore, Eric 	list_for_each_entry(ioc, &ioc_list, list)
530ea5a7a82SMoore, Eric 		ioc->aen_event_read_flag=0;
531ea5a7a82SMoore, Eric 
532ea5a7a82SMoore, Eric 	dctlprintk(("%s() called\n", __FUNCTION__));
533ea5a7a82SMoore, Eric 	return fasync_helper(fd, filep, mode, &async_queue);
534ea5a7a82SMoore, Eric }
535ea5a7a82SMoore, Eric 
536ea5a7a82SMoore, Eric static int
537ea5a7a82SMoore, Eric mptctl_release(struct inode *inode, struct file *filep)
538ea5a7a82SMoore, Eric {
539ea5a7a82SMoore, Eric 	dctlprintk(("%s() called\n", __FUNCTION__));
540ea5a7a82SMoore, Eric 	return fasync_helper(-1, filep, 0, &async_queue);
541ea5a7a82SMoore, Eric }
542ea5a7a82SMoore, Eric 
543ea5a7a82SMoore, Eric /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5441da177e4SLinus Torvalds /*
5451da177e4SLinus Torvalds  *  MPT ioctl handler
5461da177e4SLinus Torvalds  *  cmd - specify the particular IOCTL command to be issued
5471da177e4SLinus Torvalds  *  arg - data specific to the command. Must not be null.
5481da177e4SLinus Torvalds  */
5491da177e4SLinus Torvalds static long
5501da177e4SLinus Torvalds __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
5511da177e4SLinus Torvalds {
5521da177e4SLinus Torvalds 	mpt_ioctl_header __user *uhdr = (void __user *) arg;
5531da177e4SLinus Torvalds 	mpt_ioctl_header	 khdr;
5541da177e4SLinus Torvalds 	int iocnum;
5551da177e4SLinus Torvalds 	unsigned iocnumX;
5561da177e4SLinus Torvalds 	int nonblock = (file->f_flags & O_NONBLOCK);
5571da177e4SLinus Torvalds 	int ret;
5581da177e4SLinus Torvalds 	MPT_ADAPTER *iocp = NULL;
5591da177e4SLinus Torvalds 
5601da177e4SLinus Torvalds 	dctlprintk(("mptctl_ioctl() called\n"));
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 	if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
5631da177e4SLinus Torvalds 		printk(KERN_ERR "%s::mptctl_ioctl() @%d - "
5641da177e4SLinus Torvalds 				"Unable to copy mpt_ioctl_header data @ %p\n",
5651da177e4SLinus Torvalds 				__FILE__, __LINE__, uhdr);
5661da177e4SLinus Torvalds 		return -EFAULT;
5671da177e4SLinus Torvalds 	}
5681da177e4SLinus Torvalds 	ret = -ENXIO;				/* (-6) No such device or address */
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds 	/* Verify intended MPT adapter - set iocnum and the adapter
5711da177e4SLinus Torvalds 	 * pointer (iocp)
5721da177e4SLinus Torvalds 	 */
5731da177e4SLinus Torvalds 	iocnumX = khdr.iocnum & 0xFF;
5741da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
5751da177e4SLinus Torvalds 	    (iocp == NULL)) {
5761da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
5771da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnumX));
5781da177e4SLinus Torvalds 		return -ENODEV;
5791da177e4SLinus Torvalds 	}
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds 	if (!iocp->active) {
5821da177e4SLinus Torvalds 		printk(KERN_ERR "%s::mptctl_ioctl() @%d - Controller disabled.\n",
5831da177e4SLinus Torvalds 				__FILE__, __LINE__);
5841da177e4SLinus Torvalds 		return -EFAULT;
5851da177e4SLinus Torvalds 	}
5861da177e4SLinus Torvalds 
5871da177e4SLinus Torvalds 	/* Handle those commands that are just returning
5881da177e4SLinus Torvalds 	 * information stored in the driver.
5891da177e4SLinus Torvalds 	 * These commands should never time out and are unaffected
5901da177e4SLinus Torvalds 	 * by TM and FW reloads.
5911da177e4SLinus Torvalds 	 */
5921da177e4SLinus Torvalds 	if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) {
5931da177e4SLinus Torvalds 		return mptctl_getiocinfo(arg, _IOC_SIZE(cmd));
5941da177e4SLinus Torvalds 	} else if (cmd == MPTTARGETINFO) {
5951da177e4SLinus Torvalds 		return mptctl_gettargetinfo(arg);
5961da177e4SLinus Torvalds 	} else if (cmd == MPTTEST) {
5971da177e4SLinus Torvalds 		return mptctl_readtest(arg);
5981da177e4SLinus Torvalds 	} else if (cmd == MPTEVENTQUERY) {
5991da177e4SLinus Torvalds 		return mptctl_eventquery(arg);
6001da177e4SLinus Torvalds 	} else if (cmd == MPTEVENTENABLE) {
6011da177e4SLinus Torvalds 		return mptctl_eventenable(arg);
6021da177e4SLinus Torvalds 	} else if (cmd == MPTEVENTREPORT) {
6031da177e4SLinus Torvalds 		return mptctl_eventreport(arg);
6041da177e4SLinus Torvalds 	} else if (cmd == MPTFWREPLACE) {
6051da177e4SLinus Torvalds 		return mptctl_replace_fw(arg);
6061da177e4SLinus Torvalds 	}
6071da177e4SLinus Torvalds 
6081da177e4SLinus Torvalds 	/* All of these commands require an interrupt or
6091da177e4SLinus Torvalds 	 * are unknown/illegal.
6101da177e4SLinus Torvalds 	 */
6111da177e4SLinus Torvalds 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
6121da177e4SLinus Torvalds 		return ret;
6131da177e4SLinus Torvalds 
6141da177e4SLinus Torvalds 	dctlprintk((MYIOC_s_INFO_FMT ": mptctl_ioctl()\n", iocp->name));
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds 	if (cmd == MPTFWDOWNLOAD)
6171da177e4SLinus Torvalds 		ret = mptctl_fw_download(arg);
6181da177e4SLinus Torvalds 	else if (cmd == MPTCOMMAND)
6191da177e4SLinus Torvalds 		ret = mptctl_mpt_command(arg);
6201da177e4SLinus Torvalds 	else if (cmd == MPTHARDRESET)
6211da177e4SLinus Torvalds 		ret = mptctl_do_reset(arg);
6221da177e4SLinus Torvalds 	else if ((cmd & ~IOCSIZE_MASK) == (HP_GETHOSTINFO & ~IOCSIZE_MASK))
6231da177e4SLinus Torvalds 		ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd));
6241da177e4SLinus Torvalds 	else if (cmd == HP_GETTARGETINFO)
6251da177e4SLinus Torvalds 		ret = mptctl_hp_targetinfo(arg);
6261da177e4SLinus Torvalds 	else
6271da177e4SLinus Torvalds 		ret = -EINVAL;
6281da177e4SLinus Torvalds 
629eeb846ceSChristoph Hellwig 	mutex_unlock(&iocp->ioctl->ioctl_mutex);
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds 	return ret;
6321da177e4SLinus Torvalds }
6331da177e4SLinus Torvalds 
6341da177e4SLinus Torvalds static long
6351da177e4SLinus Torvalds mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
6361da177e4SLinus Torvalds {
6371da177e4SLinus Torvalds 	long ret;
6381da177e4SLinus Torvalds 	lock_kernel();
6391da177e4SLinus Torvalds 	ret = __mptctl_ioctl(file, cmd, arg);
6401da177e4SLinus Torvalds 	unlock_kernel();
6411da177e4SLinus Torvalds 	return ret;
6421da177e4SLinus Torvalds }
6431da177e4SLinus Torvalds 
6441da177e4SLinus Torvalds static int mptctl_do_reset(unsigned long arg)
6451da177e4SLinus Torvalds {
6461da177e4SLinus Torvalds 	struct mpt_ioctl_diag_reset __user *urinfo = (void __user *) arg;
6471da177e4SLinus Torvalds 	struct mpt_ioctl_diag_reset krinfo;
6481da177e4SLinus Torvalds 	MPT_ADAPTER		*iocp;
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds 	dctlprintk((KERN_INFO "mptctl_do_reset called.\n"));
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds 	if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
6531da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_do_reset - "
6541da177e4SLinus Torvalds 				"Unable to copy mpt_ioctl_diag_reset struct @ %p\n",
6551da177e4SLinus Torvalds 				__FILE__, __LINE__, urinfo);
6561da177e4SLinus Torvalds 		return -EFAULT;
6571da177e4SLinus Torvalds 	}
6581da177e4SLinus Torvalds 
6591da177e4SLinus Torvalds 	if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
6601da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
6611da177e4SLinus Torvalds 				__FILE__, __LINE__, krinfo.hdr.iocnum));
6621da177e4SLinus Torvalds 		return -ENODEV; /* (-6) No such device or address */
6631da177e4SLinus Torvalds 	}
6641da177e4SLinus Torvalds 
6651da177e4SLinus Torvalds 	if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {
6661da177e4SLinus Torvalds 		printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",
6671da177e4SLinus Torvalds 			__FILE__, __LINE__);
6681da177e4SLinus Torvalds 		return -1;
6691da177e4SLinus Torvalds 	}
6701da177e4SLinus Torvalds 
6711da177e4SLinus Torvalds 	return 0;
6721da177e4SLinus Torvalds }
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6751da177e4SLinus Torvalds /*
6761da177e4SLinus Torvalds  * MPT FW download function.  Cast the arg into the mpt_fw_xfer structure.
6771da177e4SLinus Torvalds  * This structure contains: iocnum, firmware length (bytes),
6781da177e4SLinus Torvalds  *      pointer to user space memory where the fw image is stored.
6791da177e4SLinus Torvalds  *
6801da177e4SLinus Torvalds  * Outputs:	None.
6811da177e4SLinus Torvalds  * Return:	0 if successful
6821da177e4SLinus Torvalds  *		-EFAULT if data unavailable
6831da177e4SLinus Torvalds  *		-ENXIO  if no such device
6841da177e4SLinus Torvalds  *		-EAGAIN if resource problem
6851da177e4SLinus Torvalds  *		-ENOMEM if no memory for SGE
6861da177e4SLinus Torvalds  *		-EMLINK if too many chain buffers required
6871da177e4SLinus Torvalds  *		-EBADRQC if adapter does not support FW download
6881da177e4SLinus Torvalds  *		-EBUSY if adapter is busy
6891da177e4SLinus Torvalds  *		-ENOMSG if FW upload returned bad status
6901da177e4SLinus Torvalds  */
6911da177e4SLinus Torvalds static int
6921da177e4SLinus Torvalds mptctl_fw_download(unsigned long arg)
6931da177e4SLinus Torvalds {
6941da177e4SLinus Torvalds 	struct mpt_fw_xfer __user *ufwdl = (void __user *) arg;
6951da177e4SLinus Torvalds 	struct mpt_fw_xfer	 kfwdl;
6961da177e4SLinus Torvalds 
6971da177e4SLinus Torvalds 	dctlprintk((KERN_INFO "mptctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc
6981da177e4SLinus Torvalds 	if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
6991da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
7001da177e4SLinus Torvalds 				"Unable to copy mpt_fw_xfer struct @ %p\n",
7011da177e4SLinus Torvalds 				__FILE__, __LINE__, ufwdl);
7021da177e4SLinus Torvalds 		return -EFAULT;
7031da177e4SLinus Torvalds 	}
7041da177e4SLinus Torvalds 
7051da177e4SLinus Torvalds 	return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
7061da177e4SLinus Torvalds }
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7091da177e4SLinus Torvalds /*
7101da177e4SLinus Torvalds  * FW Download engine.
7111da177e4SLinus Torvalds  * Outputs:	None.
7121da177e4SLinus Torvalds  * Return:	0 if successful
7131da177e4SLinus Torvalds  *		-EFAULT if data unavailable
7141da177e4SLinus Torvalds  *		-ENXIO  if no such device
7151da177e4SLinus Torvalds  *		-EAGAIN if resource problem
7161da177e4SLinus Torvalds  *		-ENOMEM if no memory for SGE
7171da177e4SLinus Torvalds  *		-EMLINK if too many chain buffers required
7181da177e4SLinus Torvalds  *		-EBADRQC if adapter does not support FW download
7191da177e4SLinus Torvalds  *		-EBUSY if adapter is busy
7201da177e4SLinus Torvalds  *		-ENOMSG if FW upload returned bad status
7211da177e4SLinus Torvalds  */
7221da177e4SLinus Torvalds static int
7231da177e4SLinus Torvalds mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
7241da177e4SLinus Torvalds {
7251da177e4SLinus Torvalds 	FWDownload_t		*dlmsg;
7261da177e4SLinus Torvalds 	MPT_FRAME_HDR		*mf;
7271da177e4SLinus Torvalds 	MPT_ADAPTER		*iocp;
7281da177e4SLinus Torvalds 	FWDownloadTCSGE_t	*ptsge;
7291da177e4SLinus Torvalds 	MptSge_t		*sgl, *sgIn;
7301da177e4SLinus Torvalds 	char			*sgOut;
7311da177e4SLinus Torvalds 	struct buflist		*buflist;
7321da177e4SLinus Torvalds 	struct buflist		*bl;
7331da177e4SLinus Torvalds 	dma_addr_t		 sgl_dma;
7341da177e4SLinus Torvalds 	int			 ret;
7351da177e4SLinus Torvalds 	int			 numfrags = 0;
7361da177e4SLinus Torvalds 	int			 maxfrags;
7371da177e4SLinus Torvalds 	int			 n = 0;
7381da177e4SLinus Torvalds 	u32			 sgdir;
7391da177e4SLinus Torvalds 	u32			 nib;
7401da177e4SLinus Torvalds 	int			 fw_bytes_copied = 0;
7411da177e4SLinus Torvalds 	int			 i;
7421da177e4SLinus Torvalds 	int			 sge_offset = 0;
7431da177e4SLinus Torvalds 	u16			 iocstat;
7441da177e4SLinus Torvalds 	pFWDownloadReply_t	 ReplyMsg = NULL;
7451da177e4SLinus Torvalds 
746946cbf04SMoore, Eric 	dctlprintk(("mptctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
7471da177e4SLinus Torvalds 
748946cbf04SMoore, Eric 	dctlprintk(("DbG: kfwdl.bufp  = %p\n", ufwbuf));
749946cbf04SMoore, Eric 	dctlprintk(("DbG: kfwdl.fwlen = %d\n", (int)fwlen));
750946cbf04SMoore, Eric 	dctlprintk(("DbG: kfwdl.ioc   = %04xh\n", ioc));
7511da177e4SLinus Torvalds 
752946cbf04SMoore, Eric 	if (mpt_verify_adapter(ioc, &iocp) < 0) {
753946cbf04SMoore, Eric 		dctlprintk(("ioctl_fwdl - ioc%d not found!\n",
754946cbf04SMoore, Eric 				 ioc));
7551da177e4SLinus Torvalds 		return -ENODEV; /* (-6) No such device or address */
756946cbf04SMoore, Eric 	} else {
7571da177e4SLinus Torvalds 
7581da177e4SLinus Torvalds 		/*  Valid device. Get a message frame and construct the FW download message.
7591da177e4SLinus Torvalds 	 	*/
7601da177e4SLinus Torvalds 		if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL)
7611da177e4SLinus Torvalds 			return -EAGAIN;
762946cbf04SMoore, Eric 	}
7631da177e4SLinus Torvalds 	dlmsg = (FWDownload_t*) mf;
7641da177e4SLinus Torvalds 	ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;
7651da177e4SLinus Torvalds 	sgOut = (char *) (ptsge + 1);
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds 	/*
7681da177e4SLinus Torvalds 	 * Construct f/w download request
7691da177e4SLinus Torvalds 	 */
7701da177e4SLinus Torvalds 	dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW;
7711da177e4SLinus Torvalds 	dlmsg->Reserved = 0;
7721da177e4SLinus Torvalds 	dlmsg->ChainOffset = 0;
7731da177e4SLinus Torvalds 	dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD;
7741da177e4SLinus Torvalds 	dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0;
775946cbf04SMoore, Eric 	if (iocp->facts.MsgVersion >= MPI_VERSION_01_05)
776946cbf04SMoore, Eric 		dlmsg->MsgFlags = MPI_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
777946cbf04SMoore, Eric 	else
7781da177e4SLinus Torvalds 		dlmsg->MsgFlags = 0;
7791da177e4SLinus Torvalds 
780946cbf04SMoore, Eric 
7811da177e4SLinus Torvalds 	/* Set up the Transaction SGE.
7821da177e4SLinus Torvalds 	 */
7831da177e4SLinus Torvalds 	ptsge->Reserved = 0;
7841da177e4SLinus Torvalds 	ptsge->ContextSize = 0;
7851da177e4SLinus Torvalds 	ptsge->DetailsLength = 12;
7861da177e4SLinus Torvalds 	ptsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
7871da177e4SLinus Torvalds 	ptsge->Reserved_0100_Checksum = 0;
7881da177e4SLinus Torvalds 	ptsge->ImageOffset = 0;
7891da177e4SLinus Torvalds 	ptsge->ImageSize = cpu_to_le32(fwlen);
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds 	/* Add the SGL
7921da177e4SLinus Torvalds 	 */
7931da177e4SLinus Torvalds 
7941da177e4SLinus Torvalds 	/*
7951da177e4SLinus Torvalds 	 * Need to kmalloc area(s) for holding firmware image bytes.
7961da177e4SLinus Torvalds 	 * But we need to do it piece meal, using a proper
7971da177e4SLinus Torvalds 	 * scatter gather list (with 128kB MAX hunks).
7981da177e4SLinus Torvalds 	 *
7991da177e4SLinus Torvalds 	 * A practical limit here might be # of sg hunks that fit into
8001da177e4SLinus Torvalds 	 * a single IOC request frame; 12 or 8 (see below), so:
8011da177e4SLinus Torvalds 	 * For FC9xx: 12 x 128kB == 1.5 mB (max)
8021da177e4SLinus Torvalds 	 * For C1030:  8 x 128kB == 1   mB (max)
8031da177e4SLinus Torvalds 	 * We could support chaining, but things get ugly(ier:)
8041da177e4SLinus Torvalds 	 *
8051da177e4SLinus Torvalds 	 * Set the sge_offset to the start of the sgl (bytes).
8061da177e4SLinus Torvalds 	 */
8071da177e4SLinus Torvalds 	sgdir = 0x04000000;		/* IOC will READ from sys mem */
8081da177e4SLinus Torvalds 	sge_offset = sizeof(MPIHeader_t) + sizeof(FWDownloadTCSGE_t);
8091da177e4SLinus Torvalds 	if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, sge_offset,
8101da177e4SLinus Torvalds 				    &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
8111da177e4SLinus Torvalds 		return -ENOMEM;
8121da177e4SLinus Torvalds 
8131da177e4SLinus Torvalds 	/*
8141da177e4SLinus Torvalds 	 * We should only need SGL with 2 simple_32bit entries (up to 256 kB)
8151da177e4SLinus Torvalds 	 * for FC9xx f/w image, but calculate max number of sge hunks
8161da177e4SLinus Torvalds 	 * we can fit into a request frame, and limit ourselves to that.
8171da177e4SLinus Torvalds 	 * (currently no chain support)
8181da177e4SLinus Torvalds 	 * maxfrags = (Request Size - FWdownload Size ) / Size of 32 bit SGE
8191da177e4SLinus Torvalds 	 *	Request		maxfrags
8201da177e4SLinus Torvalds 	 *	128		12
8211da177e4SLinus Torvalds 	 *	96		8
8221da177e4SLinus Torvalds 	 *	64		4
8231da177e4SLinus Torvalds 	 */
8241da177e4SLinus Torvalds 	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t))
8251da177e4SLinus Torvalds 			/ (sizeof(dma_addr_t) + sizeof(u32));
8261da177e4SLinus Torvalds 	if (numfrags > maxfrags) {
8271da177e4SLinus Torvalds 		ret = -EMLINK;
8281da177e4SLinus Torvalds 		goto fwdl_out;
8291da177e4SLinus Torvalds 	}
8301da177e4SLinus Torvalds 
831946cbf04SMoore, Eric 	dctlprintk(("DbG: sgl buffer  = %p, sgfrags = %d\n", sgl, numfrags));
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 	/*
8341da177e4SLinus Torvalds 	 * Parse SG list, copying sgl itself,
8351da177e4SLinus Torvalds 	 * plus f/w image hunks from user space as we go...
8361da177e4SLinus Torvalds 	 */
8371da177e4SLinus Torvalds 	ret = -EFAULT;
8381da177e4SLinus Torvalds 	sgIn = sgl;
8391da177e4SLinus Torvalds 	bl = buflist;
8401da177e4SLinus Torvalds 	for (i=0; i < numfrags; i++) {
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 		/* Get the SGE type: 0 - TCSGE, 3 - Chain, 1 - Simple SGE
8431da177e4SLinus Torvalds 		 * Skip everything but Simple. If simple, copy from
8441da177e4SLinus Torvalds 		 *	user space into kernel space.
8451da177e4SLinus Torvalds 		 * Note: we should not have anything but Simple as
8461da177e4SLinus Torvalds 		 *	Chain SGE are illegal.
8471da177e4SLinus Torvalds 		 */
8481da177e4SLinus Torvalds 		nib = (sgIn->FlagsLength & 0x30000000) >> 28;
8491da177e4SLinus Torvalds 		if (nib == 0 || nib == 3) {
8501da177e4SLinus Torvalds 			;
8511da177e4SLinus Torvalds 		} else if (sgIn->Address) {
8521da177e4SLinus Torvalds 			mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
8531da177e4SLinus Torvalds 			n++;
8541da177e4SLinus Torvalds 			if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
8551da177e4SLinus Torvalds 				printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
8561da177e4SLinus Torvalds 						"Unable to copy f/w buffer hunk#%d @ %p\n",
8571da177e4SLinus Torvalds 						__FILE__, __LINE__, n, ufwbuf);
8581da177e4SLinus Torvalds 				goto fwdl_out;
8591da177e4SLinus Torvalds 			}
8601da177e4SLinus Torvalds 			fw_bytes_copied += bl->len;
8611da177e4SLinus Torvalds 		}
8621da177e4SLinus Torvalds 		sgIn++;
8631da177e4SLinus Torvalds 		bl++;
8641da177e4SLinus Torvalds 		sgOut += (sizeof(dma_addr_t) + sizeof(u32));
8651da177e4SLinus Torvalds 	}
8661da177e4SLinus Torvalds 
8671da177e4SLinus Torvalds #ifdef MPT_DEBUG
8681da177e4SLinus Torvalds 	{
8691da177e4SLinus Torvalds 		u32 *m = (u32 *)mf;
8701da177e4SLinus Torvalds 		printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " ");
8711da177e4SLinus Torvalds 		for (i=0; i < 7+numfrags*2; i++)
8721da177e4SLinus Torvalds 			printk(" %08x", le32_to_cpu(m[i]));
8731da177e4SLinus Torvalds 		printk("\n");
8741da177e4SLinus Torvalds 	}
8751da177e4SLinus Torvalds #endif
8761da177e4SLinus Torvalds 
8771da177e4SLinus Torvalds 	/*
8781da177e4SLinus Torvalds 	 * Finally, perform firmware download.
8791da177e4SLinus Torvalds 	 */
880946cbf04SMoore, Eric 	ReplyMsg = NULL;
8811da177e4SLinus Torvalds 	mpt_put_msg_frame(mptctl_id, iocp, mf);
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds 	/* Now wait for the command to complete */
88486a7dcaaSMoore, Eric 	ret = wait_event_timeout(mptctl_wait,
8851da177e4SLinus Torvalds 	     iocp->ioctl->wait_done == 1,
8861da177e4SLinus Torvalds 	     HZ*60);
8871da177e4SLinus Torvalds 
8881da177e4SLinus Torvalds 	if(ret <=0 && (iocp->ioctl->wait_done != 1 )) {
8891da177e4SLinus Torvalds 	/* Now we need to reset the board */
8901da177e4SLinus Torvalds 		mptctl_timeout_expired(iocp->ioctl);
8911da177e4SLinus Torvalds 		ret = -ENODATA;
8921da177e4SLinus Torvalds 		goto fwdl_out;
8931da177e4SLinus Torvalds 	}
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds 	if (sgl)
8961da177e4SLinus Torvalds 		kfree_sgl(sgl, sgl_dma, buflist, iocp);
8971da177e4SLinus Torvalds 
8981da177e4SLinus Torvalds 	ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;
8991da177e4SLinus Torvalds 	iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
9001da177e4SLinus Torvalds 	if (iocstat == MPI_IOCSTATUS_SUCCESS) {
9011da177e4SLinus Torvalds 		printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name);
9021da177e4SLinus Torvalds 		return 0;
9031da177e4SLinus Torvalds 	} else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
9041da177e4SLinus Torvalds 		printk(KERN_WARNING MYNAM ": ?Hmmm...  %s says it doesn't support F/W download!?!\n",
9051da177e4SLinus Torvalds 				iocp->name);
9061da177e4SLinus Torvalds 		printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n");
9071da177e4SLinus Torvalds 		return -EBADRQC;
9081da177e4SLinus Torvalds 	} else if (iocstat == MPI_IOCSTATUS_BUSY) {
9091da177e4SLinus Torvalds 		printk(KERN_WARNING MYNAM ": Warning!  %s says: IOC_BUSY!\n", iocp->name);
9101da177e4SLinus Torvalds 		printk(KERN_WARNING MYNAM ": (try again later?)\n");
9111da177e4SLinus Torvalds 		return -EBUSY;
9121da177e4SLinus Torvalds 	} else {
9131da177e4SLinus Torvalds 		printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR!  %s returned [bad] status = %04xh\n",
9141da177e4SLinus Torvalds 				    iocp->name, iocstat);
9151da177e4SLinus Torvalds 		printk(KERN_WARNING MYNAM ": (bad VooDoo)\n");
9161da177e4SLinus Torvalds 		return -ENOMSG;
9171da177e4SLinus Torvalds 	}
9181da177e4SLinus Torvalds 	return 0;
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds fwdl_out:
9211da177e4SLinus Torvalds         kfree_sgl(sgl, sgl_dma, buflist, iocp);
9221da177e4SLinus Torvalds 	return ret;
9231da177e4SLinus Torvalds }
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
9261da177e4SLinus Torvalds /*
9271da177e4SLinus Torvalds  * SGE Allocation routine
9281da177e4SLinus Torvalds  *
9291da177e4SLinus Torvalds  * Inputs:	bytes - number of bytes to be transferred
9301da177e4SLinus Torvalds  *		sgdir - data direction
9311da177e4SLinus Torvalds  *		sge_offset - offset (in bytes) from the start of the request
9321da177e4SLinus Torvalds  *			frame to the first SGE
9331da177e4SLinus Torvalds  *		ioc - pointer to the mptadapter
9341da177e4SLinus Torvalds  * Outputs:	frags - number of scatter gather elements
9351da177e4SLinus Torvalds  *		blp - point to the buflist pointer
9361da177e4SLinus Torvalds  *		sglbuf_dma - pointer to the (dma) sgl
9371da177e4SLinus Torvalds  * Returns:	Null if failes
9381da177e4SLinus Torvalds  *		pointer to the (virtual) sgl if successful.
9391da177e4SLinus Torvalds  */
9401da177e4SLinus Torvalds static MptSge_t *
9411da177e4SLinus Torvalds kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
9421da177e4SLinus Torvalds 		 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
9431da177e4SLinus Torvalds {
9441da177e4SLinus Torvalds 	MptSge_t	*sglbuf = NULL;		/* pointer to array of SGE */
9451da177e4SLinus Torvalds 						/* and chain buffers */
9461da177e4SLinus Torvalds 	struct buflist	*buflist = NULL;	/* kernel routine */
9471da177e4SLinus Torvalds 	MptSge_t	*sgl;
9481da177e4SLinus Torvalds 	int		 numfrags = 0;
9491da177e4SLinus Torvalds 	int		 fragcnt = 0;
9501da177e4SLinus Torvalds 	int		 alloc_sz = min(bytes,MAX_KMALLOC_SZ);	// avoid kernel warning msg!
9511da177e4SLinus Torvalds 	int		 bytes_allocd = 0;
9521da177e4SLinus Torvalds 	int		 this_alloc;
9531da177e4SLinus Torvalds 	dma_addr_t	 pa;					// phys addr
9541da177e4SLinus Torvalds 	int		 i, buflist_ent;
9551da177e4SLinus Torvalds 	int		 sg_spill = MAX_FRAGS_SPILL1;
9561da177e4SLinus Torvalds 	int		 dir;
9571da177e4SLinus Torvalds 	/* initialization */
9581da177e4SLinus Torvalds 	*frags = 0;
9591da177e4SLinus Torvalds 	*blp = NULL;
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds 	/* Allocate and initialize an array of kernel
9621da177e4SLinus Torvalds 	 * structures for the SG elements.
9631da177e4SLinus Torvalds 	 */
9641da177e4SLinus Torvalds 	i = MAX_SGL_BYTES / 8;
9651da177e4SLinus Torvalds 	buflist = kmalloc(i, GFP_USER);
9661da177e4SLinus Torvalds 	if (buflist == NULL)
9671da177e4SLinus Torvalds 		return NULL;
9681da177e4SLinus Torvalds 	memset(buflist, 0, i);
9691da177e4SLinus Torvalds 	buflist_ent = 0;
9701da177e4SLinus Torvalds 
9711da177e4SLinus Torvalds 	/* Allocate a single block of memory to store the sg elements and
9721da177e4SLinus Torvalds 	 * the chain buffers.  The calling routine is responsible for
9731da177e4SLinus Torvalds 	 * copying the data in this array into the correct place in the
9741da177e4SLinus Torvalds 	 * request and chain buffers.
9751da177e4SLinus Torvalds 	 */
9761da177e4SLinus Torvalds 	sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma);
9771da177e4SLinus Torvalds 	if (sglbuf == NULL)
9781da177e4SLinus Torvalds 		goto free_and_fail;
9791da177e4SLinus Torvalds 
9801da177e4SLinus Torvalds 	if (sgdir & 0x04000000)
9811da177e4SLinus Torvalds 		dir = PCI_DMA_TODEVICE;
9821da177e4SLinus Torvalds 	else
9831da177e4SLinus Torvalds 		dir = PCI_DMA_FROMDEVICE;
9841da177e4SLinus Torvalds 
9851da177e4SLinus Torvalds 	/* At start:
9861da177e4SLinus Torvalds 	 *	sgl = sglbuf = point to beginning of sg buffer
9871da177e4SLinus Torvalds 	 *	buflist_ent = 0 = first kernel structure
9881da177e4SLinus Torvalds 	 *	sg_spill = number of SGE that can be written before the first
9891da177e4SLinus Torvalds 	 *		chain element.
9901da177e4SLinus Torvalds 	 *
9911da177e4SLinus Torvalds 	 */
9921da177e4SLinus Torvalds 	sgl = sglbuf;
9931da177e4SLinus Torvalds 	sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1;
9941da177e4SLinus Torvalds 	while (bytes_allocd < bytes) {
9951da177e4SLinus Torvalds 		this_alloc = min(alloc_sz, bytes-bytes_allocd);
9961da177e4SLinus Torvalds 		buflist[buflist_ent].len = this_alloc;
9971da177e4SLinus Torvalds 		buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev,
9981da177e4SLinus Torvalds 								 this_alloc,
9991da177e4SLinus Torvalds 								 &pa);
10001da177e4SLinus Torvalds 		if (buflist[buflist_ent].kptr == NULL) {
10011da177e4SLinus Torvalds 			alloc_sz = alloc_sz / 2;
10021da177e4SLinus Torvalds 			if (alloc_sz == 0) {
10031da177e4SLinus Torvalds 				printk(KERN_WARNING MYNAM "-SG: No can do - "
10041da177e4SLinus Torvalds 						    "not enough memory!   :-(\n");
10051da177e4SLinus Torvalds 				printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
10061da177e4SLinus Torvalds 						    numfrags);
10071da177e4SLinus Torvalds 				goto free_and_fail;
10081da177e4SLinus Torvalds 			}
10091da177e4SLinus Torvalds 			continue;
10101da177e4SLinus Torvalds 		} else {
10111da177e4SLinus Torvalds 			dma_addr_t dma_addr;
10121da177e4SLinus Torvalds 
10131da177e4SLinus Torvalds 			bytes_allocd += this_alloc;
10141da177e4SLinus Torvalds 			sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc);
10151da177e4SLinus Torvalds 			dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
10161da177e4SLinus Torvalds 			sgl->Address = dma_addr;
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds 			fragcnt++;
10191da177e4SLinus Torvalds 			numfrags++;
10201da177e4SLinus Torvalds 			sgl++;
10211da177e4SLinus Torvalds 			buflist_ent++;
10221da177e4SLinus Torvalds 		}
10231da177e4SLinus Torvalds 
10241da177e4SLinus Torvalds 		if (bytes_allocd >= bytes)
10251da177e4SLinus Torvalds 			break;
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds 		/* Need to chain? */
10281da177e4SLinus Torvalds 		if (fragcnt == sg_spill) {
10291da177e4SLinus Torvalds 			printk(KERN_WARNING MYNAM "-SG: No can do - " "Chain required!   :-(\n");
10301da177e4SLinus Torvalds 			printk(KERN_WARNING MYNAM "(freeing %d frags)\n", numfrags);
10311da177e4SLinus Torvalds 			goto free_and_fail;
10321da177e4SLinus Torvalds 		}
10331da177e4SLinus Torvalds 
10341da177e4SLinus Torvalds 		/* overflow check... */
10351da177e4SLinus Torvalds 		if (numfrags*8 > MAX_SGL_BYTES){
10361da177e4SLinus Torvalds 			/* GRRRRR... */
10371da177e4SLinus Torvalds 			printk(KERN_WARNING MYNAM "-SG: No can do - "
10381da177e4SLinus Torvalds 					    "too many SG frags!   :-(\n");
10391da177e4SLinus Torvalds 			printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
10401da177e4SLinus Torvalds 					    numfrags);
10411da177e4SLinus Torvalds 			goto free_and_fail;
10421da177e4SLinus Torvalds 		}
10431da177e4SLinus Torvalds 	}
10441da177e4SLinus Torvalds 
10451da177e4SLinus Torvalds 	/* Last sge fixup: set LE+eol+eob bits */
10461da177e4SLinus Torvalds 	sgl[-1].FlagsLength |= 0xC1000000;
10471da177e4SLinus Torvalds 
10481da177e4SLinus Torvalds 	*frags = numfrags;
10491da177e4SLinus Torvalds 	*blp = buflist;
10501da177e4SLinus Torvalds 
10511da177e4SLinus Torvalds 	dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
10521da177e4SLinus Torvalds 			   "%d SG frags generated!\n",
10531da177e4SLinus Torvalds 			   numfrags));
10541da177e4SLinus Torvalds 
10551da177e4SLinus Torvalds 	dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
10561da177e4SLinus Torvalds 			   "last (big) alloc_sz=%d\n",
10571da177e4SLinus Torvalds 			   alloc_sz));
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds 	return sglbuf;
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds free_and_fail:
10621da177e4SLinus Torvalds 	if (sglbuf != NULL) {
10631da177e4SLinus Torvalds 		int i;
10641da177e4SLinus Torvalds 
10651da177e4SLinus Torvalds 		for (i = 0; i < numfrags; i++) {
10661da177e4SLinus Torvalds 			dma_addr_t dma_addr;
10671da177e4SLinus Torvalds 			u8 *kptr;
10681da177e4SLinus Torvalds 			int len;
10691da177e4SLinus Torvalds 
10701da177e4SLinus Torvalds 			if ((sglbuf[i].FlagsLength >> 24) == 0x30)
10711da177e4SLinus Torvalds 				continue;
10721da177e4SLinus Torvalds 
10731da177e4SLinus Torvalds 			dma_addr = sglbuf[i].Address;
10741da177e4SLinus Torvalds 			kptr = buflist[i].kptr;
10751da177e4SLinus Torvalds 			len = buflist[i].len;
10761da177e4SLinus Torvalds 
10771da177e4SLinus Torvalds 			pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
10781da177e4SLinus Torvalds 		}
10791da177e4SLinus Torvalds 		pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma);
10801da177e4SLinus Torvalds 	}
10811da177e4SLinus Torvalds 	kfree(buflist);
10821da177e4SLinus Torvalds 	return NULL;
10831da177e4SLinus Torvalds }
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10861da177e4SLinus Torvalds /*
10871da177e4SLinus Torvalds  * Routine to free the SGL elements.
10881da177e4SLinus Torvalds  */
10891da177e4SLinus Torvalds static void
10901da177e4SLinus Torvalds kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
10911da177e4SLinus Torvalds {
10921da177e4SLinus Torvalds 	MptSge_t	*sg = sgl;
10931da177e4SLinus Torvalds 	struct buflist	*bl = buflist;
10941da177e4SLinus Torvalds 	u32		 nib;
10951da177e4SLinus Torvalds 	int		 dir;
10961da177e4SLinus Torvalds 	int		 n = 0;
10971da177e4SLinus Torvalds 
10981da177e4SLinus Torvalds 	if (sg->FlagsLength & 0x04000000)
10991da177e4SLinus Torvalds 		dir = PCI_DMA_TODEVICE;
11001da177e4SLinus Torvalds 	else
11011da177e4SLinus Torvalds 		dir = PCI_DMA_FROMDEVICE;
11021da177e4SLinus Torvalds 
11031da177e4SLinus Torvalds 	nib = (sg->FlagsLength & 0xF0000000) >> 28;
11041da177e4SLinus Torvalds 	while (! (nib & 0x4)) { /* eob */
11051da177e4SLinus Torvalds 		/* skip ignore/chain. */
11061da177e4SLinus Torvalds 		if (nib == 0 || nib == 3) {
11071da177e4SLinus Torvalds 			;
11081da177e4SLinus Torvalds 		} else if (sg->Address) {
11091da177e4SLinus Torvalds 			dma_addr_t dma_addr;
11101da177e4SLinus Torvalds 			void *kptr;
11111da177e4SLinus Torvalds 			int len;
11121da177e4SLinus Torvalds 
11131da177e4SLinus Torvalds 			dma_addr = sg->Address;
11141da177e4SLinus Torvalds 			kptr = bl->kptr;
11151da177e4SLinus Torvalds 			len = bl->len;
11161da177e4SLinus Torvalds 			pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
11171da177e4SLinus Torvalds 			pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
11181da177e4SLinus Torvalds 			n++;
11191da177e4SLinus Torvalds 		}
11201da177e4SLinus Torvalds 		sg++;
11211da177e4SLinus Torvalds 		bl++;
11221da177e4SLinus Torvalds 		nib = (le32_to_cpu(sg->FlagsLength) & 0xF0000000) >> 28;
11231da177e4SLinus Torvalds 	}
11241da177e4SLinus Torvalds 
11251da177e4SLinus Torvalds 	/* we're at eob! */
11261da177e4SLinus Torvalds 	if (sg->Address) {
11271da177e4SLinus Torvalds 		dma_addr_t dma_addr;
11281da177e4SLinus Torvalds 		void *kptr;
11291da177e4SLinus Torvalds 		int len;
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds 		dma_addr = sg->Address;
11321da177e4SLinus Torvalds 		kptr = bl->kptr;
11331da177e4SLinus Torvalds 		len = bl->len;
11341da177e4SLinus Torvalds 		pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
11351da177e4SLinus Torvalds 		pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
11361da177e4SLinus Torvalds 		n++;
11371da177e4SLinus Torvalds 	}
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds 	pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma);
11401da177e4SLinus Torvalds 	kfree(buflist);
11411da177e4SLinus Torvalds 	dctlprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));
11421da177e4SLinus Torvalds }
11431da177e4SLinus Torvalds 
11441da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11451da177e4SLinus Torvalds /*
11461da177e4SLinus Torvalds  *	mptctl_getiocinfo - Query the host adapter for IOC information.
11471da177e4SLinus Torvalds  *	@arg: User space argument
11481da177e4SLinus Torvalds  *
11491da177e4SLinus Torvalds  * Outputs:	None.
11501da177e4SLinus Torvalds  * Return:	0 if successful
11511da177e4SLinus Torvalds  *		-EFAULT if data unavailable
11521da177e4SLinus Torvalds  *		-ENODEV  if no such device/adapter
11531da177e4SLinus Torvalds  */
11541da177e4SLinus Torvalds static int
11551da177e4SLinus Torvalds mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
11561da177e4SLinus Torvalds {
11571da177e4SLinus Torvalds 	struct mpt_ioctl_iocinfo __user *uarg = (void __user *) arg;
11581da177e4SLinus Torvalds 	struct mpt_ioctl_iocinfo *karg;
11591da177e4SLinus Torvalds 	MPT_ADAPTER		*ioc;
11601da177e4SLinus Torvalds 	struct pci_dev		*pdev;
11611da177e4SLinus Torvalds 	struct Scsi_Host	*sh;
11621da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
11631da177e4SLinus Torvalds 	int			iocnum;
11641da177e4SLinus Torvalds 	int			numDevices = 0;
11651da177e4SLinus Torvalds 	unsigned int		max_id;
11661da177e4SLinus Torvalds 	int			ii;
1167b6fe4ddcSMoore, Eric Dean  	unsigned int		port;
11681da177e4SLinus Torvalds 	int			cim_rev;
11691da177e4SLinus Torvalds 	u8			revision;
11701da177e4SLinus Torvalds 
11711da177e4SLinus Torvalds 	dctlprintk((": mptctl_getiocinfo called.\n"));
11721da177e4SLinus Torvalds 	/* Add of PCI INFO results in unaligned access for
11731da177e4SLinus Torvalds 	 * IA64 and Sparc. Reset long to int. Return no PCI
11741da177e4SLinus Torvalds 	 * data for obsolete format.
11751da177e4SLinus Torvalds 	 */
11761da177e4SLinus Torvalds 	if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev0))
11771da177e4SLinus Torvalds 		cim_rev = 0;
11781da177e4SLinus Torvalds 	else if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev1))
11791da177e4SLinus Torvalds 		cim_rev = 1;
11801da177e4SLinus Torvalds 	else if (data_size == sizeof(struct mpt_ioctl_iocinfo))
11811da177e4SLinus Torvalds 		cim_rev = 2;
11821da177e4SLinus Torvalds 	else if (data_size == (sizeof(struct mpt_ioctl_iocinfo_rev0)+12))
11831da177e4SLinus Torvalds 		cim_rev = 0;	/* obsolete */
11841da177e4SLinus Torvalds 	else
11851da177e4SLinus Torvalds 		return -EFAULT;
11861da177e4SLinus Torvalds 
11871da177e4SLinus Torvalds 	karg = kmalloc(data_size, GFP_KERNEL);
11881da177e4SLinus Torvalds 	if (karg == NULL) {
11891da177e4SLinus Torvalds 		printk(KERN_ERR "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n",
11901da177e4SLinus Torvalds 				__FILE__, __LINE__);
11911da177e4SLinus Torvalds 		return -ENOMEM;
11921da177e4SLinus Torvalds 	}
11931da177e4SLinus Torvalds 
11941da177e4SLinus Torvalds 	if (copy_from_user(karg, uarg, data_size)) {
11951da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
11961da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_iocinfo struct @ %p\n",
11971da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
11981da177e4SLinus Torvalds 		kfree(karg);
11991da177e4SLinus Torvalds 		return -EFAULT;
12001da177e4SLinus Torvalds 	}
12011da177e4SLinus Torvalds 
12021da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
12031da177e4SLinus Torvalds 	    (ioc == NULL)) {
12041da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
12051da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
12061da177e4SLinus Torvalds 		kfree(karg);
12071da177e4SLinus Torvalds 		return -ENODEV;
12081da177e4SLinus Torvalds 	}
12091da177e4SLinus Torvalds 
1210b6fe4ddcSMoore, Eric Dean  	/* Verify the data transfer size is correct. */
12111da177e4SLinus Torvalds 	if (karg->hdr.maxDataSize != data_size) {
12121da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
12131da177e4SLinus Torvalds 			"Structure size mismatch. Command not completed.\n",
12141da177e4SLinus Torvalds 				__FILE__, __LINE__);
12151da177e4SLinus Torvalds 		kfree(karg);
12161da177e4SLinus Torvalds 		return -EFAULT;
12171da177e4SLinus Torvalds 	}
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds 	/* Fill in the data and return the structure to the calling
12201da177e4SLinus Torvalds 	 * program
12211da177e4SLinus Torvalds 	 */
12229cc1cfbcSMoore, Eric 	if (ioc->bus_type == SAS)
12239cc1cfbcSMoore, Eric 		karg->adapterType = MPT_IOCTL_INTERFACE_SAS;
12249cc1cfbcSMoore, Eric 	else if (ioc->bus_type == FC)
12251da177e4SLinus Torvalds 		karg->adapterType = MPT_IOCTL_INTERFACE_FC;
12261da177e4SLinus Torvalds 	else
12271da177e4SLinus Torvalds 		karg->adapterType = MPT_IOCTL_INTERFACE_SCSI;
12281da177e4SLinus Torvalds 
1229b6fe4ddcSMoore, Eric Dean  	if (karg->hdr.port > 1)
1230b6fe4ddcSMoore, Eric Dean  		return -EINVAL;
12311da177e4SLinus Torvalds 	port = karg->hdr.port;
12321da177e4SLinus Torvalds 
12331da177e4SLinus Torvalds 	karg->port = port;
12341da177e4SLinus Torvalds 	pdev = (struct pci_dev *) ioc->pcidev;
12351da177e4SLinus Torvalds 
12361da177e4SLinus Torvalds 	karg->pciId = pdev->device;
12371da177e4SLinus Torvalds 	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
12381da177e4SLinus Torvalds 	karg->hwRev = revision;
12391da177e4SLinus Torvalds 	karg->subSystemDevice = pdev->subsystem_device;
12401da177e4SLinus Torvalds 	karg->subSystemVendor = pdev->subsystem_vendor;
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds 	if (cim_rev == 1) {
12431da177e4SLinus Torvalds 		/* Get the PCI bus, device, and function numbers for the IOC
12441da177e4SLinus Torvalds 		 */
12451da177e4SLinus Torvalds 		karg->pciInfo.u.bits.busNumber = pdev->bus->number;
12461da177e4SLinus Torvalds 		karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn );
12471da177e4SLinus Torvalds 		karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn );
12481da177e4SLinus Torvalds 	} else if (cim_rev == 2) {
12491da177e4SLinus Torvalds 		/* Get the PCI bus, device, function and segment ID numbers
12501da177e4SLinus Torvalds 		   for the IOC */
12511da177e4SLinus Torvalds 		karg->pciInfo.u.bits.busNumber = pdev->bus->number;
12521da177e4SLinus Torvalds 		karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn );
12531da177e4SLinus Torvalds 		karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn );
12541da177e4SLinus Torvalds 		karg->pciInfo.segmentID = pci_domain_nr(pdev->bus);
12551da177e4SLinus Torvalds 	}
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	/* Get number of devices
12581da177e4SLinus Torvalds          */
12591da177e4SLinus Torvalds 	if ((sh = ioc->sh) != NULL) {
12601da177e4SLinus Torvalds 		 /* sh->max_id = maximum target ID + 1
12611da177e4SLinus Torvalds 		 */
12621da177e4SLinus Torvalds 		max_id = sh->max_id - 1;
12631da177e4SLinus Torvalds 		hd = (MPT_SCSI_HOST *) sh->hostdata;
12641da177e4SLinus Torvalds 
12651da177e4SLinus Torvalds 		/* Check all of the target structures and
12661da177e4SLinus Torvalds 		 * keep a counter.
12671da177e4SLinus Torvalds 		 */
12681da177e4SLinus Torvalds 		if (hd && hd->Targets) {
12691da177e4SLinus Torvalds 			for (ii = 0; ii <= max_id; ii++) {
12701da177e4SLinus Torvalds 				if (hd->Targets[ii])
12711da177e4SLinus Torvalds 					numDevices++;
12721da177e4SLinus Torvalds 			}
12731da177e4SLinus Torvalds 		}
12741da177e4SLinus Torvalds 	}
12751da177e4SLinus Torvalds 	karg->numDevices = numDevices;
12761da177e4SLinus Torvalds 
12771da177e4SLinus Torvalds 	/* Set the BIOS and FW Version
12781da177e4SLinus Torvalds 	 */
12791da177e4SLinus Torvalds 	karg->FWVersion = ioc->facts.FWVersion.Word;
12801da177e4SLinus Torvalds 	karg->BIOSVersion = ioc->biosVersion;
12811da177e4SLinus Torvalds 
12821da177e4SLinus Torvalds 	/* Set the Version Strings.
12831da177e4SLinus Torvalds 	 */
12841da177e4SLinus Torvalds 	strncpy (karg->driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH);
12851da177e4SLinus Torvalds 	karg->driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0';
12861da177e4SLinus Torvalds 
12871da177e4SLinus Torvalds 	karg->busChangeEvent = 0;
12881da177e4SLinus Torvalds 	karg->hostId = ioc->pfacts[port].PortSCSIID;
12891da177e4SLinus Torvalds 	karg->rsvd[0] = karg->rsvd[1] = 0;
12901da177e4SLinus Torvalds 
12911da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
12921da177e4SLinus Torvalds 	 */
12931da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, karg, data_size)) {
12941da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
12951da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_iocinfo struct @ %p\n",
12961da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
12971da177e4SLinus Torvalds 		kfree(karg);
12981da177e4SLinus Torvalds 		return -EFAULT;
12991da177e4SLinus Torvalds 	}
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds 	kfree(karg);
13021da177e4SLinus Torvalds 	return 0;
13031da177e4SLinus Torvalds }
13041da177e4SLinus Torvalds 
13051da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13061da177e4SLinus Torvalds /*
13071da177e4SLinus Torvalds  *	mptctl_gettargetinfo - Query the host adapter for target information.
13081da177e4SLinus Torvalds  *	@arg: User space argument
13091da177e4SLinus Torvalds  *
13101da177e4SLinus Torvalds  * Outputs:	None.
13111da177e4SLinus Torvalds  * Return:	0 if successful
13121da177e4SLinus Torvalds  *		-EFAULT if data unavailable
13131da177e4SLinus Torvalds  *		-ENODEV  if no such device/adapter
13141da177e4SLinus Torvalds  */
13151da177e4SLinus Torvalds static int
13161da177e4SLinus Torvalds mptctl_gettargetinfo (unsigned long arg)
13171da177e4SLinus Torvalds {
13181da177e4SLinus Torvalds 	struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
13191da177e4SLinus Torvalds 	struct mpt_ioctl_targetinfo karg;
13201da177e4SLinus Torvalds 	MPT_ADAPTER		*ioc;
13211da177e4SLinus Torvalds 	struct Scsi_Host	*sh;
13221da177e4SLinus Torvalds 	MPT_SCSI_HOST		*hd;
1323c7c82987SMoore, Eric Dean 	VirtTarget		*vdev;
13241da177e4SLinus Torvalds 	char			*pmem;
13251da177e4SLinus Torvalds 	int			*pdata;
13261da177e4SLinus Torvalds 	IOCPage2_t		*pIoc2;
13271da177e4SLinus Torvalds 	IOCPage3_t		*pIoc3;
13281da177e4SLinus Torvalds 	int			iocnum;
13291da177e4SLinus Torvalds 	int			numDevices = 0;
13301da177e4SLinus Torvalds 	unsigned int		max_id;
13311da177e4SLinus Torvalds 	int			id, jj, indexed_lun, lun_index;
13321da177e4SLinus Torvalds 	u32			lun;
13331da177e4SLinus Torvalds 	int			maxWordsLeft;
13341da177e4SLinus Torvalds 	int			numBytes;
13351da177e4SLinus Torvalds 	u8			port, devType, bus_id;
13361da177e4SLinus Torvalds 
13371da177e4SLinus Torvalds 	dctlprintk(("mptctl_gettargetinfo called.\n"));
13381da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
13391da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
13401da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
13411da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
13421da177e4SLinus Torvalds 		return -EFAULT;
13431da177e4SLinus Torvalds 	}
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
13461da177e4SLinus Torvalds 	    (ioc == NULL)) {
13471da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
13481da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
13491da177e4SLinus Torvalds 		return -ENODEV;
13501da177e4SLinus Torvalds 	}
13511da177e4SLinus Torvalds 
13521da177e4SLinus Torvalds 	/* Get the port number and set the maximum number of bytes
13531da177e4SLinus Torvalds 	 * in the returned structure.
13541da177e4SLinus Torvalds 	 * Ignore the port setting.
13551da177e4SLinus Torvalds 	 */
13561da177e4SLinus Torvalds 	numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
13571da177e4SLinus Torvalds 	maxWordsLeft = numBytes/sizeof(int);
13581da177e4SLinus Torvalds 	port = karg.hdr.port;
13591da177e4SLinus Torvalds 
13601da177e4SLinus Torvalds 	if (maxWordsLeft <= 0) {
13611da177e4SLinus Torvalds 		printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
13621da177e4SLinus Torvalds 				__FILE__, __LINE__);
13631da177e4SLinus Torvalds 		return -ENOMEM;
13641da177e4SLinus Torvalds 	}
13651da177e4SLinus Torvalds 
13661da177e4SLinus Torvalds 	/* Fill in the data and return the structure to the calling
13671da177e4SLinus Torvalds 	 * program
13681da177e4SLinus Torvalds 	 */
13691da177e4SLinus Torvalds 
13701da177e4SLinus Torvalds 	/* struct mpt_ioctl_targetinfo does not contain sufficient space
13711da177e4SLinus Torvalds 	 * for the target structures so when the IOCTL is called, there is
13721da177e4SLinus Torvalds 	 * not sufficient stack space for the structure. Allocate memory,
13731da177e4SLinus Torvalds 	 * populate the memory, copy back to the user, then free memory.
13741da177e4SLinus Torvalds 	 * targetInfo format:
13751da177e4SLinus Torvalds 	 * bits 31-24: reserved
13761da177e4SLinus Torvalds 	 *      23-16: LUN
13771da177e4SLinus Torvalds 	 *      15- 8: Bus Number
13781da177e4SLinus Torvalds 	 *       7- 0: Target ID
13791da177e4SLinus Torvalds 	 */
13801da177e4SLinus Torvalds 	pmem = kmalloc(numBytes, GFP_KERNEL);
13811da177e4SLinus Torvalds 	if (pmem == NULL) {
13821da177e4SLinus Torvalds 		printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
13831da177e4SLinus Torvalds 				__FILE__, __LINE__);
13841da177e4SLinus Torvalds 		return -ENOMEM;
13851da177e4SLinus Torvalds 	}
13861da177e4SLinus Torvalds 	memset(pmem, 0, numBytes);
13871da177e4SLinus Torvalds 	pdata =  (int *) pmem;
13881da177e4SLinus Torvalds 
13891da177e4SLinus Torvalds 	/* Get number of devices
13901da177e4SLinus Torvalds          */
13911da177e4SLinus Torvalds 	if ((sh = ioc->sh) != NULL) {
13921da177e4SLinus Torvalds 
13931da177e4SLinus Torvalds 		max_id = sh->max_id - 1;
13941da177e4SLinus Torvalds 		hd = (MPT_SCSI_HOST *) sh->hostdata;
13951da177e4SLinus Torvalds 
13961da177e4SLinus Torvalds 		/* Check all of the target structures.
13971da177e4SLinus Torvalds 		 * Save the Id and increment the counter,
13981da177e4SLinus Torvalds 		 * if ptr non-null.
13991da177e4SLinus Torvalds 		 * sh->max_id = maximum target ID + 1
14001da177e4SLinus Torvalds 		 */
14011da177e4SLinus Torvalds 		if (hd && hd->Targets) {
14021da177e4SLinus Torvalds 			mpt_findImVolumes(ioc);
1403466544d8SMoore, Eric Dean 			pIoc2 = ioc->raid_data.pIocPg2;
14041da177e4SLinus Torvalds 			for ( id = 0; id <= max_id; ) {
14051da177e4SLinus Torvalds 				if ( pIoc2 && pIoc2->NumActiveVolumes ) {
14061da177e4SLinus Torvalds 					if ( id == pIoc2->RaidVolume[0].VolumeID ) {
14071da177e4SLinus Torvalds 						if (maxWordsLeft <= 0) {
14081da177e4SLinus Torvalds 							printk(KERN_ERR "mptctl_gettargetinfo - "
14091da177e4SLinus Torvalds 			"buffer is full but volume is available on ioc %d\n, numDevices=%d", iocnum, numDevices);
14101da177e4SLinus Torvalds 							goto data_space_full;
14111da177e4SLinus Torvalds 						}
14121da177e4SLinus Torvalds 						if ( ( pIoc2->RaidVolume[0].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ) == 0 )
14131da177e4SLinus Torvalds                         				devType = 0x80;
14141da177e4SLinus Torvalds                     				else
14151da177e4SLinus Torvalds                         				devType = 0xC0;
14161da177e4SLinus Torvalds 						bus_id = pIoc2->RaidVolume[0].VolumeBus;
14171da177e4SLinus Torvalds 	            				numDevices++;
14181da177e4SLinus Torvalds                     				*pdata = ( (devType << 24) | (bus_id << 8) | id );
14191da177e4SLinus Torvalds 						dctlprintk((KERN_ERR "mptctl_gettargetinfo - "
14201da177e4SLinus Torvalds 		"volume ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata));
14211da177e4SLinus Torvalds                     				pdata++;
14221da177e4SLinus Torvalds 						--maxWordsLeft;
14231da177e4SLinus Torvalds 						goto next_id;
14241da177e4SLinus Torvalds 					} else {
1425466544d8SMoore, Eric Dean 						pIoc3 = ioc->raid_data.pIocPg3;
14261da177e4SLinus Torvalds             					for ( jj = 0; jj < pIoc3->NumPhysDisks; jj++ ) {
14271da177e4SLinus Torvalds                     					if ( pIoc3->PhysDisk[jj].PhysDiskID == id )
14281da177e4SLinus Torvalds 								goto next_id;
14291da177e4SLinus Torvalds 						}
14301da177e4SLinus Torvalds 					}
14311da177e4SLinus Torvalds 				}
14321da177e4SLinus Torvalds 				if ( (vdev = hd->Targets[id]) ) {
14331da177e4SLinus Torvalds 					for (jj = 0; jj <= MPT_LAST_LUN; jj++) {
14341da177e4SLinus Torvalds 						lun_index = (jj >> 5);
14351da177e4SLinus Torvalds 						indexed_lun = (jj % 32);
14361da177e4SLinus Torvalds 						lun = (1 << indexed_lun);
14371da177e4SLinus Torvalds 						if (vdev->luns[lun_index] & lun) {
14381da177e4SLinus Torvalds 							if (maxWordsLeft <= 0) {
14391da177e4SLinus Torvalds 								printk(KERN_ERR "mptctl_gettargetinfo - "
14401da177e4SLinus Torvalds 			"buffer is full but more targets are available on ioc %d numDevices=%d\n", iocnum, numDevices);
14411da177e4SLinus Torvalds 								goto data_space_full;
14421da177e4SLinus Torvalds 							}
14431da177e4SLinus Torvalds 							bus_id = vdev->bus_id;
14441da177e4SLinus Torvalds 							numDevices++;
14451da177e4SLinus Torvalds                             				*pdata = ( (jj << 16) | (bus_id << 8) | id );
14461da177e4SLinus Torvalds 							dctlprintk((KERN_ERR "mptctl_gettargetinfo - "
14471da177e4SLinus Torvalds 		"target ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata));
14481da177e4SLinus Torvalds 							pdata++;
14491da177e4SLinus Torvalds 							--maxWordsLeft;
14501da177e4SLinus Torvalds 						}
14511da177e4SLinus Torvalds 					}
14521da177e4SLinus Torvalds 				}
14531da177e4SLinus Torvalds next_id:
14541da177e4SLinus Torvalds 				id++;
14551da177e4SLinus Torvalds 			}
14561da177e4SLinus Torvalds 		}
14571da177e4SLinus Torvalds 	}
14581da177e4SLinus Torvalds data_space_full:
14591da177e4SLinus Torvalds 	karg.numDevices = numDevices;
14601da177e4SLinus Torvalds 
14611da177e4SLinus Torvalds 	/* Copy part of the data from kernel memory to user memory
14621da177e4SLinus Torvalds 	 */
14631da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg,
14641da177e4SLinus Torvalds 				sizeof(struct mpt_ioctl_targetinfo))) {
14651da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
14661da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
14671da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
14681da177e4SLinus Torvalds 		kfree(pmem);
14691da177e4SLinus Torvalds 		return -EFAULT;
14701da177e4SLinus Torvalds 	}
14711da177e4SLinus Torvalds 
14721da177e4SLinus Torvalds 	/* Copy the remaining data from kernel memory to user memory
14731da177e4SLinus Torvalds 	 */
14741da177e4SLinus Torvalds 	if (copy_to_user(uarg->targetInfo, pmem, numBytes)) {
14751da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
14761da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
14771da177e4SLinus Torvalds 				__FILE__, __LINE__, pdata);
14781da177e4SLinus Torvalds 		kfree(pmem);
14791da177e4SLinus Torvalds 		return -EFAULT;
14801da177e4SLinus Torvalds 	}
14811da177e4SLinus Torvalds 
14821da177e4SLinus Torvalds 	kfree(pmem);
14831da177e4SLinus Torvalds 
14841da177e4SLinus Torvalds 	return 0;
14851da177e4SLinus Torvalds }
14861da177e4SLinus Torvalds 
14871da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
14881da177e4SLinus Torvalds /* MPT IOCTL Test function.
14891da177e4SLinus Torvalds  *
14901da177e4SLinus Torvalds  * Outputs:	None.
14911da177e4SLinus Torvalds  * Return:	0 if successful
14921da177e4SLinus Torvalds  *		-EFAULT if data unavailable
14931da177e4SLinus Torvalds  *		-ENODEV  if no such device/adapter
14941da177e4SLinus Torvalds  */
14951da177e4SLinus Torvalds static int
14961da177e4SLinus Torvalds mptctl_readtest (unsigned long arg)
14971da177e4SLinus Torvalds {
14981da177e4SLinus Torvalds 	struct mpt_ioctl_test __user *uarg = (void __user *) arg;
14991da177e4SLinus Torvalds 	struct mpt_ioctl_test	 karg;
15001da177e4SLinus Torvalds 	MPT_ADAPTER *ioc;
15011da177e4SLinus Torvalds 	int iocnum;
15021da177e4SLinus Torvalds 
15031da177e4SLinus Torvalds 	dctlprintk(("mptctl_readtest called.\n"));
15041da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
15051da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_readtest - "
15061da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_test struct @ %p\n",
15071da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
15081da177e4SLinus Torvalds 		return -EFAULT;
15091da177e4SLinus Torvalds 	}
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
15121da177e4SLinus Torvalds 	    (ioc == NULL)) {
15131da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
15141da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
15151da177e4SLinus Torvalds 		return -ENODEV;
15161da177e4SLinus Torvalds 	}
15171da177e4SLinus Torvalds 
15181da177e4SLinus Torvalds 	/* Fill in the data and return the structure to the calling
15191da177e4SLinus Torvalds 	 * program
15201da177e4SLinus Torvalds 	 */
15211da177e4SLinus Torvalds 
15221da177e4SLinus Torvalds #ifdef MFCNT
15231da177e4SLinus Torvalds 	karg.chip_type = ioc->mfcnt;
15241da177e4SLinus Torvalds #else
15251da177e4SLinus Torvalds 	karg.chip_type = ioc->pcidev->device;
15261da177e4SLinus Torvalds #endif
15271da177e4SLinus Torvalds 	strncpy (karg.name, ioc->name, MPT_MAX_NAME);
15281da177e4SLinus Torvalds 	karg.name[MPT_MAX_NAME-1]='\0';
15291da177e4SLinus Torvalds 	strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH);
15301da177e4SLinus Torvalds 	karg.product[MPT_PRODUCT_LENGTH-1]='\0';
15311da177e4SLinus Torvalds 
15321da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
15331da177e4SLinus Torvalds 	 */
15341da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) {
15351da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_readtest - "
15361da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_test struct @ %p\n",
15371da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
15381da177e4SLinus Torvalds 		return -EFAULT;
15391da177e4SLinus Torvalds 	}
15401da177e4SLinus Torvalds 
15411da177e4SLinus Torvalds 	return 0;
15421da177e4SLinus Torvalds }
15431da177e4SLinus Torvalds 
15441da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
15451da177e4SLinus Torvalds /*
15461da177e4SLinus Torvalds  *	mptctl_eventquery - Query the host adapter for the event types
15471da177e4SLinus Torvalds  *	that are being logged.
15481da177e4SLinus Torvalds  *	@arg: User space argument
15491da177e4SLinus Torvalds  *
15501da177e4SLinus Torvalds  * Outputs:	None.
15511da177e4SLinus Torvalds  * Return:	0 if successful
15521da177e4SLinus Torvalds  *		-EFAULT if data unavailable
15531da177e4SLinus Torvalds  *		-ENODEV  if no such device/adapter
15541da177e4SLinus Torvalds  */
15551da177e4SLinus Torvalds static int
15561da177e4SLinus Torvalds mptctl_eventquery (unsigned long arg)
15571da177e4SLinus Torvalds {
15581da177e4SLinus Torvalds 	struct mpt_ioctl_eventquery __user *uarg = (void __user *) arg;
15591da177e4SLinus Torvalds 	struct mpt_ioctl_eventquery	 karg;
15601da177e4SLinus Torvalds 	MPT_ADAPTER *ioc;
15611da177e4SLinus Torvalds 	int iocnum;
15621da177e4SLinus Torvalds 
15631da177e4SLinus Torvalds 	dctlprintk(("mptctl_eventquery called.\n"));
15641da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
15651da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_eventquery - "
15661da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_eventquery struct @ %p\n",
15671da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
15681da177e4SLinus Torvalds 		return -EFAULT;
15691da177e4SLinus Torvalds 	}
15701da177e4SLinus Torvalds 
15711da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
15721da177e4SLinus Torvalds 	    (ioc == NULL)) {
15731da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
15741da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
15751da177e4SLinus Torvalds 		return -ENODEV;
15761da177e4SLinus Torvalds 	}
15771da177e4SLinus Torvalds 
15785b5ef4f6SMoore, Eric 	karg.eventEntries = MPTCTL_EVENT_LOG_SIZE;
15791da177e4SLinus Torvalds 	karg.eventTypes = ioc->eventTypes;
15801da177e4SLinus Torvalds 
15811da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
15821da177e4SLinus Torvalds 	 */
15831da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) {
15841da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_eventquery - "
15851da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_eventquery struct @ %p\n",
15861da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
15871da177e4SLinus Torvalds 		return -EFAULT;
15881da177e4SLinus Torvalds 	}
15891da177e4SLinus Torvalds 	return 0;
15901da177e4SLinus Torvalds }
15911da177e4SLinus Torvalds 
15921da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
15931da177e4SLinus Torvalds static int
15941da177e4SLinus Torvalds mptctl_eventenable (unsigned long arg)
15951da177e4SLinus Torvalds {
15961da177e4SLinus Torvalds 	struct mpt_ioctl_eventenable __user *uarg = (void __user *) arg;
15971da177e4SLinus Torvalds 	struct mpt_ioctl_eventenable	 karg;
15981da177e4SLinus Torvalds 	MPT_ADAPTER *ioc;
15991da177e4SLinus Torvalds 	int iocnum;
16001da177e4SLinus Torvalds 
16011da177e4SLinus Torvalds 	dctlprintk(("mptctl_eventenable called.\n"));
16021da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
16031da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_eventenable - "
16041da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_eventenable struct @ %p\n",
16051da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
16061da177e4SLinus Torvalds 		return -EFAULT;
16071da177e4SLinus Torvalds 	}
16081da177e4SLinus Torvalds 
16091da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
16101da177e4SLinus Torvalds 	    (ioc == NULL)) {
16111da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
16121da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
16131da177e4SLinus Torvalds 		return -ENODEV;
16141da177e4SLinus Torvalds 	}
16151da177e4SLinus Torvalds 
16161da177e4SLinus Torvalds 	if (ioc->events == NULL) {
16171da177e4SLinus Torvalds 		/* Have not yet allocated memory - do so now.
16181da177e4SLinus Torvalds 		 */
16191da177e4SLinus Torvalds 		int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
16201da177e4SLinus Torvalds 		ioc->events = kmalloc(sz, GFP_KERNEL);
16211da177e4SLinus Torvalds 		if (ioc->events == NULL) {
16221da177e4SLinus Torvalds 			printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
16231da177e4SLinus Torvalds 			return -ENOMEM;
16241da177e4SLinus Torvalds 		}
16251da177e4SLinus Torvalds 		memset(ioc->events, 0, sz);
16261da177e4SLinus Torvalds 		ioc->alloc_total += sz;
16271da177e4SLinus Torvalds 
16281da177e4SLinus Torvalds 		ioc->eventContext = 0;
16291da177e4SLinus Torvalds         }
16301da177e4SLinus Torvalds 
16311da177e4SLinus Torvalds 	/* Update the IOC event logging flag.
16321da177e4SLinus Torvalds 	 */
16331da177e4SLinus Torvalds 	ioc->eventTypes = karg.eventTypes;
16341da177e4SLinus Torvalds 
16351da177e4SLinus Torvalds 	return 0;
16361da177e4SLinus Torvalds }
16371da177e4SLinus Torvalds 
16381da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
16391da177e4SLinus Torvalds static int
16401da177e4SLinus Torvalds mptctl_eventreport (unsigned long arg)
16411da177e4SLinus Torvalds {
16421da177e4SLinus Torvalds 	struct mpt_ioctl_eventreport __user *uarg = (void __user *) arg;
16431da177e4SLinus Torvalds 	struct mpt_ioctl_eventreport	 karg;
16441da177e4SLinus Torvalds 	MPT_ADAPTER		 *ioc;
16451da177e4SLinus Torvalds 	int			 iocnum;
16461da177e4SLinus Torvalds 	int			 numBytes, maxEvents, max;
16471da177e4SLinus Torvalds 
16481da177e4SLinus Torvalds 	dctlprintk(("mptctl_eventreport called.\n"));
16491da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
16501da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_eventreport - "
16511da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_eventreport struct @ %p\n",
16521da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
16531da177e4SLinus Torvalds 		return -EFAULT;
16541da177e4SLinus Torvalds 	}
16551da177e4SLinus Torvalds 
16561da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
16571da177e4SLinus Torvalds 	    (ioc == NULL)) {
16581da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
16591da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
16601da177e4SLinus Torvalds 		return -ENODEV;
16611da177e4SLinus Torvalds 	}
16621da177e4SLinus Torvalds 
16631da177e4SLinus Torvalds 	numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
16641da177e4SLinus Torvalds 	maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
16651da177e4SLinus Torvalds 
16661da177e4SLinus Torvalds 
16675b5ef4f6SMoore, Eric 	max = MPTCTL_EVENT_LOG_SIZE < maxEvents ? MPTCTL_EVENT_LOG_SIZE : maxEvents;
16681da177e4SLinus Torvalds 
16691da177e4SLinus Torvalds 	/* If fewer than 1 event is requested, there must have
16701da177e4SLinus Torvalds 	 * been some type of error.
16711da177e4SLinus Torvalds 	 */
16721da177e4SLinus Torvalds 	if ((max < 1) || !ioc->events)
16731da177e4SLinus Torvalds 		return -ENODATA;
16741da177e4SLinus Torvalds 
1675ea5a7a82SMoore, Eric 	/* reset this flag so SIGIO can restart */
1676ea5a7a82SMoore, Eric 	ioc->aen_event_read_flag=0;
1677ea5a7a82SMoore, Eric 
16781da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
16791da177e4SLinus Torvalds 	 */
16801da177e4SLinus Torvalds 	numBytes = max * sizeof(MPT_IOCTL_EVENTS);
16811da177e4SLinus Torvalds 	if (copy_to_user(uarg->eventData, ioc->events, numBytes)) {
16821da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_eventreport - "
16831da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_eventreport struct @ %p\n",
16841da177e4SLinus Torvalds 				__FILE__, __LINE__, ioc->events);
16851da177e4SLinus Torvalds 		return -EFAULT;
16861da177e4SLinus Torvalds 	}
16871da177e4SLinus Torvalds 
16881da177e4SLinus Torvalds 	return 0;
16891da177e4SLinus Torvalds }
16901da177e4SLinus Torvalds 
16911da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
16921da177e4SLinus Torvalds static int
16931da177e4SLinus Torvalds mptctl_replace_fw (unsigned long arg)
16941da177e4SLinus Torvalds {
16951da177e4SLinus Torvalds 	struct mpt_ioctl_replace_fw __user *uarg = (void __user *) arg;
16961da177e4SLinus Torvalds 	struct mpt_ioctl_replace_fw	 karg;
16971da177e4SLinus Torvalds 	MPT_ADAPTER		 *ioc;
16981da177e4SLinus Torvalds 	int			 iocnum;
16991da177e4SLinus Torvalds 	int			 newFwSize;
17001da177e4SLinus Torvalds 
17011da177e4SLinus Torvalds 	dctlprintk(("mptctl_replace_fw called.\n"));
17021da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
17031da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
17041da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
17051da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
17061da177e4SLinus Torvalds 		return -EFAULT;
17071da177e4SLinus Torvalds 	}
17081da177e4SLinus Torvalds 
17091da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
17101da177e4SLinus Torvalds 	    (ioc == NULL)) {
17111da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
17121da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
17131da177e4SLinus Torvalds 		return -ENODEV;
17141da177e4SLinus Torvalds 	}
17151da177e4SLinus Torvalds 
17161da177e4SLinus Torvalds 	/* If caching FW, Free the old FW image
17171da177e4SLinus Torvalds 	 */
17181da177e4SLinus Torvalds 	if (ioc->cached_fw == NULL)
17191da177e4SLinus Torvalds 		return 0;
17201da177e4SLinus Torvalds 
17211da177e4SLinus Torvalds 	mpt_free_fw_memory(ioc);
17221da177e4SLinus Torvalds 
17231da177e4SLinus Torvalds 	/* Allocate memory for the new FW image
17241da177e4SLinus Torvalds 	 */
17251da177e4SLinus Torvalds 	newFwSize = karg.newImageSize;
17261da177e4SLinus Torvalds 
17271da177e4SLinus Torvalds 	if (newFwSize & 0x01)
17281da177e4SLinus Torvalds 		newFwSize += 1;
17291da177e4SLinus Torvalds 	if (newFwSize & 0x02)
17301da177e4SLinus Torvalds 		newFwSize += 2;
17311da177e4SLinus Torvalds 
17321da177e4SLinus Torvalds 	mpt_alloc_fw_memory(ioc, newFwSize);
17331da177e4SLinus Torvalds 	if (ioc->cached_fw == NULL)
17341da177e4SLinus Torvalds 		return -ENOMEM;
17351da177e4SLinus Torvalds 
17361da177e4SLinus Torvalds 	/* Copy the data from user memory to kernel space
17371da177e4SLinus Torvalds 	 */
17381da177e4SLinus Torvalds 	if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
17391da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
17401da177e4SLinus Torvalds 				"Unable to read in mpt_ioctl_replace_fw image "
17411da177e4SLinus Torvalds 				"@ %p\n", __FILE__, __LINE__, uarg);
17421da177e4SLinus Torvalds 		mpt_free_fw_memory(ioc);
17431da177e4SLinus Torvalds 		return -EFAULT;
17441da177e4SLinus Torvalds 	}
17451da177e4SLinus Torvalds 
17461da177e4SLinus Torvalds 	/* Update IOCFactsReply
17471da177e4SLinus Torvalds 	 */
17481da177e4SLinus Torvalds 	ioc->facts.FWImageSize = newFwSize;
17491da177e4SLinus Torvalds 	return 0;
17501da177e4SLinus Torvalds }
17511da177e4SLinus Torvalds 
17521da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
17531da177e4SLinus Torvalds /* MPT IOCTL MPTCOMMAND function.
17541da177e4SLinus Torvalds  * Cast the arg into the mpt_ioctl_mpt_command structure.
17551da177e4SLinus Torvalds  *
17561da177e4SLinus Torvalds  * Outputs:	None.
17571da177e4SLinus Torvalds  * Return:	0 if successful
17581da177e4SLinus Torvalds  *		-EBUSY  if previous command timout and IOC reset is not complete.
17591da177e4SLinus Torvalds  *		-EFAULT if data unavailable
17601da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
17611da177e4SLinus Torvalds  *		-ETIME	if timer expires
17621da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
17631da177e4SLinus Torvalds  */
17641da177e4SLinus Torvalds static int
17651da177e4SLinus Torvalds mptctl_mpt_command (unsigned long arg)
17661da177e4SLinus Torvalds {
17671da177e4SLinus Torvalds 	struct mpt_ioctl_command __user *uarg = (void __user *) arg;
17681da177e4SLinus Torvalds 	struct mpt_ioctl_command  karg;
17691da177e4SLinus Torvalds 	MPT_ADAPTER	*ioc;
17701da177e4SLinus Torvalds 	int		iocnum;
17711da177e4SLinus Torvalds 	int		rc;
17721da177e4SLinus Torvalds 
17731da177e4SLinus Torvalds 	dctlprintk(("mptctl_command called.\n"));
17741da177e4SLinus Torvalds 
17751da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
17761da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_mpt_command - "
17771da177e4SLinus Torvalds 			"Unable to read in mpt_ioctl_command struct @ %p\n",
17781da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
17791da177e4SLinus Torvalds 		return -EFAULT;
17801da177e4SLinus Torvalds 	}
17811da177e4SLinus Torvalds 
17821da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
17831da177e4SLinus Torvalds 	    (ioc == NULL)) {
17841da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
17851da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
17861da177e4SLinus Torvalds 		return -ENODEV;
17871da177e4SLinus Torvalds 	}
17881da177e4SLinus Torvalds 
17891da177e4SLinus Torvalds 	rc = mptctl_do_mpt_command (karg, &uarg->MF);
17901da177e4SLinus Torvalds 
17911da177e4SLinus Torvalds 	return rc;
17921da177e4SLinus Torvalds }
17931da177e4SLinus Torvalds 
17941da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
17951da177e4SLinus Torvalds /* Worker routine for the IOCTL MPTCOMMAND and MPTCOMMAND32 (sparc) commands.
17961da177e4SLinus Torvalds  *
17971da177e4SLinus Torvalds  * Outputs:	None.
17981da177e4SLinus Torvalds  * Return:	0 if successful
17991da177e4SLinus Torvalds  *		-EBUSY  if previous command timout and IOC reset is not complete.
18001da177e4SLinus Torvalds  *		-EFAULT if data unavailable
18011da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
18021da177e4SLinus Torvalds  *		-ETIME	if timer expires
18031da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
18041da177e4SLinus Torvalds  *		-EPERM if SCSI I/O and target is untagged
18051da177e4SLinus Torvalds  */
18061da177e4SLinus Torvalds static int
18071da177e4SLinus Torvalds mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
18081da177e4SLinus Torvalds {
18091da177e4SLinus Torvalds 	MPT_ADAPTER	*ioc;
18101da177e4SLinus Torvalds 	MPT_FRAME_HDR	*mf = NULL;
18111da177e4SLinus Torvalds 	MPIHeader_t	*hdr;
18121da177e4SLinus Torvalds 	char		*psge;
18131da177e4SLinus Torvalds 	struct buflist	bufIn;	/* data In buffer */
18141da177e4SLinus Torvalds 	struct buflist	bufOut; /* data Out buffer */
18151da177e4SLinus Torvalds 	dma_addr_t	dma_addr_in;
18161da177e4SLinus Torvalds 	dma_addr_t	dma_addr_out;
18171da177e4SLinus Torvalds 	int		sgSize = 0;	/* Num SG elements */
18181da177e4SLinus Torvalds 	int		iocnum, flagsLength;
18191da177e4SLinus Torvalds 	int		sz, rc = 0;
18201da177e4SLinus Torvalds 	int		msgContext;
18211da177e4SLinus Torvalds 	u16		req_idx;
18221da177e4SLinus Torvalds 	ulong 		timeout;
18231da177e4SLinus Torvalds 
18241da177e4SLinus Torvalds 	dctlprintk(("mptctl_do_mpt_command called.\n"));
18251da177e4SLinus Torvalds 	bufIn.kptr = bufOut.kptr = NULL;
18261da177e4SLinus Torvalds 
18271da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
18281da177e4SLinus Torvalds 	    (ioc == NULL)) {
18291da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
18301da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
18311da177e4SLinus Torvalds 		return -ENODEV;
18321da177e4SLinus Torvalds 	}
18331da177e4SLinus Torvalds 	if (!ioc->ioctl) {
18341da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
18351da177e4SLinus Torvalds 			"No memory available during driver init.\n",
18361da177e4SLinus Torvalds 				__FILE__, __LINE__);
18371da177e4SLinus Torvalds 		return -ENOMEM;
18381da177e4SLinus Torvalds 	} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
18391da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
18401da177e4SLinus Torvalds 			"Busy with IOC Reset \n", __FILE__, __LINE__);
18411da177e4SLinus Torvalds 		return -EBUSY;
18421da177e4SLinus Torvalds 	}
18431da177e4SLinus Torvalds 
18441da177e4SLinus Torvalds 	/* Verify that the final request frame will not be too large.
18451da177e4SLinus Torvalds 	 */
18461da177e4SLinus Torvalds 	sz = karg.dataSgeOffset * 4;
18471da177e4SLinus Torvalds 	if (karg.dataInSize > 0)
18481da177e4SLinus Torvalds 		sz += sizeof(dma_addr_t) + sizeof(u32);
18491da177e4SLinus Torvalds 	if (karg.dataOutSize > 0)
18501da177e4SLinus Torvalds 		sz += sizeof(dma_addr_t) + sizeof(u32);
18511da177e4SLinus Torvalds 
18521da177e4SLinus Torvalds 	if (sz > ioc->req_sz) {
18531da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
18541da177e4SLinus Torvalds 			"Request frame too large (%d) maximum (%d)\n",
18551da177e4SLinus Torvalds 				__FILE__, __LINE__, sz, ioc->req_sz);
18561da177e4SLinus Torvalds 		return -EFAULT;
18571da177e4SLinus Torvalds 	}
18581da177e4SLinus Torvalds 
18591da177e4SLinus Torvalds 	/* Get a free request frame and save the message context.
18601da177e4SLinus Torvalds 	 */
18611da177e4SLinus Torvalds         if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
18621da177e4SLinus Torvalds                 return -EAGAIN;
18631da177e4SLinus Torvalds 
18641da177e4SLinus Torvalds 	hdr = (MPIHeader_t *) mf;
18651da177e4SLinus Torvalds 	msgContext = le32_to_cpu(hdr->MsgContext);
18661da177e4SLinus Torvalds 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
18671da177e4SLinus Torvalds 
18681da177e4SLinus Torvalds 	/* Copy the request frame
18691da177e4SLinus Torvalds 	 * Reset the saved message context.
18701da177e4SLinus Torvalds 	 * Request frame in user space
18711da177e4SLinus Torvalds 	 */
18721da177e4SLinus Torvalds 	if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) {
18731da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
18741da177e4SLinus Torvalds 			"Unable to read MF from mpt_ioctl_command struct @ %p\n",
18751da177e4SLinus Torvalds 			__FILE__, __LINE__, mfPtr);
18761da177e4SLinus Torvalds 		rc = -EFAULT;
18771da177e4SLinus Torvalds 		goto done_free_mem;
18781da177e4SLinus Torvalds 	}
18791da177e4SLinus Torvalds 	hdr->MsgContext = cpu_to_le32(msgContext);
18801da177e4SLinus Torvalds 
18811da177e4SLinus Torvalds 
18821da177e4SLinus Torvalds 	/* Verify that this request is allowed.
18831da177e4SLinus Torvalds 	 */
18841da177e4SLinus Torvalds 	switch (hdr->Function) {
18851da177e4SLinus Torvalds 	case MPI_FUNCTION_IOC_FACTS:
18861da177e4SLinus Torvalds 	case MPI_FUNCTION_PORT_FACTS:
18871da177e4SLinus Torvalds 		karg.dataOutSize  = karg.dataInSize = 0;
18881da177e4SLinus Torvalds 		break;
18891da177e4SLinus Torvalds 
18901da177e4SLinus Torvalds 	case MPI_FUNCTION_CONFIG:
18911da177e4SLinus Torvalds 	case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
18921da177e4SLinus Torvalds 	case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
18931da177e4SLinus Torvalds 	case MPI_FUNCTION_FW_UPLOAD:
18941da177e4SLinus Torvalds 	case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
18951da177e4SLinus Torvalds 	case MPI_FUNCTION_FW_DOWNLOAD:
18961da177e4SLinus Torvalds 	case MPI_FUNCTION_FC_PRIMITIVE_SEND:
1897096f7a2aSMoore, Eric 	case MPI_FUNCTION_TOOLBOX:
1898096f7a2aSMoore, Eric 	case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
18991da177e4SLinus Torvalds 		break;
19001da177e4SLinus Torvalds 
19011da177e4SLinus Torvalds 	case MPI_FUNCTION_SCSI_IO_REQUEST:
19021da177e4SLinus Torvalds 		if (ioc->sh) {
19031da177e4SLinus Torvalds 			SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
1904c7c82987SMoore, Eric Dean 			VirtTarget	*pTarget = NULL;
19051da177e4SLinus Torvalds 			MPT_SCSI_HOST	*hd = NULL;
19061da177e4SLinus Torvalds 			int qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
19071da177e4SLinus Torvalds 			int scsidir = 0;
19081da177e4SLinus Torvalds 			int target = (int) pScsiReq->TargetID;
19091da177e4SLinus Torvalds 			int dataSize;
19101da177e4SLinus Torvalds 
19111da177e4SLinus Torvalds 			if ((target < 0) || (target >= ioc->sh->max_id)) {
19121da177e4SLinus Torvalds 				printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
19131da177e4SLinus Torvalds 					"Target ID out of bounds. \n",
19141da177e4SLinus Torvalds 					__FILE__, __LINE__);
19151da177e4SLinus Torvalds 				rc = -ENODEV;
19161da177e4SLinus Torvalds 				goto done_free_mem;
19171da177e4SLinus Torvalds 			}
19181da177e4SLinus Torvalds 
19195f07e249SMoore, Eric 			pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
19205f07e249SMoore, Eric 			pScsiReq->MsgFlags |= mpt_msg_flags();
19215f07e249SMoore, Eric 
19221da177e4SLinus Torvalds 
19231da177e4SLinus Torvalds 			/* verify that app has not requested
19241da177e4SLinus Torvalds 			 *	more sense data than driver
19251da177e4SLinus Torvalds 			 *	can provide, if so, reset this parameter
19261da177e4SLinus Torvalds 			 * set the sense buffer pointer low address
19271da177e4SLinus Torvalds 			 * update the control field to specify Q type
19281da177e4SLinus Torvalds 			 */
19291da177e4SLinus Torvalds 			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
19301da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
19311da177e4SLinus Torvalds 			else
19321da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = karg.maxSenseBytes;
19331da177e4SLinus Torvalds 
19341da177e4SLinus Torvalds 			pScsiReq->SenseBufferLowAddr =
19351da177e4SLinus Torvalds 				cpu_to_le32(ioc->sense_buf_low_dma
19361da177e4SLinus Torvalds 				   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
19371da177e4SLinus Torvalds 
19381da177e4SLinus Torvalds 			if ((hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) {
19391da177e4SLinus Torvalds 				if (hd->Targets)
19401da177e4SLinus Torvalds 					pTarget = hd->Targets[target];
19411da177e4SLinus Torvalds 			}
19421da177e4SLinus Torvalds 
19431da177e4SLinus Torvalds 			if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
19441da177e4SLinus Torvalds 				qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
19451da177e4SLinus Torvalds 
19461da177e4SLinus Torvalds 			/* Have the IOCTL driver set the direction based
19471da177e4SLinus Torvalds 			 * on the dataOutSize (ordering issue with Sparc).
19481da177e4SLinus Torvalds 			 */
19491da177e4SLinus Torvalds 			if (karg.dataOutSize > 0) {
19501da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_WRITE;
19511da177e4SLinus Torvalds 				dataSize = karg.dataOutSize;
19521da177e4SLinus Torvalds 			} else {
19531da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_READ;
19541da177e4SLinus Torvalds 				dataSize = karg.dataInSize;
19551da177e4SLinus Torvalds 			}
19561da177e4SLinus Torvalds 
19571da177e4SLinus Torvalds 			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
19581da177e4SLinus Torvalds 			pScsiReq->DataLength = cpu_to_le32(dataSize);
19591da177e4SLinus Torvalds 
19601da177e4SLinus Torvalds 			ioc->ioctl->reset = MPTCTL_RESET_OK;
19611da177e4SLinus Torvalds 			ioc->ioctl->target = target;
19621da177e4SLinus Torvalds 
19631da177e4SLinus Torvalds 		} else {
19641da177e4SLinus Torvalds 			printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
19651da177e4SLinus Torvalds 				"SCSI driver is not loaded. \n",
19661da177e4SLinus Torvalds 					__FILE__, __LINE__);
19671da177e4SLinus Torvalds 			rc = -EFAULT;
19681da177e4SLinus Torvalds 			goto done_free_mem;
19691da177e4SLinus Torvalds 		}
19701da177e4SLinus Torvalds 		break;
19711da177e4SLinus Torvalds 
1972096f7a2aSMoore, Eric 	case MPI_FUNCTION_SMP_PASSTHROUGH:
1973096f7a2aSMoore, Eric 		/* Check mf->PassthruFlags to determine if
1974096f7a2aSMoore, Eric 		 * transfer is ImmediateMode or not.
1975096f7a2aSMoore, Eric 		 * Immediate mode returns data in the ReplyFrame.
1976096f7a2aSMoore, Eric 		 * Else, we are sending request and response data
1977096f7a2aSMoore, Eric 		 * in two SGLs at the end of the mf.
1978096f7a2aSMoore, Eric 		 */
1979096f7a2aSMoore, Eric 		break;
1980096f7a2aSMoore, Eric 
1981096f7a2aSMoore, Eric 	case MPI_FUNCTION_SATA_PASSTHROUGH:
1982096f7a2aSMoore, Eric 		if (!ioc->sh) {
1983096f7a2aSMoore, Eric 			printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
1984096f7a2aSMoore, Eric 				"SCSI driver is not loaded. \n",
1985096f7a2aSMoore, Eric 					__FILE__, __LINE__);
1986096f7a2aSMoore, Eric 			rc = -EFAULT;
1987096f7a2aSMoore, Eric 			goto done_free_mem;
1988096f7a2aSMoore, Eric 		}
1989096f7a2aSMoore, Eric 		break;
1990096f7a2aSMoore, Eric 
19911da177e4SLinus Torvalds 	case MPI_FUNCTION_RAID_ACTION:
19921da177e4SLinus Torvalds 		/* Just add a SGE
19931da177e4SLinus Torvalds 		 */
19941da177e4SLinus Torvalds 		break;
19951da177e4SLinus Torvalds 
19961da177e4SLinus Torvalds 	case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
19971da177e4SLinus Torvalds 		if (ioc->sh) {
19981da177e4SLinus Torvalds 			SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
19991da177e4SLinus Torvalds 			int qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
20001da177e4SLinus Torvalds 			int scsidir = MPI_SCSIIO_CONTROL_READ;
20011da177e4SLinus Torvalds 			int dataSize;
20021da177e4SLinus Torvalds 
20035f07e249SMoore, Eric 			pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
20045f07e249SMoore, Eric 			pScsiReq->MsgFlags |= mpt_msg_flags();
20055f07e249SMoore, Eric 
20061da177e4SLinus Torvalds 
20071da177e4SLinus Torvalds 			/* verify that app has not requested
20081da177e4SLinus Torvalds 			 *	more sense data than driver
20091da177e4SLinus Torvalds 			 *	can provide, if so, reset this parameter
20101da177e4SLinus Torvalds 			 * set the sense buffer pointer low address
20111da177e4SLinus Torvalds 			 * update the control field to specify Q type
20121da177e4SLinus Torvalds 			 */
20131da177e4SLinus Torvalds 			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
20141da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
20151da177e4SLinus Torvalds 			else
20161da177e4SLinus Torvalds 				pScsiReq->SenseBufferLength = karg.maxSenseBytes;
20171da177e4SLinus Torvalds 
20181da177e4SLinus Torvalds 			pScsiReq->SenseBufferLowAddr =
20191da177e4SLinus Torvalds 				cpu_to_le32(ioc->sense_buf_low_dma
20201da177e4SLinus Torvalds 				   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
20211da177e4SLinus Torvalds 
20221da177e4SLinus Torvalds 			/* All commands to physical devices are tagged
20231da177e4SLinus Torvalds 			 */
20241da177e4SLinus Torvalds 
20251da177e4SLinus Torvalds 			/* Have the IOCTL driver set the direction based
20261da177e4SLinus Torvalds 			 * on the dataOutSize (ordering issue with Sparc).
20271da177e4SLinus Torvalds 			 */
20281da177e4SLinus Torvalds 			if (karg.dataOutSize > 0) {
20291da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_WRITE;
20301da177e4SLinus Torvalds 				dataSize = karg.dataOutSize;
20311da177e4SLinus Torvalds 			} else {
20321da177e4SLinus Torvalds 				scsidir = MPI_SCSIIO_CONTROL_READ;
20331da177e4SLinus Torvalds 				dataSize = karg.dataInSize;
20341da177e4SLinus Torvalds 			}
20351da177e4SLinus Torvalds 
20361da177e4SLinus Torvalds 			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
20371da177e4SLinus Torvalds 			pScsiReq->DataLength = cpu_to_le32(dataSize);
20381da177e4SLinus Torvalds 
20391da177e4SLinus Torvalds 			ioc->ioctl->reset = MPTCTL_RESET_OK;
20401da177e4SLinus Torvalds 			ioc->ioctl->target = pScsiReq->TargetID;
20411da177e4SLinus Torvalds 		} else {
20421da177e4SLinus Torvalds 			printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
20431da177e4SLinus Torvalds 				"SCSI driver is not loaded. \n",
20441da177e4SLinus Torvalds 					__FILE__, __LINE__);
20451da177e4SLinus Torvalds 			rc = -EFAULT;
20461da177e4SLinus Torvalds 			goto done_free_mem;
20471da177e4SLinus Torvalds 		}
20481da177e4SLinus Torvalds 		break;
20491da177e4SLinus Torvalds 
20501da177e4SLinus Torvalds 	case MPI_FUNCTION_SCSI_TASK_MGMT:
20511da177e4SLinus Torvalds 		{
20521da177e4SLinus Torvalds 			MPT_SCSI_HOST *hd = NULL;
20531da177e4SLinus Torvalds 			if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) {
20541da177e4SLinus Torvalds 				printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
20551da177e4SLinus Torvalds 					"SCSI driver not loaded or SCSI host not found. \n",
20561da177e4SLinus Torvalds 					__FILE__, __LINE__);
20571da177e4SLinus Torvalds 				rc = -EFAULT;
20581da177e4SLinus Torvalds 				goto done_free_mem;
20591da177e4SLinus Torvalds 			} else if (mptctl_set_tm_flags(hd) != 0) {
20601da177e4SLinus Torvalds 				rc = -EPERM;
20611da177e4SLinus Torvalds 				goto done_free_mem;
20621da177e4SLinus Torvalds 			}
20631da177e4SLinus Torvalds 		}
20641da177e4SLinus Torvalds 		break;
20651da177e4SLinus Torvalds 
20661da177e4SLinus Torvalds 	case MPI_FUNCTION_IOC_INIT:
20671da177e4SLinus Torvalds 		{
20681da177e4SLinus Torvalds 			IOCInit_t	*pInit = (IOCInit_t *) mf;
20691da177e4SLinus Torvalds 			u32		high_addr, sense_high;
20701da177e4SLinus Torvalds 
20711da177e4SLinus Torvalds 			/* Verify that all entries in the IOC INIT match
20721da177e4SLinus Torvalds 			 * existing setup (and in LE format).
20731da177e4SLinus Torvalds 			 */
20741da177e4SLinus Torvalds 			if (sizeof(dma_addr_t) == sizeof(u64)) {
20751da177e4SLinus Torvalds 				high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32));
20761da177e4SLinus Torvalds 				sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
20771da177e4SLinus Torvalds 			} else {
20781da177e4SLinus Torvalds 				high_addr = 0;
20791da177e4SLinus Torvalds 				sense_high= 0;
20801da177e4SLinus Torvalds 			}
20811da177e4SLinus Torvalds 
20821da177e4SLinus Torvalds 			if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) ||
20831da177e4SLinus Torvalds 				(pInit->MaxBuses != ioc->facts.MaxBuses) ||
20841da177e4SLinus Torvalds 				(pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
20851da177e4SLinus Torvalds 				(pInit->HostMfaHighAddr != high_addr) ||
20861da177e4SLinus Torvalds 				(pInit->SenseBufferHighAddr != sense_high)) {
20871da177e4SLinus Torvalds 				printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
20881da177e4SLinus Torvalds 					"IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n",
20891da177e4SLinus Torvalds 					__FILE__, __LINE__);
20901da177e4SLinus Torvalds 				rc = -EFAULT;
20911da177e4SLinus Torvalds 				goto done_free_mem;
20921da177e4SLinus Torvalds 			}
20931da177e4SLinus Torvalds 		}
20941da177e4SLinus Torvalds 		break;
20951da177e4SLinus Torvalds 	default:
20961da177e4SLinus Torvalds 		/*
20971da177e4SLinus Torvalds 		 * MPI_FUNCTION_PORT_ENABLE
20981da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_CMD_BUFFER_POST
20991da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_ASSIST
21001da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_STATUS_SEND
21011da177e4SLinus Torvalds 		 * MPI_FUNCTION_TARGET_MODE_ABORT
21021da177e4SLinus Torvalds 		 * MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET
21031da177e4SLinus Torvalds 		 * MPI_FUNCTION_IO_UNIT_RESET
21041da177e4SLinus Torvalds 		 * MPI_FUNCTION_HANDSHAKE
21051da177e4SLinus Torvalds 		 * MPI_FUNCTION_REPLY_FRAME_REMOVAL
21061da177e4SLinus Torvalds 		 * MPI_FUNCTION_EVENT_NOTIFICATION
21071da177e4SLinus Torvalds 		 *  (driver handles event notification)
21081da177e4SLinus Torvalds 		 * MPI_FUNCTION_EVENT_ACK
21091da177e4SLinus Torvalds 		 */
21101da177e4SLinus Torvalds 
21111da177e4SLinus Torvalds 		/*  What to do with these???  CHECK ME!!!
21121da177e4SLinus Torvalds 			MPI_FUNCTION_FC_LINK_SRVC_BUF_POST
21131da177e4SLinus Torvalds 			MPI_FUNCTION_FC_LINK_SRVC_RSP
21141da177e4SLinus Torvalds 			MPI_FUNCTION_FC_ABORT
21151da177e4SLinus Torvalds 			MPI_FUNCTION_LAN_SEND
21161da177e4SLinus Torvalds 			MPI_FUNCTION_LAN_RECEIVE
21171da177e4SLinus Torvalds 		 	MPI_FUNCTION_LAN_RESET
21181da177e4SLinus Torvalds 		*/
21191da177e4SLinus Torvalds 
21201da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
21211da177e4SLinus Torvalds 			"Illegal request (function 0x%x) \n",
21221da177e4SLinus Torvalds 			__FILE__, __LINE__, hdr->Function);
21231da177e4SLinus Torvalds 		rc = -EFAULT;
21241da177e4SLinus Torvalds 		goto done_free_mem;
21251da177e4SLinus Torvalds 	}
21261da177e4SLinus Torvalds 
21271da177e4SLinus Torvalds 	/* Add the SGL ( at most one data in SGE and one data out SGE )
21281da177e4SLinus Torvalds 	 * In the case of two SGE's - the data out (write) will always
21291da177e4SLinus Torvalds 	 * preceede the data in (read) SGE. psgList is used to free the
21301da177e4SLinus Torvalds 	 * allocated memory.
21311da177e4SLinus Torvalds 	 */
21321da177e4SLinus Torvalds 	psge = (char *) (((int *) mf) + karg.dataSgeOffset);
21331da177e4SLinus Torvalds 	flagsLength = 0;
21341da177e4SLinus Torvalds 
21351da177e4SLinus Torvalds 	/* bufIn and bufOut are used for user to kernel space transfers
21361da177e4SLinus Torvalds 	 */
21371da177e4SLinus Torvalds 	bufIn.kptr = bufOut.kptr = NULL;
21381da177e4SLinus Torvalds 	bufIn.len = bufOut.len = 0;
21391da177e4SLinus Torvalds 
21401da177e4SLinus Torvalds 	if (karg.dataOutSize > 0)
21411da177e4SLinus Torvalds 		sgSize ++;
21421da177e4SLinus Torvalds 
21431da177e4SLinus Torvalds 	if (karg.dataInSize > 0)
21441da177e4SLinus Torvalds 		sgSize ++;
21451da177e4SLinus Torvalds 
21461da177e4SLinus Torvalds 	if (sgSize > 0) {
21471da177e4SLinus Torvalds 
21481da177e4SLinus Torvalds 		/* Set up the dataOut memory allocation */
21491da177e4SLinus Torvalds 		if (karg.dataOutSize > 0) {
21501da177e4SLinus Torvalds 			if (karg.dataInSize > 0) {
21511da177e4SLinus Torvalds 				flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
21521da177e4SLinus Torvalds 						MPI_SGE_FLAGS_END_OF_BUFFER |
21531da177e4SLinus Torvalds 						MPI_SGE_FLAGS_DIRECTION |
21541da177e4SLinus Torvalds 						mpt_addr_size() )
21551da177e4SLinus Torvalds 						<< MPI_SGE_FLAGS_SHIFT;
21561da177e4SLinus Torvalds 			} else {
21571da177e4SLinus Torvalds 				flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
21581da177e4SLinus Torvalds 			}
21591da177e4SLinus Torvalds 			flagsLength |= karg.dataOutSize;
21601da177e4SLinus Torvalds 			bufOut.len = karg.dataOutSize;
21611da177e4SLinus Torvalds 			bufOut.kptr = pci_alloc_consistent(
21621da177e4SLinus Torvalds 					ioc->pcidev, bufOut.len, &dma_addr_out);
21631da177e4SLinus Torvalds 
21641da177e4SLinus Torvalds 			if (bufOut.kptr == NULL) {
21651da177e4SLinus Torvalds 				rc = -ENOMEM;
21661da177e4SLinus Torvalds 				goto done_free_mem;
21671da177e4SLinus Torvalds 			} else {
21681da177e4SLinus Torvalds 				/* Set up this SGE.
21691da177e4SLinus Torvalds 				 * Copy to MF and to sglbuf
21701da177e4SLinus Torvalds 				 */
21711da177e4SLinus Torvalds 				mpt_add_sge(psge, flagsLength, dma_addr_out);
21721da177e4SLinus Torvalds 				psge += (sizeof(u32) + sizeof(dma_addr_t));
21731da177e4SLinus Torvalds 
21741da177e4SLinus Torvalds 				/* Copy user data to kernel space.
21751da177e4SLinus Torvalds 				 */
21761da177e4SLinus Torvalds 				if (copy_from_user(bufOut.kptr,
21771da177e4SLinus Torvalds 						karg.dataOutBufPtr,
21781da177e4SLinus Torvalds 						bufOut.len)) {
21791da177e4SLinus Torvalds 					printk(KERN_ERR
21801da177e4SLinus Torvalds 						"%s@%d::mptctl_do_mpt_command - Unable "
21811da177e4SLinus Torvalds 						"to read user data "
21821da177e4SLinus Torvalds 						"struct @ %p\n",
21831da177e4SLinus Torvalds 						__FILE__, __LINE__,karg.dataOutBufPtr);
21841da177e4SLinus Torvalds 					rc =  -EFAULT;
21851da177e4SLinus Torvalds 					goto done_free_mem;
21861da177e4SLinus Torvalds 				}
21871da177e4SLinus Torvalds 			}
21881da177e4SLinus Torvalds 		}
21891da177e4SLinus Torvalds 
21901da177e4SLinus Torvalds 		if (karg.dataInSize > 0) {
21911da177e4SLinus Torvalds 			flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
21921da177e4SLinus Torvalds 			flagsLength |= karg.dataInSize;
21931da177e4SLinus Torvalds 
21941da177e4SLinus Torvalds 			bufIn.len = karg.dataInSize;
21951da177e4SLinus Torvalds 			bufIn.kptr = pci_alloc_consistent(ioc->pcidev,
21961da177e4SLinus Torvalds 					bufIn.len, &dma_addr_in);
21971da177e4SLinus Torvalds 
21981da177e4SLinus Torvalds 			if (bufIn.kptr == NULL) {
21991da177e4SLinus Torvalds 				rc = -ENOMEM;
22001da177e4SLinus Torvalds 				goto done_free_mem;
22011da177e4SLinus Torvalds 			} else {
22021da177e4SLinus Torvalds 				/* Set up this SGE
22031da177e4SLinus Torvalds 				 * Copy to MF and to sglbuf
22041da177e4SLinus Torvalds 				 */
22051da177e4SLinus Torvalds 				mpt_add_sge(psge, flagsLength, dma_addr_in);
22061da177e4SLinus Torvalds 			}
22071da177e4SLinus Torvalds 		}
22081da177e4SLinus Torvalds 	} else  {
22091da177e4SLinus Torvalds 		/* Add a NULL SGE
22101da177e4SLinus Torvalds 		 */
22111da177e4SLinus Torvalds 		mpt_add_sge(psge, flagsLength, (dma_addr_t) -1);
22121da177e4SLinus Torvalds 	}
22131da177e4SLinus Torvalds 
22141da177e4SLinus Torvalds 	ioc->ioctl->wait_done = 0;
22151da177e4SLinus Torvalds 	if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
22161da177e4SLinus Torvalds 
22171da177e4SLinus Torvalds 		DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf);
22181da177e4SLinus Torvalds 
22191da177e4SLinus Torvalds 		if (mpt_send_handshake_request(mptctl_id, ioc,
22201da177e4SLinus Torvalds 			sizeof(SCSITaskMgmt_t), (u32*)mf,
22211da177e4SLinus Torvalds 			CAN_SLEEP) != 0) {
22221da177e4SLinus Torvalds 			dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
22231da177e4SLinus Torvalds 				" (ioc %p, mf %p) \n", ioc->name,
22241da177e4SLinus Torvalds 				ioc, mf));
22251da177e4SLinus Torvalds 			mptctl_free_tm_flags(ioc);
22261da177e4SLinus Torvalds 			rc = -ENODATA;
22271da177e4SLinus Torvalds 			goto done_free_mem;
22281da177e4SLinus Torvalds 		}
22291da177e4SLinus Torvalds 
22301da177e4SLinus Torvalds 	} else
22311da177e4SLinus Torvalds 		mpt_put_msg_frame(mptctl_id, ioc, mf);
22321da177e4SLinus Torvalds 
22331da177e4SLinus Torvalds 	/* Now wait for the command to complete */
22341da177e4SLinus Torvalds 	timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
223586a7dcaaSMoore, Eric 	timeout = wait_event_timeout(mptctl_wait,
22361da177e4SLinus Torvalds 	     ioc->ioctl->wait_done == 1,
22371da177e4SLinus Torvalds 	     HZ*timeout);
22381da177e4SLinus Torvalds 
22391da177e4SLinus Torvalds 	if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) {
22401da177e4SLinus Torvalds 	/* Now we need to reset the board */
22411da177e4SLinus Torvalds 
22421da177e4SLinus Torvalds 		if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT)
22431da177e4SLinus Torvalds 			mptctl_free_tm_flags(ioc);
22441da177e4SLinus Torvalds 
22451da177e4SLinus Torvalds 		mptctl_timeout_expired(ioc->ioctl);
22461da177e4SLinus Torvalds 		rc = -ENODATA;
22471da177e4SLinus Torvalds 		goto done_free_mem;
22481da177e4SLinus Torvalds 	}
22491da177e4SLinus Torvalds 
22501da177e4SLinus Torvalds 	mf = NULL;
22511da177e4SLinus Torvalds 
22521da177e4SLinus Torvalds 	/* If a valid reply frame, copy to the user.
22531da177e4SLinus Torvalds 	 * Offset 2: reply length in U32's
22541da177e4SLinus Torvalds 	 */
22551da177e4SLinus Torvalds 	if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) {
22561da177e4SLinus Torvalds 		if (karg.maxReplyBytes < ioc->reply_sz) {
22571da177e4SLinus Torvalds 			 sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
22581da177e4SLinus Torvalds 		} else {
22591da177e4SLinus Torvalds 			 sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
22601da177e4SLinus Torvalds 		}
22611da177e4SLinus Torvalds 
22621da177e4SLinus Torvalds 		if (sz > 0) {
22631da177e4SLinus Torvalds 			if (copy_to_user(karg.replyFrameBufPtr,
22641da177e4SLinus Torvalds 				 &ioc->ioctl->ReplyFrame, sz)){
22651da177e4SLinus Torvalds 				 printk(KERN_ERR
22661da177e4SLinus Torvalds 				     "%s@%d::mptctl_do_mpt_command - "
22671da177e4SLinus Torvalds 				 "Unable to write out reply frame %p\n",
22681da177e4SLinus Torvalds 				 __FILE__, __LINE__, karg.replyFrameBufPtr);
22691da177e4SLinus Torvalds 				 rc =  -ENODATA;
22701da177e4SLinus Torvalds 				 goto done_free_mem;
22711da177e4SLinus Torvalds 			}
22721da177e4SLinus Torvalds 		}
22731da177e4SLinus Torvalds 	}
22741da177e4SLinus Torvalds 
22751da177e4SLinus Torvalds 	/* If valid sense data, copy to user.
22761da177e4SLinus Torvalds 	 */
22771da177e4SLinus Torvalds 	if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
22781da177e4SLinus Torvalds 		sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
22791da177e4SLinus Torvalds 		if (sz > 0) {
22801da177e4SLinus Torvalds 			if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
22811da177e4SLinus Torvalds 				printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
22821da177e4SLinus Torvalds 				"Unable to write sense data to user %p\n",
22831da177e4SLinus Torvalds 				__FILE__, __LINE__,
22841da177e4SLinus Torvalds 				karg.senseDataPtr);
22851da177e4SLinus Torvalds 				rc =  -ENODATA;
22861da177e4SLinus Torvalds 				goto done_free_mem;
22871da177e4SLinus Torvalds 			}
22881da177e4SLinus Torvalds 		}
22891da177e4SLinus Torvalds 	}
22901da177e4SLinus Torvalds 
22911da177e4SLinus Torvalds 	/* If the overall status is _GOOD and data in, copy data
22921da177e4SLinus Torvalds 	 * to user.
22931da177e4SLinus Torvalds 	 */
22941da177e4SLinus Torvalds 	if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) &&
22951da177e4SLinus Torvalds 				(karg.dataInSize > 0) && (bufIn.kptr)) {
22961da177e4SLinus Torvalds 
22971da177e4SLinus Torvalds 		if (copy_to_user(karg.dataInBufPtr,
22981da177e4SLinus Torvalds 				 bufIn.kptr, karg.dataInSize)) {
22991da177e4SLinus Torvalds 			printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
23001da177e4SLinus Torvalds 				"Unable to write data to user %p\n",
23011da177e4SLinus Torvalds 				__FILE__, __LINE__,
23021da177e4SLinus Torvalds 				karg.dataInBufPtr);
23031da177e4SLinus Torvalds 			rc =  -ENODATA;
23041da177e4SLinus Torvalds 		}
23051da177e4SLinus Torvalds 	}
23061da177e4SLinus Torvalds 
23071da177e4SLinus Torvalds done_free_mem:
23081da177e4SLinus Torvalds 
23091da177e4SLinus Torvalds 	ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD |
23101da177e4SLinus Torvalds 		MPT_IOCTL_STATUS_SENSE_VALID |
23111da177e4SLinus Torvalds 		MPT_IOCTL_STATUS_RF_VALID );
23121da177e4SLinus Torvalds 
23131da177e4SLinus Torvalds 	/* Free the allocated memory.
23141da177e4SLinus Torvalds 	 */
23151da177e4SLinus Torvalds 	if (bufOut.kptr != NULL) {
23161da177e4SLinus Torvalds 		pci_free_consistent(ioc->pcidev,
23171da177e4SLinus Torvalds 			bufOut.len, (void *) bufOut.kptr, dma_addr_out);
23181da177e4SLinus Torvalds 	}
23191da177e4SLinus Torvalds 
23201da177e4SLinus Torvalds 	if (bufIn.kptr != NULL) {
23211da177e4SLinus Torvalds 		pci_free_consistent(ioc->pcidev,
23221da177e4SLinus Torvalds 			bufIn.len, (void *) bufIn.kptr, dma_addr_in);
23231da177e4SLinus Torvalds 	}
23241da177e4SLinus Torvalds 
23251da177e4SLinus Torvalds 	/* mf is null if command issued successfully
23261da177e4SLinus Torvalds 	 * otherwise, failure occured after mf acquired.
23271da177e4SLinus Torvalds 	 */
23281da177e4SLinus Torvalds 	if (mf)
23291da177e4SLinus Torvalds 		mpt_free_msg_frame(ioc, mf);
23301da177e4SLinus Torvalds 
23311da177e4SLinus Torvalds 	return rc;
23321da177e4SLinus Torvalds }
23331da177e4SLinus Torvalds 
23341da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2335*ba856d32SEric Moore /* Prototype Routine for the HOST INFO command.
23361da177e4SLinus Torvalds  *
23371da177e4SLinus Torvalds  * Outputs:	None.
23381da177e4SLinus Torvalds  * Return:	0 if successful
23391da177e4SLinus Torvalds  *		-EFAULT if data unavailable
23401da177e4SLinus Torvalds  *		-EBUSY  if previous command timout and IOC reset is not complete.
23411da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
23421da177e4SLinus Torvalds  *		-ETIME	if timer expires
23431da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
23441da177e4SLinus Torvalds  */
23451da177e4SLinus Torvalds static int
23461da177e4SLinus Torvalds mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
23471da177e4SLinus Torvalds {
23481da177e4SLinus Torvalds 	hp_host_info_t	__user *uarg = (void __user *) arg;
23491da177e4SLinus Torvalds 	MPT_ADAPTER		*ioc;
23501da177e4SLinus Torvalds 	struct pci_dev		*pdev;
2351592f9c2fSMoore, Eric 	char                    *pbuf=NULL;
23521da177e4SLinus Torvalds 	dma_addr_t		buf_dma;
23531da177e4SLinus Torvalds 	hp_host_info_t		karg;
23541da177e4SLinus Torvalds 	CONFIGPARMS		cfg;
23551da177e4SLinus Torvalds 	ConfigPageHeader_t	hdr;
23561da177e4SLinus Torvalds 	int			iocnum;
23571da177e4SLinus Torvalds 	int			rc, cim_rev;
2358592f9c2fSMoore, Eric 	ToolboxIstwiReadWriteRequest_t	*IstwiRWRequest;
2359592f9c2fSMoore, Eric 	MPT_FRAME_HDR		*mf = NULL;
2360592f9c2fSMoore, Eric 	MPIHeader_t		*mpi_hdr;
23611da177e4SLinus Torvalds 
23621da177e4SLinus Torvalds 	dctlprintk((": mptctl_hp_hostinfo called.\n"));
23631da177e4SLinus Torvalds 	/* Reset long to int. Should affect IA64 and SPARC only
23641da177e4SLinus Torvalds 	 */
23651da177e4SLinus Torvalds 	if (data_size == sizeof(hp_host_info_t))
23661da177e4SLinus Torvalds 		cim_rev = 1;
23671da177e4SLinus Torvalds 	else if (data_size == sizeof(hp_host_info_rev0_t))
23681da177e4SLinus Torvalds 		cim_rev = 0;	/* obsolete */
23691da177e4SLinus Torvalds 	else
23701da177e4SLinus Torvalds 		return -EFAULT;
23711da177e4SLinus Torvalds 
23721da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
23731da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_hp_host_info - "
23741da177e4SLinus Torvalds 			"Unable to read in hp_host_info struct @ %p\n",
23751da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
23761da177e4SLinus Torvalds 		return -EFAULT;
23771da177e4SLinus Torvalds 	}
23781da177e4SLinus Torvalds 
23791da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
23801da177e4SLinus Torvalds 	    (ioc == NULL)) {
23811da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
23821da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
23831da177e4SLinus Torvalds 		return -ENODEV;
23841da177e4SLinus Torvalds 	}
23851da177e4SLinus Torvalds 
23861da177e4SLinus Torvalds 	/* Fill in the data and return the structure to the calling
23871da177e4SLinus Torvalds 	 * program
23881da177e4SLinus Torvalds 	 */
23891da177e4SLinus Torvalds 	pdev = (struct pci_dev *) ioc->pcidev;
23901da177e4SLinus Torvalds 
23911da177e4SLinus Torvalds 	karg.vendor = pdev->vendor;
23921da177e4SLinus Torvalds 	karg.device = pdev->device;
23931da177e4SLinus Torvalds 	karg.subsystem_id = pdev->subsystem_device;
23941da177e4SLinus Torvalds 	karg.subsystem_vendor = pdev->subsystem_vendor;
23951da177e4SLinus Torvalds 	karg.devfn = pdev->devfn;
23961da177e4SLinus Torvalds 	karg.bus = pdev->bus->number;
23971da177e4SLinus Torvalds 
23981da177e4SLinus Torvalds 	/* Save the SCSI host no. if
23991da177e4SLinus Torvalds 	 * SCSI driver loaded
24001da177e4SLinus Torvalds 	 */
24011da177e4SLinus Torvalds 	if (ioc->sh != NULL)
24021da177e4SLinus Torvalds 		karg.host_no = ioc->sh->host_no;
24031da177e4SLinus Torvalds 	else
24041da177e4SLinus Torvalds 		karg.host_no =  -1;
24051da177e4SLinus Torvalds 
24061da177e4SLinus Torvalds 	/* Reformat the fw_version into a string
24071da177e4SLinus Torvalds 	 */
24081da177e4SLinus Torvalds 	karg.fw_version[0] = ioc->facts.FWVersion.Struct.Major >= 10 ?
24091da177e4SLinus Torvalds 		((ioc->facts.FWVersion.Struct.Major / 10) + '0') : '0';
24101da177e4SLinus Torvalds 	karg.fw_version[1] = (ioc->facts.FWVersion.Struct.Major % 10 ) + '0';
24111da177e4SLinus Torvalds 	karg.fw_version[2] = '.';
24121da177e4SLinus Torvalds 	karg.fw_version[3] = ioc->facts.FWVersion.Struct.Minor >= 10 ?
24131da177e4SLinus Torvalds 		((ioc->facts.FWVersion.Struct.Minor / 10) + '0') : '0';
24141da177e4SLinus Torvalds 	karg.fw_version[4] = (ioc->facts.FWVersion.Struct.Minor % 10 ) + '0';
24151da177e4SLinus Torvalds 	karg.fw_version[5] = '.';
24161da177e4SLinus Torvalds 	karg.fw_version[6] = ioc->facts.FWVersion.Struct.Unit >= 10 ?
24171da177e4SLinus Torvalds 		((ioc->facts.FWVersion.Struct.Unit / 10) + '0') : '0';
24181da177e4SLinus Torvalds 	karg.fw_version[7] = (ioc->facts.FWVersion.Struct.Unit % 10 ) + '0';
24191da177e4SLinus Torvalds 	karg.fw_version[8] = '.';
24201da177e4SLinus Torvalds 	karg.fw_version[9] = ioc->facts.FWVersion.Struct.Dev >= 10 ?
24211da177e4SLinus Torvalds 		((ioc->facts.FWVersion.Struct.Dev / 10) + '0') : '0';
24221da177e4SLinus Torvalds 	karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0';
24231da177e4SLinus Torvalds 	karg.fw_version[11] = '\0';
24241da177e4SLinus Torvalds 
24251da177e4SLinus Torvalds 	/* Issue a config request to get the device serial number
24261da177e4SLinus Torvalds 	 */
24271da177e4SLinus Torvalds 	hdr.PageVersion = 0;
24281da177e4SLinus Torvalds 	hdr.PageLength = 0;
24291da177e4SLinus Torvalds 	hdr.PageNumber = 0;
24301da177e4SLinus Torvalds 	hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
243169218ee5SChristoph Hellwig 	cfg.cfghdr.hdr = &hdr;
24321da177e4SLinus Torvalds 	cfg.physAddr = -1;
24331da177e4SLinus Torvalds 	cfg.pageAddr = 0;
24341da177e4SLinus Torvalds 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
24351da177e4SLinus Torvalds 	cfg.dir = 0;	/* read */
24361da177e4SLinus Torvalds 	cfg.timeout = 10;
24371da177e4SLinus Torvalds 
24381da177e4SLinus Torvalds 	strncpy(karg.serial_number, " ", 24);
24391da177e4SLinus Torvalds 	if (mpt_config(ioc, &cfg) == 0) {
244069218ee5SChristoph Hellwig 		if (cfg.cfghdr.hdr->PageLength > 0) {
24411da177e4SLinus Torvalds 			/* Issue the second config page request */
24421da177e4SLinus Torvalds 			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
24431da177e4SLinus Torvalds 
24441da177e4SLinus Torvalds 			pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
24451da177e4SLinus Torvalds 			if (pbuf) {
24461da177e4SLinus Torvalds 				cfg.physAddr = buf_dma;
24471da177e4SLinus Torvalds 				if (mpt_config(ioc, &cfg) == 0) {
24481da177e4SLinus Torvalds 					ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
24491da177e4SLinus Torvalds 					if (strlen(pdata->BoardTracerNumber) > 1) {
24501da177e4SLinus Torvalds 						strncpy(karg.serial_number, 									    pdata->BoardTracerNumber, 24);
24511da177e4SLinus Torvalds 						karg.serial_number[24-1]='\0';
24521da177e4SLinus Torvalds 					}
24531da177e4SLinus Torvalds 				}
24541da177e4SLinus Torvalds 				pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
24551da177e4SLinus Torvalds 				pbuf = NULL;
24561da177e4SLinus Torvalds 			}
24571da177e4SLinus Torvalds 		}
24581da177e4SLinus Torvalds 	}
24591da177e4SLinus Torvalds 	rc = mpt_GetIocState(ioc, 1);
24601da177e4SLinus Torvalds 	switch (rc) {
24611da177e4SLinus Torvalds 	case MPI_IOC_STATE_OPERATIONAL:
24621da177e4SLinus Torvalds 		karg.ioc_status =  HP_STATUS_OK;
24631da177e4SLinus Torvalds 		break;
24641da177e4SLinus Torvalds 
24651da177e4SLinus Torvalds 	case MPI_IOC_STATE_FAULT:
24661da177e4SLinus Torvalds 		karg.ioc_status =  HP_STATUS_FAILED;
24671da177e4SLinus Torvalds 		break;
24681da177e4SLinus Torvalds 
24691da177e4SLinus Torvalds 	case MPI_IOC_STATE_RESET:
24701da177e4SLinus Torvalds 	case MPI_IOC_STATE_READY:
24711da177e4SLinus Torvalds 	default:
24721da177e4SLinus Torvalds 		karg.ioc_status =  HP_STATUS_OTHER;
24731da177e4SLinus Torvalds 		break;
24741da177e4SLinus Torvalds 	}
24751da177e4SLinus Torvalds 
24761da177e4SLinus Torvalds 	karg.base_io_addr = pci_resource_start(pdev, 0);
24771da177e4SLinus Torvalds 
24789cc1cfbcSMoore, Eric 	if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
24791da177e4SLinus Torvalds 		karg.bus_phys_width = HP_BUS_WIDTH_UNK;
24801da177e4SLinus Torvalds 	else
24811da177e4SLinus Torvalds 		karg.bus_phys_width = HP_BUS_WIDTH_16;
24821da177e4SLinus Torvalds 
24831da177e4SLinus Torvalds 	karg.hard_resets = 0;
24841da177e4SLinus Torvalds 	karg.soft_resets = 0;
24851da177e4SLinus Torvalds 	karg.timeouts = 0;
24861da177e4SLinus Torvalds 	if (ioc->sh != NULL) {
24871da177e4SLinus Torvalds 		MPT_SCSI_HOST *hd =  (MPT_SCSI_HOST *)ioc->sh->hostdata;
24881da177e4SLinus Torvalds 
24891da177e4SLinus Torvalds 		if (hd && (cim_rev == 1)) {
24901da177e4SLinus Torvalds 			karg.hard_resets = hd->hard_resets;
24911da177e4SLinus Torvalds 			karg.soft_resets = hd->soft_resets;
24921da177e4SLinus Torvalds 			karg.timeouts = hd->timeouts;
24931da177e4SLinus Torvalds 		}
24941da177e4SLinus Torvalds 	}
24951da177e4SLinus Torvalds 
2496592f9c2fSMoore, Eric 	/*
2497592f9c2fSMoore, Eric 	 * Gather ISTWI(Industry Standard Two Wire Interface) Data
2498592f9c2fSMoore, Eric 	 */
2499592f9c2fSMoore, Eric 	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
2500592f9c2fSMoore, Eric 		dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
2501592f9c2fSMoore, Eric 		    ioc->name,__FUNCTION__));
2502592f9c2fSMoore, Eric 		goto out;
2503592f9c2fSMoore, Eric 	}
2504592f9c2fSMoore, Eric 
2505592f9c2fSMoore, Eric 	IstwiRWRequest = (ToolboxIstwiReadWriteRequest_t *)mf;
2506592f9c2fSMoore, Eric 	mpi_hdr = (MPIHeader_t *) mf;
2507592f9c2fSMoore, Eric 	memset(IstwiRWRequest,0,sizeof(ToolboxIstwiReadWriteRequest_t));
2508592f9c2fSMoore, Eric 	IstwiRWRequest->Function = MPI_FUNCTION_TOOLBOX;
2509592f9c2fSMoore, Eric 	IstwiRWRequest->Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL;
2510592f9c2fSMoore, Eric 	IstwiRWRequest->MsgContext = mpi_hdr->MsgContext;
2511592f9c2fSMoore, Eric 	IstwiRWRequest->Flags = MPI_TB_ISTWI_FLAGS_READ;
2512592f9c2fSMoore, Eric 	IstwiRWRequest->NumAddressBytes = 0x01;
2513592f9c2fSMoore, Eric 	IstwiRWRequest->DataLength = cpu_to_le16(0x04);
2514592f9c2fSMoore, Eric 	if (pdev->devfn & 1)
2515592f9c2fSMoore, Eric 		IstwiRWRequest->DeviceAddr = 0xB2;
2516592f9c2fSMoore, Eric 	else
2517592f9c2fSMoore, Eric 		IstwiRWRequest->DeviceAddr = 0xB0;
2518592f9c2fSMoore, Eric 
25191da177e4SLinus Torvalds 	pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
2520592f9c2fSMoore, Eric 	if (!pbuf)
2521592f9c2fSMoore, Eric 		goto out;
2522592f9c2fSMoore, Eric 	mpt_add_sge((char *)&IstwiRWRequest->SGL,
2523592f9c2fSMoore, Eric 	    (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
2524592f9c2fSMoore, Eric 
2525592f9c2fSMoore, Eric 	ioc->ioctl->wait_done = 0;
2526592f9c2fSMoore, Eric 	mpt_put_msg_frame(mptctl_id, ioc, mf);
2527592f9c2fSMoore, Eric 
2528592f9c2fSMoore, Eric 	rc = wait_event_timeout(mptctl_wait,
2529592f9c2fSMoore, Eric 	     ioc->ioctl->wait_done == 1,
2530592f9c2fSMoore, Eric 	     HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */);
2531592f9c2fSMoore, Eric 
2532592f9c2fSMoore, Eric 	if(rc <=0 && (ioc->ioctl->wait_done != 1 )) {
2533592f9c2fSMoore, Eric 		/*
2534592f9c2fSMoore, Eric 		 * Now we need to reset the board
2535592f9c2fSMoore, Eric 		 */
2536592f9c2fSMoore, Eric 		mpt_free_msg_frame(ioc, mf);
2537592f9c2fSMoore, Eric 		mptctl_timeout_expired(ioc->ioctl);
2538592f9c2fSMoore, Eric 		goto out;
2539592f9c2fSMoore, Eric 	}
2540592f9c2fSMoore, Eric 
2541592f9c2fSMoore, Eric 	/*
2542592f9c2fSMoore, Eric 	 *ISTWI Data Definition
2543592f9c2fSMoore, Eric 	 * pbuf[0] = FW_VERSION = 0x4
2544592f9c2fSMoore, Eric 	 * pbuf[1] = Bay Count = 6 or 4 or 2, depending on
2545592f9c2fSMoore, Eric 	 *  the config, you should be seeing one out of these three values
2546592f9c2fSMoore, Eric 	 * pbuf[2] = Drive Installed Map = bit pattern depend on which
2547592f9c2fSMoore, Eric 	 *   bays have drives in them
2548592f9c2fSMoore, Eric 	 * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3)
2549592f9c2fSMoore, Eric 	 */
2550592f9c2fSMoore, Eric 	if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID)
25511da177e4SLinus Torvalds 		karg.rsvd = *(u32 *)pbuf;
2552592f9c2fSMoore, Eric 
2553592f9c2fSMoore, Eric  out:
2554592f9c2fSMoore, Eric 	if (pbuf)
25551da177e4SLinus Torvalds 		pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma);
25561da177e4SLinus Torvalds 
25571da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
25581da177e4SLinus Torvalds 	 */
25591da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) {
25601da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_hpgethostinfo - "
25611da177e4SLinus Torvalds 			"Unable to write out hp_host_info @ %p\n",
25621da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
25631da177e4SLinus Torvalds 		return -EFAULT;
25641da177e4SLinus Torvalds 	}
25651da177e4SLinus Torvalds 
25661da177e4SLinus Torvalds 	return 0;
25671da177e4SLinus Torvalds 
25681da177e4SLinus Torvalds }
25691da177e4SLinus Torvalds 
25701da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2571*ba856d32SEric Moore /* Prototype Routine for the TARGET INFO command.
25721da177e4SLinus Torvalds  *
25731da177e4SLinus Torvalds  * Outputs:	None.
25741da177e4SLinus Torvalds  * Return:	0 if successful
25751da177e4SLinus Torvalds  *		-EFAULT if data unavailable
25761da177e4SLinus Torvalds  *		-EBUSY  if previous command timout and IOC reset is not complete.
25771da177e4SLinus Torvalds  *		-ENODEV if no such device/adapter
25781da177e4SLinus Torvalds  *		-ETIME	if timer expires
25791da177e4SLinus Torvalds  *		-ENOMEM if memory allocation error
25801da177e4SLinus Torvalds  */
25811da177e4SLinus Torvalds static int
25821da177e4SLinus Torvalds mptctl_hp_targetinfo(unsigned long arg)
25831da177e4SLinus Torvalds {
25841da177e4SLinus Torvalds 	hp_target_info_t __user *uarg = (void __user *) arg;
25851da177e4SLinus Torvalds 	SCSIDevicePage0_t	*pg0_alloc;
25861da177e4SLinus Torvalds 	SCSIDevicePage3_t	*pg3_alloc;
25871da177e4SLinus Torvalds 	MPT_ADAPTER		*ioc;
25881da177e4SLinus Torvalds 	MPT_SCSI_HOST 		*hd = NULL;
25891da177e4SLinus Torvalds 	hp_target_info_t	karg;
25901da177e4SLinus Torvalds 	int			iocnum;
25911da177e4SLinus Torvalds 	int			data_sz;
25921da177e4SLinus Torvalds 	dma_addr_t		page_dma;
25931da177e4SLinus Torvalds 	CONFIGPARMS	 	cfg;
25941da177e4SLinus Torvalds 	ConfigPageHeader_t	hdr;
25951da177e4SLinus Torvalds 	int			tmp, np, rc = 0;
25961da177e4SLinus Torvalds 
25971da177e4SLinus Torvalds 	dctlprintk((": mptctl_hp_targetinfo called.\n"));
25981da177e4SLinus Torvalds 	if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
25991da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - "
26001da177e4SLinus Torvalds 			"Unable to read in hp_host_targetinfo struct @ %p\n",
26011da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
26021da177e4SLinus Torvalds 		return -EFAULT;
26031da177e4SLinus Torvalds 	}
26041da177e4SLinus Torvalds 
26051da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
26061da177e4SLinus Torvalds 		(ioc == NULL)) {
26071da177e4SLinus Torvalds 		dctlprintk((KERN_ERR "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
26081da177e4SLinus Torvalds 				__FILE__, __LINE__, iocnum));
26091da177e4SLinus Torvalds 		return -ENODEV;
26101da177e4SLinus Torvalds 	}
26111da177e4SLinus Torvalds 
26121da177e4SLinus Torvalds 	/*  There is nothing to do for FCP parts.
26131da177e4SLinus Torvalds 	 */
26149cc1cfbcSMoore, Eric 	if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
26151da177e4SLinus Torvalds 		return 0;
26161da177e4SLinus Torvalds 
26171da177e4SLinus Torvalds 	if ((ioc->spi_data.sdp0length == 0) || (ioc->sh == NULL))
26181da177e4SLinus Torvalds 		return 0;
26191da177e4SLinus Torvalds 
26201da177e4SLinus Torvalds 	if (ioc->sh->host_no != karg.hdr.host)
26211da177e4SLinus Torvalds 		return -ENODEV;
26221da177e4SLinus Torvalds 
26231da177e4SLinus Torvalds        /* Get the data transfer speeds
26241da177e4SLinus Torvalds         */
26251da177e4SLinus Torvalds 	data_sz = ioc->spi_data.sdp0length * 4;
26261da177e4SLinus Torvalds 	pg0_alloc = (SCSIDevicePage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
26271da177e4SLinus Torvalds 	if (pg0_alloc) {
26281da177e4SLinus Torvalds 		hdr.PageVersion = ioc->spi_data.sdp0version;
26291da177e4SLinus Torvalds 		hdr.PageLength = data_sz;
26301da177e4SLinus Torvalds 		hdr.PageNumber = 0;
26311da177e4SLinus Torvalds 		hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
26321da177e4SLinus Torvalds 
263369218ee5SChristoph Hellwig 		cfg.cfghdr.hdr = &hdr;
26341da177e4SLinus Torvalds 		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
26351da177e4SLinus Torvalds 		cfg.dir = 0;
26361da177e4SLinus Torvalds 		cfg.timeout = 0;
26371da177e4SLinus Torvalds 		cfg.physAddr = page_dma;
26381da177e4SLinus Torvalds 
26391da177e4SLinus Torvalds 		cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
26401da177e4SLinus Torvalds 
26411da177e4SLinus Torvalds 		if ((rc = mpt_config(ioc, &cfg)) == 0) {
26421da177e4SLinus Torvalds 			np = le32_to_cpu(pg0_alloc->NegotiatedParameters);
26431da177e4SLinus Torvalds 			karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ?
26441da177e4SLinus Torvalds 					HP_BUS_WIDTH_16 : HP_BUS_WIDTH_8;
26451da177e4SLinus Torvalds 
26461da177e4SLinus Torvalds 			if (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) {
26471da177e4SLinus Torvalds 				tmp = (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
26481da177e4SLinus Torvalds 				if (tmp < 0x09)
26491da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA320;
26501da177e4SLinus Torvalds 				else if (tmp <= 0x09)
26511da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA160;
26521da177e4SLinus Torvalds 				else if (tmp <= 0x0A)
26531da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA2;
26541da177e4SLinus Torvalds 				else if (tmp <= 0x0C)
26551da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ULTRA;
26561da177e4SLinus Torvalds 				else if (tmp <= 0x25)
26571da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_FAST;
26581da177e4SLinus Torvalds 				else
26591da177e4SLinus Torvalds 					karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
26601da177e4SLinus Torvalds 			} else
26611da177e4SLinus Torvalds 				karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
26621da177e4SLinus Torvalds 		}
26631da177e4SLinus Torvalds 
26641da177e4SLinus Torvalds 		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg0_alloc, page_dma);
26651da177e4SLinus Torvalds 	}
26661da177e4SLinus Torvalds 
26671da177e4SLinus Torvalds 	/* Set defaults
26681da177e4SLinus Torvalds 	 */
26691da177e4SLinus Torvalds 	karg.message_rejects = -1;
26701da177e4SLinus Torvalds 	karg.phase_errors = -1;
26711da177e4SLinus Torvalds 	karg.parity_errors = -1;
26721da177e4SLinus Torvalds 	karg.select_timeouts = -1;
26731da177e4SLinus Torvalds 
26741da177e4SLinus Torvalds 	/* Get the target error parameters
26751da177e4SLinus Torvalds 	 */
26761da177e4SLinus Torvalds 	hdr.PageVersion = 0;
26771da177e4SLinus Torvalds 	hdr.PageLength = 0;
26781da177e4SLinus Torvalds 	hdr.PageNumber = 3;
26791da177e4SLinus Torvalds 	hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
26801da177e4SLinus Torvalds 
268169218ee5SChristoph Hellwig 	cfg.cfghdr.hdr = &hdr;
26821da177e4SLinus Torvalds 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
26831da177e4SLinus Torvalds 	cfg.dir = 0;
26841da177e4SLinus Torvalds 	cfg.timeout = 0;
26851da177e4SLinus Torvalds 	cfg.physAddr = -1;
268669218ee5SChristoph Hellwig 	if ((mpt_config(ioc, &cfg) == 0) && (cfg.cfghdr.hdr->PageLength > 0)) {
26871da177e4SLinus Torvalds 		/* Issue the second config page request */
26881da177e4SLinus Torvalds 		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
268969218ee5SChristoph Hellwig 		data_sz = (int) cfg.cfghdr.hdr->PageLength * 4;
26901da177e4SLinus Torvalds 		pg3_alloc = (SCSIDevicePage3_t *) pci_alloc_consistent(
26911da177e4SLinus Torvalds 							ioc->pcidev, data_sz, &page_dma);
26921da177e4SLinus Torvalds 		if (pg3_alloc) {
26931da177e4SLinus Torvalds 			cfg.physAddr = page_dma;
26941da177e4SLinus Torvalds 			cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
26951da177e4SLinus Torvalds 			if ((rc = mpt_config(ioc, &cfg)) == 0) {
26961da177e4SLinus Torvalds 				karg.message_rejects = (u32) le16_to_cpu(pg3_alloc->MsgRejectCount);
26971da177e4SLinus Torvalds 				karg.phase_errors = (u32) le16_to_cpu(pg3_alloc->PhaseErrorCount);
26981da177e4SLinus Torvalds 				karg.parity_errors = (u32) le16_to_cpu(pg3_alloc->ParityErrorCount);
26991da177e4SLinus Torvalds 			}
27001da177e4SLinus Torvalds 			pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
27011da177e4SLinus Torvalds 		}
27021da177e4SLinus Torvalds 	}
27031da177e4SLinus Torvalds 	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
27041da177e4SLinus Torvalds 	if (hd != NULL)
27051da177e4SLinus Torvalds 		karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
27061da177e4SLinus Torvalds 
27071da177e4SLinus Torvalds 	/* Copy the data from kernel memory to user memory
27081da177e4SLinus Torvalds 	 */
27091da177e4SLinus Torvalds 	if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) {
27101da177e4SLinus Torvalds 		printk(KERN_ERR "%s@%d::mptctl_hp_target_info - "
27111da177e4SLinus Torvalds 			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
27121da177e4SLinus Torvalds 				__FILE__, __LINE__, uarg);
27131da177e4SLinus Torvalds 		return -EFAULT;
27141da177e4SLinus Torvalds 	}
27151da177e4SLinus Torvalds 
27161da177e4SLinus Torvalds 	return 0;
27171da177e4SLinus Torvalds }
27181da177e4SLinus Torvalds 
27191da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
27201da177e4SLinus Torvalds 
27211da177e4SLinus Torvalds static struct file_operations mptctl_fops = {
27221da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
27231da177e4SLinus Torvalds 	.llseek =	no_llseek,
2724ea5a7a82SMoore, Eric 	.release =	mptctl_release,
2725ea5a7a82SMoore, Eric 	.fasync = 	mptctl_fasync,
27261da177e4SLinus Torvalds 	.unlocked_ioctl = mptctl_ioctl,
27271da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
27281da177e4SLinus Torvalds 	.compat_ioctl = compat_mpctl_ioctl,
27291da177e4SLinus Torvalds #endif
27301da177e4SLinus Torvalds };
27311da177e4SLinus Torvalds 
27321da177e4SLinus Torvalds static struct miscdevice mptctl_miscdev = {
27331da177e4SLinus Torvalds 	MPT_MINOR,
27341da177e4SLinus Torvalds 	MYNAM,
27351da177e4SLinus Torvalds 	&mptctl_fops
27361da177e4SLinus Torvalds };
27371da177e4SLinus Torvalds 
27381da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
27391da177e4SLinus Torvalds 
27401da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
27411da177e4SLinus Torvalds 
27421da177e4SLinus Torvalds static int
27431da177e4SLinus Torvalds compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
27441da177e4SLinus Torvalds 			unsigned long arg)
27451da177e4SLinus Torvalds {
27461da177e4SLinus Torvalds 	struct mpt_fw_xfer32 kfw32;
27471da177e4SLinus Torvalds 	struct mpt_fw_xfer kfw;
27481da177e4SLinus Torvalds 	MPT_ADAPTER *iocp = NULL;
27491da177e4SLinus Torvalds 	int iocnum, iocnumX;
27501da177e4SLinus Torvalds 	int nonblock = (filp->f_flags & O_NONBLOCK);
27511da177e4SLinus Torvalds 	int ret;
27521da177e4SLinus Torvalds 
27531da177e4SLinus Torvalds 	dctlprintk((KERN_INFO MYNAM "::compat_mptfwxfer_ioctl() called\n"));
27541da177e4SLinus Torvalds 
27551da177e4SLinus Torvalds 	if (copy_from_user(&kfw32, (char __user *)arg, sizeof(kfw32)))
27561da177e4SLinus Torvalds 		return -EFAULT;
27571da177e4SLinus Torvalds 
27581da177e4SLinus Torvalds 	/* Verify intended MPT adapter */
27591da177e4SLinus Torvalds 	iocnumX = kfw32.iocnum & 0xFF;
27601da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
27611da177e4SLinus Torvalds 	    (iocp == NULL)) {
27621da177e4SLinus Torvalds 		dctlprintk((KERN_ERR MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
27631da177e4SLinus Torvalds 				__LINE__, iocnumX));
27641da177e4SLinus Torvalds 		return -ENODEV;
27651da177e4SLinus Torvalds 	}
27661da177e4SLinus Torvalds 
27671da177e4SLinus Torvalds 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
27681da177e4SLinus Torvalds 		return ret;
27691da177e4SLinus Torvalds 
27701da177e4SLinus Torvalds 	kfw.iocnum = iocnum;
27711da177e4SLinus Torvalds 	kfw.fwlen = kfw32.fwlen;
27721da177e4SLinus Torvalds 	kfw.bufp = compat_ptr(kfw32.bufp);
27731da177e4SLinus Torvalds 
27741da177e4SLinus Torvalds 	ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
27751da177e4SLinus Torvalds 
2776eeb846ceSChristoph Hellwig 	mutex_unlock(&iocp->ioctl->ioctl_mutex);
27771da177e4SLinus Torvalds 
27781da177e4SLinus Torvalds 	return ret;
27791da177e4SLinus Torvalds }
27801da177e4SLinus Torvalds 
27811da177e4SLinus Torvalds static int
27821da177e4SLinus Torvalds compat_mpt_command(struct file *filp, unsigned int cmd,
27831da177e4SLinus Torvalds 			unsigned long arg)
27841da177e4SLinus Torvalds {
27851da177e4SLinus Torvalds 	struct mpt_ioctl_command32 karg32;
27861da177e4SLinus Torvalds 	struct mpt_ioctl_command32 __user *uarg = (struct mpt_ioctl_command32 __user *) arg;
27871da177e4SLinus Torvalds 	struct mpt_ioctl_command karg;
27881da177e4SLinus Torvalds 	MPT_ADAPTER *iocp = NULL;
27891da177e4SLinus Torvalds 	int iocnum, iocnumX;
27901da177e4SLinus Torvalds 	int nonblock = (filp->f_flags & O_NONBLOCK);
27911da177e4SLinus Torvalds 	int ret;
27921da177e4SLinus Torvalds 
27931da177e4SLinus Torvalds 	dctlprintk((KERN_INFO MYNAM "::compat_mpt_command() called\n"));
27941da177e4SLinus Torvalds 
27951da177e4SLinus Torvalds 	if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32)))
27961da177e4SLinus Torvalds 		return -EFAULT;
27971da177e4SLinus Torvalds 
27981da177e4SLinus Torvalds 	/* Verify intended MPT adapter */
27991da177e4SLinus Torvalds 	iocnumX = karg32.hdr.iocnum & 0xFF;
28001da177e4SLinus Torvalds 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
28011da177e4SLinus Torvalds 	    (iocp == NULL)) {
28021da177e4SLinus Torvalds 		dctlprintk((KERN_ERR MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
28031da177e4SLinus Torvalds 				__LINE__, iocnumX));
28041da177e4SLinus Torvalds 		return -ENODEV;
28051da177e4SLinus Torvalds 	}
28061da177e4SLinus Torvalds 
28071da177e4SLinus Torvalds 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
28081da177e4SLinus Torvalds 		return ret;
28091da177e4SLinus Torvalds 
28101da177e4SLinus Torvalds 	/* Copy data to karg */
28111da177e4SLinus Torvalds 	karg.hdr.iocnum = karg32.hdr.iocnum;
28121da177e4SLinus Torvalds 	karg.hdr.port = karg32.hdr.port;
28131da177e4SLinus Torvalds 	karg.timeout = karg32.timeout;
28141da177e4SLinus Torvalds 	karg.maxReplyBytes = karg32.maxReplyBytes;
28151da177e4SLinus Torvalds 
28161da177e4SLinus Torvalds 	karg.dataInSize = karg32.dataInSize;
28171da177e4SLinus Torvalds 	karg.dataOutSize = karg32.dataOutSize;
28181da177e4SLinus Torvalds 	karg.maxSenseBytes = karg32.maxSenseBytes;
28191da177e4SLinus Torvalds 	karg.dataSgeOffset = karg32.dataSgeOffset;
28201da177e4SLinus Torvalds 
28211da177e4SLinus Torvalds 	karg.replyFrameBufPtr = (char __user *)(unsigned long)karg32.replyFrameBufPtr;
28221da177e4SLinus Torvalds 	karg.dataInBufPtr = (char __user *)(unsigned long)karg32.dataInBufPtr;
28231da177e4SLinus Torvalds 	karg.dataOutBufPtr = (char __user *)(unsigned long)karg32.dataOutBufPtr;
28241da177e4SLinus Torvalds 	karg.senseDataPtr = (char __user *)(unsigned long)karg32.senseDataPtr;
28251da177e4SLinus Torvalds 
28261da177e4SLinus Torvalds 	/* Pass new structure to do_mpt_command
28271da177e4SLinus Torvalds 	 */
28281da177e4SLinus Torvalds 	ret = mptctl_do_mpt_command (karg, &uarg->MF);
28291da177e4SLinus Torvalds 
2830eeb846ceSChristoph Hellwig 	mutex_unlock(&iocp->ioctl->ioctl_mutex);
28311da177e4SLinus Torvalds 
28321da177e4SLinus Torvalds 	return ret;
28331da177e4SLinus Torvalds }
28341da177e4SLinus Torvalds 
28351da177e4SLinus Torvalds static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
28361da177e4SLinus Torvalds {
28371da177e4SLinus Torvalds 	long ret;
28381da177e4SLinus Torvalds 	lock_kernel();
28391da177e4SLinus Torvalds 	switch (cmd) {
28401da177e4SLinus Torvalds 	case MPTIOCINFO:
28411da177e4SLinus Torvalds 	case MPTIOCINFO1:
28421da177e4SLinus Torvalds 	case MPTIOCINFO2:
28431da177e4SLinus Torvalds 	case MPTTARGETINFO:
28441da177e4SLinus Torvalds 	case MPTEVENTQUERY:
28451da177e4SLinus Torvalds 	case MPTEVENTENABLE:
28461da177e4SLinus Torvalds 	case MPTEVENTREPORT:
28471da177e4SLinus Torvalds 	case MPTHARDRESET:
28481da177e4SLinus Torvalds 	case HP_GETHOSTINFO:
28491da177e4SLinus Torvalds 	case HP_GETTARGETINFO:
28501da177e4SLinus Torvalds 	case MPTTEST:
28511da177e4SLinus Torvalds 		ret = __mptctl_ioctl(f, cmd, arg);
28521da177e4SLinus Torvalds 		break;
28531da177e4SLinus Torvalds 	case MPTCOMMAND32:
28541da177e4SLinus Torvalds 		ret = compat_mpt_command(f, cmd, arg);
28551da177e4SLinus Torvalds 		break;
28561da177e4SLinus Torvalds 	case MPTFWDOWNLOAD32:
28571da177e4SLinus Torvalds 		ret = compat_mptfwxfer_ioctl(f, cmd, arg);
28581da177e4SLinus Torvalds 		break;
28591da177e4SLinus Torvalds 	default:
28601da177e4SLinus Torvalds 		ret = -ENOIOCTLCMD;
28611da177e4SLinus Torvalds 		break;
28621da177e4SLinus Torvalds 	}
28631da177e4SLinus Torvalds 	unlock_kernel();
28641da177e4SLinus Torvalds 	return ret;
28651da177e4SLinus Torvalds }
28661da177e4SLinus Torvalds 
28671da177e4SLinus Torvalds #endif
28681da177e4SLinus Torvalds 
28691da177e4SLinus Torvalds 
28701da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
28711da177e4SLinus Torvalds /*
28721da177e4SLinus Torvalds  *	mptctl_probe - Installs ioctl devices per bus.
28731da177e4SLinus Torvalds  *	@pdev: Pointer to pci_dev structure
28741da177e4SLinus Torvalds  *
28751da177e4SLinus Torvalds  *	Returns 0 for success, non-zero for failure.
28761da177e4SLinus Torvalds  *
28771da177e4SLinus Torvalds  */
28781da177e4SLinus Torvalds 
28791da177e4SLinus Torvalds static int
28801da177e4SLinus Torvalds mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
28811da177e4SLinus Torvalds {
28821da177e4SLinus Torvalds 	int err;
28831da177e4SLinus Torvalds 	int sz;
28841da177e4SLinus Torvalds 	u8 *mem;
28851da177e4SLinus Torvalds 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
28861da177e4SLinus Torvalds 
28871da177e4SLinus Torvalds 	/*
28881da177e4SLinus Torvalds 	 * Allocate and inite a MPT_IOCTL structure
28891da177e4SLinus Torvalds 	*/
28901da177e4SLinus Torvalds 	sz = sizeof (MPT_IOCTL);
28911da177e4SLinus Torvalds 	mem = kmalloc(sz, GFP_KERNEL);
28921da177e4SLinus Torvalds 	if (mem == NULL) {
28931da177e4SLinus Torvalds 		err = -ENOMEM;
28941da177e4SLinus Torvalds 		goto out_fail;
28951da177e4SLinus Torvalds 	}
28961da177e4SLinus Torvalds 
28971da177e4SLinus Torvalds 	memset(mem, 0, sz);
28981da177e4SLinus Torvalds 	ioc->ioctl = (MPT_IOCTL *) mem;
28991da177e4SLinus Torvalds 	ioc->ioctl->ioc = ioc;
2900eeb846ceSChristoph Hellwig 	mutex_init(&ioc->ioctl->ioctl_mutex);
29011da177e4SLinus Torvalds 	return 0;
29021da177e4SLinus Torvalds 
29031da177e4SLinus Torvalds out_fail:
29041da177e4SLinus Torvalds 
29051da177e4SLinus Torvalds 	mptctl_remove(pdev);
29061da177e4SLinus Torvalds 	return err;
29071da177e4SLinus Torvalds }
29081da177e4SLinus Torvalds 
29091da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
29101da177e4SLinus Torvalds /*
29111da177e4SLinus Torvalds  *	mptctl_remove - Removed ioctl devices
29121da177e4SLinus Torvalds  *	@pdev: Pointer to pci_dev structure
29131da177e4SLinus Torvalds  *
29141da177e4SLinus Torvalds  *
29151da177e4SLinus Torvalds  */
29161da177e4SLinus Torvalds static void
29171da177e4SLinus Torvalds mptctl_remove(struct pci_dev *pdev)
29181da177e4SLinus Torvalds {
29191da177e4SLinus Torvalds 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
29201da177e4SLinus Torvalds 
29211da177e4SLinus Torvalds 	kfree ( ioc->ioctl );
29221da177e4SLinus Torvalds }
29231da177e4SLinus Torvalds 
29241da177e4SLinus Torvalds static struct mpt_pci_driver mptctl_driver = {
29251da177e4SLinus Torvalds   .probe		= mptctl_probe,
29261da177e4SLinus Torvalds   .remove		= mptctl_remove,
29271da177e4SLinus Torvalds };
29281da177e4SLinus Torvalds 
29291da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
29301da177e4SLinus Torvalds static int __init mptctl_init(void)
29311da177e4SLinus Torvalds {
29321da177e4SLinus Torvalds 	int err;
29331da177e4SLinus Torvalds 	int where = 1;
29341da177e4SLinus Torvalds 
29351da177e4SLinus Torvalds 	show_mptmod_ver(my_NAME, my_VERSION);
29361da177e4SLinus Torvalds 
29371da177e4SLinus Torvalds 	if(mpt_device_driver_register(&mptctl_driver,
29381da177e4SLinus Torvalds 	  MPTCTL_DRIVER) != 0 ) {
29391da177e4SLinus Torvalds 		dprintk((KERN_INFO MYNAM
29401da177e4SLinus Torvalds 		": failed to register dd callbacks\n"));
29411da177e4SLinus Torvalds 	}
29421da177e4SLinus Torvalds 
29431da177e4SLinus Torvalds 	/* Register this device */
29441da177e4SLinus Torvalds 	err = misc_register(&mptctl_miscdev);
29451da177e4SLinus Torvalds 	if (err < 0) {
29461da177e4SLinus Torvalds 		printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
29471da177e4SLinus Torvalds 		goto out_fail;
29481da177e4SLinus Torvalds 	}
29491da177e4SLinus Torvalds 	printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
29501da177e4SLinus Torvalds 	printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
29511da177e4SLinus Torvalds 			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
29521da177e4SLinus Torvalds 
29531da177e4SLinus Torvalds 	/*
29541da177e4SLinus Torvalds 	 *  Install our handler
29551da177e4SLinus Torvalds 	 */
29561da177e4SLinus Torvalds 	++where;
29571da177e4SLinus Torvalds 	if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) {
29581da177e4SLinus Torvalds 		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
29591da177e4SLinus Torvalds 		misc_deregister(&mptctl_miscdev);
29601da177e4SLinus Torvalds 		err = -EBUSY;
29611da177e4SLinus Torvalds 		goto out_fail;
29621da177e4SLinus Torvalds 	}
29631da177e4SLinus Torvalds 
29641da177e4SLinus Torvalds 	if (mpt_reset_register(mptctl_id, mptctl_ioc_reset) == 0) {
29651da177e4SLinus Torvalds 		dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
29661da177e4SLinus Torvalds 	} else {
29671da177e4SLinus Torvalds 		/* FIXME! */
29681da177e4SLinus Torvalds 	}
29691da177e4SLinus Torvalds 
2970ea5a7a82SMoore, Eric 	if (mpt_event_register(mptctl_id, mptctl_event_process) == 0) {
29713a892befSMoore, Eric 		devtverboseprintk((KERN_INFO MYNAM
2972ea5a7a82SMoore, Eric 		  ": Registered for IOC event notifications\n"));
2973ea5a7a82SMoore, Eric 	}
2974ea5a7a82SMoore, Eric 
29751da177e4SLinus Torvalds 	return 0;
29761da177e4SLinus Torvalds 
29771da177e4SLinus Torvalds out_fail:
29781da177e4SLinus Torvalds 
29791da177e4SLinus Torvalds 	mpt_device_driver_deregister(MPTCTL_DRIVER);
29801da177e4SLinus Torvalds 
29811da177e4SLinus Torvalds 	return err;
29821da177e4SLinus Torvalds }
29831da177e4SLinus Torvalds 
29841da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
29851da177e4SLinus Torvalds static void mptctl_exit(void)
29861da177e4SLinus Torvalds {
29871da177e4SLinus Torvalds 	misc_deregister(&mptctl_miscdev);
29881da177e4SLinus Torvalds 	printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",
29891da177e4SLinus Torvalds 			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
29901da177e4SLinus Torvalds 
29911da177e4SLinus Torvalds 	/* De-register reset handler from base module */
29921da177e4SLinus Torvalds 	mpt_reset_deregister(mptctl_id);
29931da177e4SLinus Torvalds 	dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
29941da177e4SLinus Torvalds 
29951da177e4SLinus Torvalds 	/* De-register callback handler from base module */
29961da177e4SLinus Torvalds 	mpt_deregister(mptctl_id);
29971da177e4SLinus Torvalds 	printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
29981da177e4SLinus Torvalds 
29991da177e4SLinus Torvalds         mpt_device_driver_deregister(MPTCTL_DRIVER);
30001da177e4SLinus Torvalds 
30011da177e4SLinus Torvalds }
30021da177e4SLinus Torvalds 
30031da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
30041da177e4SLinus Torvalds 
30051da177e4SLinus Torvalds module_init(mptctl_init);
30061da177e4SLinus Torvalds module_exit(mptctl_exit);
3007