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