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