1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * 3*1da177e4SLinus Torvalds * Linux MegaRAID device driver 4*1da177e4SLinus Torvalds * 5*1da177e4SLinus Torvalds * Copyright (c) 2003-2004 LSI Logic Corporation. 6*1da177e4SLinus Torvalds * 7*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 8*1da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 9*1da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 10*1da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 11*1da177e4SLinus Torvalds * 12*1da177e4SLinus Torvalds * FILE : megaraid_mm.c 13*1da177e4SLinus Torvalds * Version : v2.20.2.5 (Jan 21 2005) 14*1da177e4SLinus Torvalds * 15*1da177e4SLinus Torvalds * Common management module 16*1da177e4SLinus Torvalds */ 17*1da177e4SLinus Torvalds 18*1da177e4SLinus Torvalds #include "megaraid_mm.h" 19*1da177e4SLinus Torvalds #include <linux/smp_lock.h> 20*1da177e4SLinus Torvalds 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds // Entry points for char node driver 23*1da177e4SLinus Torvalds static int mraid_mm_open(struct inode *, struct file *); 24*1da177e4SLinus Torvalds static int mraid_mm_ioctl(struct inode *, struct file *, uint, unsigned long); 25*1da177e4SLinus Torvalds 26*1da177e4SLinus Torvalds 27*1da177e4SLinus Torvalds // routines to convert to and from the old the format 28*1da177e4SLinus Torvalds static int mimd_to_kioc(mimd_t __user *, mraid_mmadp_t *, uioc_t *); 29*1da177e4SLinus Torvalds static int kioc_to_mimd(uioc_t *, mimd_t __user *); 30*1da177e4SLinus Torvalds 31*1da177e4SLinus Torvalds 32*1da177e4SLinus Torvalds // Helper functions 33*1da177e4SLinus Torvalds static int handle_drvrcmd(void __user *, uint8_t, int *); 34*1da177e4SLinus Torvalds static int lld_ioctl(mraid_mmadp_t *, uioc_t *); 35*1da177e4SLinus Torvalds static void ioctl_done(uioc_t *); 36*1da177e4SLinus Torvalds static void lld_timedout(unsigned long); 37*1da177e4SLinus Torvalds static void hinfo_to_cinfo(mraid_hba_info_t *, mcontroller_t *); 38*1da177e4SLinus Torvalds static mraid_mmadp_t *mraid_mm_get_adapter(mimd_t __user *, int *); 39*1da177e4SLinus Torvalds static uioc_t *mraid_mm_alloc_kioc(mraid_mmadp_t *); 40*1da177e4SLinus Torvalds static void mraid_mm_dealloc_kioc(mraid_mmadp_t *, uioc_t *); 41*1da177e4SLinus Torvalds static int mraid_mm_attach_buf(mraid_mmadp_t *, uioc_t *, int); 42*1da177e4SLinus Torvalds static int mraid_mm_setup_dma_pools(mraid_mmadp_t *); 43*1da177e4SLinus Torvalds static void mraid_mm_free_adp_resources(mraid_mmadp_t *); 44*1da177e4SLinus Torvalds static void mraid_mm_teardown_dma_pools(mraid_mmadp_t *); 45*1da177e4SLinus Torvalds 46*1da177e4SLinus Torvalds #ifdef CONFIG_COMPAT 47*1da177e4SLinus Torvalds static long mraid_mm_compat_ioctl(struct file *, unsigned int, unsigned long); 48*1da177e4SLinus Torvalds #endif 49*1da177e4SLinus Torvalds 50*1da177e4SLinus Torvalds MODULE_AUTHOR("LSI Logic Corporation"); 51*1da177e4SLinus Torvalds MODULE_DESCRIPTION("LSI Logic Management Module"); 52*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 53*1da177e4SLinus Torvalds MODULE_VERSION(LSI_COMMON_MOD_VERSION); 54*1da177e4SLinus Torvalds 55*1da177e4SLinus Torvalds static int dbglevel = CL_ANN; 56*1da177e4SLinus Torvalds module_param_named(dlevel, dbglevel, int, 0); 57*1da177e4SLinus Torvalds MODULE_PARM_DESC(dlevel, "Debug level (default=0)"); 58*1da177e4SLinus Torvalds 59*1da177e4SLinus Torvalds EXPORT_SYMBOL(mraid_mm_register_adp); 60*1da177e4SLinus Torvalds EXPORT_SYMBOL(mraid_mm_unregister_adp); 61*1da177e4SLinus Torvalds EXPORT_SYMBOL(mraid_mm_adapter_app_handle); 62*1da177e4SLinus Torvalds 63*1da177e4SLinus Torvalds static int majorno; 64*1da177e4SLinus Torvalds static uint32_t drvr_ver = 0x02200201; 65*1da177e4SLinus Torvalds 66*1da177e4SLinus Torvalds static int adapters_count_g; 67*1da177e4SLinus Torvalds static struct list_head adapters_list_g; 68*1da177e4SLinus Torvalds 69*1da177e4SLinus Torvalds static wait_queue_head_t wait_q; 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds static struct file_operations lsi_fops = { 72*1da177e4SLinus Torvalds .open = mraid_mm_open, 73*1da177e4SLinus Torvalds .ioctl = mraid_mm_ioctl, 74*1da177e4SLinus Torvalds #ifdef CONFIG_COMPAT 75*1da177e4SLinus Torvalds .compat_ioctl = mraid_mm_compat_ioctl, 76*1da177e4SLinus Torvalds #endif 77*1da177e4SLinus Torvalds .owner = THIS_MODULE, 78*1da177e4SLinus Torvalds }; 79*1da177e4SLinus Torvalds 80*1da177e4SLinus Torvalds /** 81*1da177e4SLinus Torvalds * mraid_mm_open - open routine for char node interface 82*1da177e4SLinus Torvalds * @inod : unused 83*1da177e4SLinus Torvalds * @filep : unused 84*1da177e4SLinus Torvalds * 85*1da177e4SLinus Torvalds * allow ioctl operations by apps only if they superuser privilege 86*1da177e4SLinus Torvalds */ 87*1da177e4SLinus Torvalds static int 88*1da177e4SLinus Torvalds mraid_mm_open(struct inode *inode, struct file *filep) 89*1da177e4SLinus Torvalds { 90*1da177e4SLinus Torvalds /* 91*1da177e4SLinus Torvalds * Only allow superuser to access private ioctl interface 92*1da177e4SLinus Torvalds */ 93*1da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) return (-EACCES); 94*1da177e4SLinus Torvalds 95*1da177e4SLinus Torvalds return 0; 96*1da177e4SLinus Torvalds } 97*1da177e4SLinus Torvalds 98*1da177e4SLinus Torvalds /** 99*1da177e4SLinus Torvalds * mraid_mm_ioctl - module entry-point for ioctls 100*1da177e4SLinus Torvalds * @inode : inode (ignored) 101*1da177e4SLinus Torvalds * @filep : file operations pointer (ignored) 102*1da177e4SLinus Torvalds * @cmd : ioctl command 103*1da177e4SLinus Torvalds * @arg : user ioctl packet 104*1da177e4SLinus Torvalds */ 105*1da177e4SLinus Torvalds static int 106*1da177e4SLinus Torvalds mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, 107*1da177e4SLinus Torvalds unsigned long arg) 108*1da177e4SLinus Torvalds { 109*1da177e4SLinus Torvalds uioc_t *kioc; 110*1da177e4SLinus Torvalds char signature[EXT_IOCTL_SIGN_SZ] = {0}; 111*1da177e4SLinus Torvalds int rval; 112*1da177e4SLinus Torvalds mraid_mmadp_t *adp; 113*1da177e4SLinus Torvalds uint8_t old_ioctl; 114*1da177e4SLinus Torvalds int drvrcmd_rval; 115*1da177e4SLinus Torvalds void __user *argp = (void __user *)arg; 116*1da177e4SLinus Torvalds 117*1da177e4SLinus Torvalds /* 118*1da177e4SLinus Torvalds * Make sure only USCSICMD are issued through this interface. 119*1da177e4SLinus Torvalds * MIMD application would still fire different command. 120*1da177e4SLinus Torvalds */ 121*1da177e4SLinus Torvalds 122*1da177e4SLinus Torvalds if ((_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD)) { 123*1da177e4SLinus Torvalds return (-EINVAL); 124*1da177e4SLinus Torvalds } 125*1da177e4SLinus Torvalds 126*1da177e4SLinus Torvalds /* 127*1da177e4SLinus Torvalds * Look for signature to see if this is the new or old ioctl format. 128*1da177e4SLinus Torvalds */ 129*1da177e4SLinus Torvalds if (copy_from_user(signature, argp, EXT_IOCTL_SIGN_SZ)) { 130*1da177e4SLinus Torvalds con_log(CL_ANN, (KERN_WARNING 131*1da177e4SLinus Torvalds "megaraid cmm: copy from usr addr failed\n")); 132*1da177e4SLinus Torvalds return (-EFAULT); 133*1da177e4SLinus Torvalds } 134*1da177e4SLinus Torvalds 135*1da177e4SLinus Torvalds if (memcmp(signature, EXT_IOCTL_SIGN, EXT_IOCTL_SIGN_SZ) == 0) 136*1da177e4SLinus Torvalds old_ioctl = 0; 137*1da177e4SLinus Torvalds else 138*1da177e4SLinus Torvalds old_ioctl = 1; 139*1da177e4SLinus Torvalds 140*1da177e4SLinus Torvalds /* 141*1da177e4SLinus Torvalds * At present, we don't support the new ioctl packet 142*1da177e4SLinus Torvalds */ 143*1da177e4SLinus Torvalds if (!old_ioctl ) 144*1da177e4SLinus Torvalds return (-EINVAL); 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds /* 147*1da177e4SLinus Torvalds * If it is a driver ioctl (as opposed to fw ioctls), then we can 148*1da177e4SLinus Torvalds * handle the command locally. rval > 0 means it is not a drvr cmd 149*1da177e4SLinus Torvalds */ 150*1da177e4SLinus Torvalds rval = handle_drvrcmd(argp, old_ioctl, &drvrcmd_rval); 151*1da177e4SLinus Torvalds 152*1da177e4SLinus Torvalds if (rval < 0) 153*1da177e4SLinus Torvalds return rval; 154*1da177e4SLinus Torvalds else if (rval == 0) 155*1da177e4SLinus Torvalds return drvrcmd_rval; 156*1da177e4SLinus Torvalds 157*1da177e4SLinus Torvalds rval = 0; 158*1da177e4SLinus Torvalds if ((adp = mraid_mm_get_adapter(argp, &rval)) == NULL) { 159*1da177e4SLinus Torvalds return rval; 160*1da177e4SLinus Torvalds } 161*1da177e4SLinus Torvalds 162*1da177e4SLinus Torvalds /* 163*1da177e4SLinus Torvalds * Check if adapter can accept ioctl. We may have marked it offline 164*1da177e4SLinus Torvalds * if any previous kioc had timedout on this controller. 165*1da177e4SLinus Torvalds */ 166*1da177e4SLinus Torvalds if (!adp->quiescent) { 167*1da177e4SLinus Torvalds con_log(CL_ANN, (KERN_WARNING 168*1da177e4SLinus Torvalds "megaraid cmm: controller cannot accept cmds due to " 169*1da177e4SLinus Torvalds "earlier errors\n" )); 170*1da177e4SLinus Torvalds return -EFAULT; 171*1da177e4SLinus Torvalds } 172*1da177e4SLinus Torvalds 173*1da177e4SLinus Torvalds /* 174*1da177e4SLinus Torvalds * The following call will block till a kioc is available 175*1da177e4SLinus Torvalds */ 176*1da177e4SLinus Torvalds kioc = mraid_mm_alloc_kioc(adp); 177*1da177e4SLinus Torvalds 178*1da177e4SLinus Torvalds /* 179*1da177e4SLinus Torvalds * User sent the old mimd_t ioctl packet. Convert it to uioc_t. 180*1da177e4SLinus Torvalds */ 181*1da177e4SLinus Torvalds if ((rval = mimd_to_kioc(argp, adp, kioc))) { 182*1da177e4SLinus Torvalds mraid_mm_dealloc_kioc(adp, kioc); 183*1da177e4SLinus Torvalds return rval; 184*1da177e4SLinus Torvalds } 185*1da177e4SLinus Torvalds 186*1da177e4SLinus Torvalds kioc->done = ioctl_done; 187*1da177e4SLinus Torvalds 188*1da177e4SLinus Torvalds /* 189*1da177e4SLinus Torvalds * Issue the IOCTL to the low level driver. After the IOCTL completes 190*1da177e4SLinus Torvalds * release the kioc if and only if it was _not_ timedout. If it was 191*1da177e4SLinus Torvalds * timedout, that means that resources are still with low level driver. 192*1da177e4SLinus Torvalds */ 193*1da177e4SLinus Torvalds if ((rval = lld_ioctl(adp, kioc))) { 194*1da177e4SLinus Torvalds 195*1da177e4SLinus Torvalds if (!kioc->timedout) 196*1da177e4SLinus Torvalds mraid_mm_dealloc_kioc(adp, kioc); 197*1da177e4SLinus Torvalds 198*1da177e4SLinus Torvalds return rval; 199*1da177e4SLinus Torvalds } 200*1da177e4SLinus Torvalds 201*1da177e4SLinus Torvalds /* 202*1da177e4SLinus Torvalds * Convert the kioc back to user space 203*1da177e4SLinus Torvalds */ 204*1da177e4SLinus Torvalds rval = kioc_to_mimd(kioc, argp); 205*1da177e4SLinus Torvalds 206*1da177e4SLinus Torvalds /* 207*1da177e4SLinus Torvalds * Return the kioc to free pool 208*1da177e4SLinus Torvalds */ 209*1da177e4SLinus Torvalds mraid_mm_dealloc_kioc(adp, kioc); 210*1da177e4SLinus Torvalds 211*1da177e4SLinus Torvalds return rval; 212*1da177e4SLinus Torvalds } 213*1da177e4SLinus Torvalds 214*1da177e4SLinus Torvalds 215*1da177e4SLinus Torvalds /** 216*1da177e4SLinus Torvalds * mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet 217*1da177e4SLinus Torvalds * @umimd : User space mimd_t ioctl packet 218*1da177e4SLinus Torvalds * @adapter : pointer to the adapter (OUT) 219*1da177e4SLinus Torvalds */ 220*1da177e4SLinus Torvalds static mraid_mmadp_t * 221*1da177e4SLinus Torvalds mraid_mm_get_adapter(mimd_t __user *umimd, int *rval) 222*1da177e4SLinus Torvalds { 223*1da177e4SLinus Torvalds mraid_mmadp_t *adapter; 224*1da177e4SLinus Torvalds mimd_t mimd; 225*1da177e4SLinus Torvalds uint32_t adapno; 226*1da177e4SLinus Torvalds int iterator; 227*1da177e4SLinus Torvalds 228*1da177e4SLinus Torvalds 229*1da177e4SLinus Torvalds if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) { 230*1da177e4SLinus Torvalds *rval = -EFAULT; 231*1da177e4SLinus Torvalds return NULL; 232*1da177e4SLinus Torvalds } 233*1da177e4SLinus Torvalds 234*1da177e4SLinus Torvalds adapno = GETADAP(mimd.ui.fcs.adapno); 235*1da177e4SLinus Torvalds 236*1da177e4SLinus Torvalds if (adapno >= adapters_count_g) { 237*1da177e4SLinus Torvalds *rval = -ENODEV; 238*1da177e4SLinus Torvalds return NULL; 239*1da177e4SLinus Torvalds } 240*1da177e4SLinus Torvalds 241*1da177e4SLinus Torvalds adapter = NULL; 242*1da177e4SLinus Torvalds iterator = 0; 243*1da177e4SLinus Torvalds 244*1da177e4SLinus Torvalds list_for_each_entry(adapter, &adapters_list_g, list) { 245*1da177e4SLinus Torvalds if (iterator++ == adapno) break; 246*1da177e4SLinus Torvalds } 247*1da177e4SLinus Torvalds 248*1da177e4SLinus Torvalds if (!adapter) { 249*1da177e4SLinus Torvalds *rval = -ENODEV; 250*1da177e4SLinus Torvalds return NULL; 251*1da177e4SLinus Torvalds } 252*1da177e4SLinus Torvalds 253*1da177e4SLinus Torvalds return adapter; 254*1da177e4SLinus Torvalds } 255*1da177e4SLinus Torvalds 256*1da177e4SLinus Torvalds /* 257*1da177e4SLinus Torvalds * handle_drvrcmd - This routine checks if the opcode is a driver 258*1da177e4SLinus Torvalds * cmd and if it is, handles it. 259*1da177e4SLinus Torvalds * @arg : packet sent by the user app 260*1da177e4SLinus Torvalds * @old_ioctl : mimd if 1; uioc otherwise 261*1da177e4SLinus Torvalds */ 262*1da177e4SLinus Torvalds static int 263*1da177e4SLinus Torvalds handle_drvrcmd(void __user *arg, uint8_t old_ioctl, int *rval) 264*1da177e4SLinus Torvalds { 265*1da177e4SLinus Torvalds mimd_t __user *umimd; 266*1da177e4SLinus Torvalds mimd_t kmimd; 267*1da177e4SLinus Torvalds uint8_t opcode; 268*1da177e4SLinus Torvalds uint8_t subopcode; 269*1da177e4SLinus Torvalds 270*1da177e4SLinus Torvalds if (old_ioctl) 271*1da177e4SLinus Torvalds goto old_packet; 272*1da177e4SLinus Torvalds else 273*1da177e4SLinus Torvalds goto new_packet; 274*1da177e4SLinus Torvalds 275*1da177e4SLinus Torvalds new_packet: 276*1da177e4SLinus Torvalds return (-ENOTSUPP); 277*1da177e4SLinus Torvalds 278*1da177e4SLinus Torvalds old_packet: 279*1da177e4SLinus Torvalds *rval = 0; 280*1da177e4SLinus Torvalds umimd = arg; 281*1da177e4SLinus Torvalds 282*1da177e4SLinus Torvalds if (copy_from_user(&kmimd, umimd, sizeof(mimd_t))) 283*1da177e4SLinus Torvalds return (-EFAULT); 284*1da177e4SLinus Torvalds 285*1da177e4SLinus Torvalds opcode = kmimd.ui.fcs.opcode; 286*1da177e4SLinus Torvalds subopcode = kmimd.ui.fcs.subopcode; 287*1da177e4SLinus Torvalds 288*1da177e4SLinus Torvalds /* 289*1da177e4SLinus Torvalds * If the opcode is 0x82 and the subopcode is either GET_DRVRVER or 290*1da177e4SLinus Torvalds * GET_NUMADP, then we can handle. Otherwise we should return 1 to 291*1da177e4SLinus Torvalds * indicate that we cannot handle this. 292*1da177e4SLinus Torvalds */ 293*1da177e4SLinus Torvalds if (opcode != 0x82) 294*1da177e4SLinus Torvalds return 1; 295*1da177e4SLinus Torvalds 296*1da177e4SLinus Torvalds switch (subopcode) { 297*1da177e4SLinus Torvalds 298*1da177e4SLinus Torvalds case MEGAIOC_QDRVRVER: 299*1da177e4SLinus Torvalds 300*1da177e4SLinus Torvalds if (copy_to_user(kmimd.data, &drvr_ver, sizeof(uint32_t))) 301*1da177e4SLinus Torvalds return (-EFAULT); 302*1da177e4SLinus Torvalds 303*1da177e4SLinus Torvalds return 0; 304*1da177e4SLinus Torvalds 305*1da177e4SLinus Torvalds case MEGAIOC_QNADAP: 306*1da177e4SLinus Torvalds 307*1da177e4SLinus Torvalds *rval = adapters_count_g; 308*1da177e4SLinus Torvalds 309*1da177e4SLinus Torvalds if (copy_to_user(kmimd.data, &adapters_count_g, 310*1da177e4SLinus Torvalds sizeof(uint32_t))) 311*1da177e4SLinus Torvalds return (-EFAULT); 312*1da177e4SLinus Torvalds 313*1da177e4SLinus Torvalds return 0; 314*1da177e4SLinus Torvalds 315*1da177e4SLinus Torvalds default: 316*1da177e4SLinus Torvalds /* cannot handle */ 317*1da177e4SLinus Torvalds return 1; 318*1da177e4SLinus Torvalds } 319*1da177e4SLinus Torvalds 320*1da177e4SLinus Torvalds return 0; 321*1da177e4SLinus Torvalds } 322*1da177e4SLinus Torvalds 323*1da177e4SLinus Torvalds 324*1da177e4SLinus Torvalds /** 325*1da177e4SLinus Torvalds * mimd_to_kioc - Converter from old to new ioctl format 326*1da177e4SLinus Torvalds * 327*1da177e4SLinus Torvalds * @umimd : user space old MIMD IOCTL 328*1da177e4SLinus Torvalds * @kioc : kernel space new format IOCTL 329*1da177e4SLinus Torvalds * 330*1da177e4SLinus Torvalds * Routine to convert MIMD interface IOCTL to new interface IOCTL packet. The 331*1da177e4SLinus Torvalds * new packet is in kernel space so that driver can perform operations on it 332*1da177e4SLinus Torvalds * freely. 333*1da177e4SLinus Torvalds */ 334*1da177e4SLinus Torvalds 335*1da177e4SLinus Torvalds static int 336*1da177e4SLinus Torvalds mimd_to_kioc(mimd_t __user *umimd, mraid_mmadp_t *adp, uioc_t *kioc) 337*1da177e4SLinus Torvalds { 338*1da177e4SLinus Torvalds mbox64_t *mbox64; 339*1da177e4SLinus Torvalds mbox_t *mbox; 340*1da177e4SLinus Torvalds mraid_passthru_t *pthru32; 341*1da177e4SLinus Torvalds uint32_t adapno; 342*1da177e4SLinus Torvalds uint8_t opcode; 343*1da177e4SLinus Torvalds uint8_t subopcode; 344*1da177e4SLinus Torvalds mimd_t mimd; 345*1da177e4SLinus Torvalds 346*1da177e4SLinus Torvalds if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) 347*1da177e4SLinus Torvalds return (-EFAULT); 348*1da177e4SLinus Torvalds 349*1da177e4SLinus Torvalds /* 350*1da177e4SLinus Torvalds * Applications are not allowed to send extd pthru 351*1da177e4SLinus Torvalds */ 352*1da177e4SLinus Torvalds if ((mimd.mbox[0] == MBOXCMD_PASSTHRU64) || 353*1da177e4SLinus Torvalds (mimd.mbox[0] == MBOXCMD_EXTPTHRU)) 354*1da177e4SLinus Torvalds return (-EINVAL); 355*1da177e4SLinus Torvalds 356*1da177e4SLinus Torvalds opcode = mimd.ui.fcs.opcode; 357*1da177e4SLinus Torvalds subopcode = mimd.ui.fcs.subopcode; 358*1da177e4SLinus Torvalds adapno = GETADAP(mimd.ui.fcs.adapno); 359*1da177e4SLinus Torvalds 360*1da177e4SLinus Torvalds if (adapno >= adapters_count_g) 361*1da177e4SLinus Torvalds return (-ENODEV); 362*1da177e4SLinus Torvalds 363*1da177e4SLinus Torvalds kioc->adapno = adapno; 364*1da177e4SLinus Torvalds kioc->mb_type = MBOX_LEGACY; 365*1da177e4SLinus Torvalds kioc->app_type = APPTYPE_MIMD; 366*1da177e4SLinus Torvalds 367*1da177e4SLinus Torvalds switch (opcode) { 368*1da177e4SLinus Torvalds 369*1da177e4SLinus Torvalds case 0x82: 370*1da177e4SLinus Torvalds 371*1da177e4SLinus Torvalds if (subopcode == MEGAIOC_QADAPINFO) { 372*1da177e4SLinus Torvalds 373*1da177e4SLinus Torvalds kioc->opcode = GET_ADAP_INFO; 374*1da177e4SLinus Torvalds kioc->data_dir = UIOC_RD; 375*1da177e4SLinus Torvalds kioc->xferlen = sizeof(mraid_hba_info_t); 376*1da177e4SLinus Torvalds 377*1da177e4SLinus Torvalds if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) 378*1da177e4SLinus Torvalds return (-ENOMEM); 379*1da177e4SLinus Torvalds } 380*1da177e4SLinus Torvalds else { 381*1da177e4SLinus Torvalds con_log(CL_ANN, (KERN_WARNING 382*1da177e4SLinus Torvalds "megaraid cmm: Invalid subop\n")); 383*1da177e4SLinus Torvalds return (-EINVAL); 384*1da177e4SLinus Torvalds } 385*1da177e4SLinus Torvalds 386*1da177e4SLinus Torvalds break; 387*1da177e4SLinus Torvalds 388*1da177e4SLinus Torvalds case 0x81: 389*1da177e4SLinus Torvalds 390*1da177e4SLinus Torvalds kioc->opcode = MBOX_CMD; 391*1da177e4SLinus Torvalds kioc->xferlen = mimd.ui.fcs.length; 392*1da177e4SLinus Torvalds kioc->user_data_len = kioc->xferlen; 393*1da177e4SLinus Torvalds kioc->user_data = mimd.ui.fcs.buffer; 394*1da177e4SLinus Torvalds 395*1da177e4SLinus Torvalds if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) 396*1da177e4SLinus Torvalds return (-ENOMEM); 397*1da177e4SLinus Torvalds 398*1da177e4SLinus Torvalds if (mimd.outlen) kioc->data_dir = UIOC_RD; 399*1da177e4SLinus Torvalds if (mimd.inlen) kioc->data_dir |= UIOC_WR; 400*1da177e4SLinus Torvalds 401*1da177e4SLinus Torvalds break; 402*1da177e4SLinus Torvalds 403*1da177e4SLinus Torvalds case 0x80: 404*1da177e4SLinus Torvalds 405*1da177e4SLinus Torvalds kioc->opcode = MBOX_CMD; 406*1da177e4SLinus Torvalds kioc->xferlen = (mimd.outlen > mimd.inlen) ? 407*1da177e4SLinus Torvalds mimd.outlen : mimd.inlen; 408*1da177e4SLinus Torvalds kioc->user_data_len = kioc->xferlen; 409*1da177e4SLinus Torvalds kioc->user_data = mimd.data; 410*1da177e4SLinus Torvalds 411*1da177e4SLinus Torvalds if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) 412*1da177e4SLinus Torvalds return (-ENOMEM); 413*1da177e4SLinus Torvalds 414*1da177e4SLinus Torvalds if (mimd.outlen) kioc->data_dir = UIOC_RD; 415*1da177e4SLinus Torvalds if (mimd.inlen) kioc->data_dir |= UIOC_WR; 416*1da177e4SLinus Torvalds 417*1da177e4SLinus Torvalds break; 418*1da177e4SLinus Torvalds 419*1da177e4SLinus Torvalds default: 420*1da177e4SLinus Torvalds return (-EINVAL); 421*1da177e4SLinus Torvalds } 422*1da177e4SLinus Torvalds 423*1da177e4SLinus Torvalds /* 424*1da177e4SLinus Torvalds * If driver command, nothing else to do 425*1da177e4SLinus Torvalds */ 426*1da177e4SLinus Torvalds if (opcode == 0x82) 427*1da177e4SLinus Torvalds return 0; 428*1da177e4SLinus Torvalds 429*1da177e4SLinus Torvalds /* 430*1da177e4SLinus Torvalds * This is a mailbox cmd; copy the mailbox from mimd 431*1da177e4SLinus Torvalds */ 432*1da177e4SLinus Torvalds mbox64 = (mbox64_t *)((unsigned long)kioc->cmdbuf); 433*1da177e4SLinus Torvalds mbox = &mbox64->mbox32; 434*1da177e4SLinus Torvalds memcpy(mbox, mimd.mbox, 14); 435*1da177e4SLinus Torvalds 436*1da177e4SLinus Torvalds if (mbox->cmd != MBOXCMD_PASSTHRU) { // regular DCMD 437*1da177e4SLinus Torvalds 438*1da177e4SLinus Torvalds mbox->xferaddr = (uint32_t)kioc->buf_paddr; 439*1da177e4SLinus Torvalds 440*1da177e4SLinus Torvalds if (kioc->data_dir & UIOC_WR) { 441*1da177e4SLinus Torvalds if (copy_from_user(kioc->buf_vaddr, kioc->user_data, 442*1da177e4SLinus Torvalds kioc->xferlen)) { 443*1da177e4SLinus Torvalds return (-EFAULT); 444*1da177e4SLinus Torvalds } 445*1da177e4SLinus Torvalds } 446*1da177e4SLinus Torvalds 447*1da177e4SLinus Torvalds return 0; 448*1da177e4SLinus Torvalds } 449*1da177e4SLinus Torvalds 450*1da177e4SLinus Torvalds /* 451*1da177e4SLinus Torvalds * This is a regular 32-bit pthru cmd; mbox points to pthru struct. 452*1da177e4SLinus Torvalds * Just like in above case, the beginning for memblk is treated as 453*1da177e4SLinus Torvalds * a mailbox. The passthru will begin at next 1K boundary. And the 454*1da177e4SLinus Torvalds * data will start 1K after that. 455*1da177e4SLinus Torvalds */ 456*1da177e4SLinus Torvalds pthru32 = kioc->pthru32; 457*1da177e4SLinus Torvalds kioc->user_pthru = &umimd->pthru; 458*1da177e4SLinus Torvalds mbox->xferaddr = (uint32_t)kioc->pthru32_h; 459*1da177e4SLinus Torvalds 460*1da177e4SLinus Torvalds if (copy_from_user(pthru32, kioc->user_pthru, 461*1da177e4SLinus Torvalds sizeof(mraid_passthru_t))) { 462*1da177e4SLinus Torvalds return (-EFAULT); 463*1da177e4SLinus Torvalds } 464*1da177e4SLinus Torvalds 465*1da177e4SLinus Torvalds pthru32->dataxferaddr = kioc->buf_paddr; 466*1da177e4SLinus Torvalds if (kioc->data_dir & UIOC_WR) { 467*1da177e4SLinus Torvalds if (copy_from_user(kioc->buf_vaddr, kioc->user_data, 468*1da177e4SLinus Torvalds pthru32->dataxferlen)) { 469*1da177e4SLinus Torvalds return (-EFAULT); 470*1da177e4SLinus Torvalds } 471*1da177e4SLinus Torvalds } 472*1da177e4SLinus Torvalds 473*1da177e4SLinus Torvalds return 0; 474*1da177e4SLinus Torvalds } 475*1da177e4SLinus Torvalds 476*1da177e4SLinus Torvalds /** 477*1da177e4SLinus Torvalds * mraid_mm_attch_buf - Attach a free dma buffer for required size 478*1da177e4SLinus Torvalds * 479*1da177e4SLinus Torvalds * @adp : Adapter softstate 480*1da177e4SLinus Torvalds * @kioc : kioc that the buffer needs to be attached to 481*1da177e4SLinus Torvalds * @xferlen : required length for buffer 482*1da177e4SLinus Torvalds * 483*1da177e4SLinus Torvalds * First we search for a pool with smallest buffer that is >= @xferlen. If 484*1da177e4SLinus Torvalds * that pool has no free buffer, we will try for the next bigger size. If none 485*1da177e4SLinus Torvalds * is available, we will try to allocate the smallest buffer that is >= 486*1da177e4SLinus Torvalds * @xferlen and attach it the pool. 487*1da177e4SLinus Torvalds */ 488*1da177e4SLinus Torvalds static int 489*1da177e4SLinus Torvalds mraid_mm_attach_buf(mraid_mmadp_t *adp, uioc_t *kioc, int xferlen) 490*1da177e4SLinus Torvalds { 491*1da177e4SLinus Torvalds mm_dmapool_t *pool; 492*1da177e4SLinus Torvalds int right_pool = -1; 493*1da177e4SLinus Torvalds unsigned long flags; 494*1da177e4SLinus Torvalds int i; 495*1da177e4SLinus Torvalds 496*1da177e4SLinus Torvalds kioc->pool_index = -1; 497*1da177e4SLinus Torvalds kioc->buf_vaddr = NULL; 498*1da177e4SLinus Torvalds kioc->buf_paddr = 0; 499*1da177e4SLinus Torvalds kioc->free_buf = 0; 500*1da177e4SLinus Torvalds 501*1da177e4SLinus Torvalds /* 502*1da177e4SLinus Torvalds * We need xferlen amount of memory. See if we can get it from our 503*1da177e4SLinus Torvalds * dma pools. If we don't get exact size, we will try bigger buffer 504*1da177e4SLinus Torvalds */ 505*1da177e4SLinus Torvalds 506*1da177e4SLinus Torvalds for (i = 0; i < MAX_DMA_POOLS; i++) { 507*1da177e4SLinus Torvalds 508*1da177e4SLinus Torvalds pool = &adp->dma_pool_list[i]; 509*1da177e4SLinus Torvalds 510*1da177e4SLinus Torvalds if (xferlen > pool->buf_size) 511*1da177e4SLinus Torvalds continue; 512*1da177e4SLinus Torvalds 513*1da177e4SLinus Torvalds if (right_pool == -1) 514*1da177e4SLinus Torvalds right_pool = i; 515*1da177e4SLinus Torvalds 516*1da177e4SLinus Torvalds spin_lock_irqsave(&pool->lock, flags); 517*1da177e4SLinus Torvalds 518*1da177e4SLinus Torvalds if (!pool->in_use) { 519*1da177e4SLinus Torvalds 520*1da177e4SLinus Torvalds pool->in_use = 1; 521*1da177e4SLinus Torvalds kioc->pool_index = i; 522*1da177e4SLinus Torvalds kioc->buf_vaddr = pool->vaddr; 523*1da177e4SLinus Torvalds kioc->buf_paddr = pool->paddr; 524*1da177e4SLinus Torvalds 525*1da177e4SLinus Torvalds spin_unlock_irqrestore(&pool->lock, flags); 526*1da177e4SLinus Torvalds return 0; 527*1da177e4SLinus Torvalds } 528*1da177e4SLinus Torvalds else { 529*1da177e4SLinus Torvalds spin_unlock_irqrestore(&pool->lock, flags); 530*1da177e4SLinus Torvalds continue; 531*1da177e4SLinus Torvalds } 532*1da177e4SLinus Torvalds } 533*1da177e4SLinus Torvalds 534*1da177e4SLinus Torvalds /* 535*1da177e4SLinus Torvalds * If xferlen doesn't match any of our pools, return error 536*1da177e4SLinus Torvalds */ 537*1da177e4SLinus Torvalds if (right_pool == -1) 538*1da177e4SLinus Torvalds return -EINVAL; 539*1da177e4SLinus Torvalds 540*1da177e4SLinus Torvalds /* 541*1da177e4SLinus Torvalds * We did not get any buffer from the preallocated pool. Let us try 542*1da177e4SLinus Torvalds * to allocate one new buffer. NOTE: This is a blocking call. 543*1da177e4SLinus Torvalds */ 544*1da177e4SLinus Torvalds pool = &adp->dma_pool_list[right_pool]; 545*1da177e4SLinus Torvalds 546*1da177e4SLinus Torvalds spin_lock_irqsave(&pool->lock, flags); 547*1da177e4SLinus Torvalds 548*1da177e4SLinus Torvalds kioc->pool_index = right_pool; 549*1da177e4SLinus Torvalds kioc->free_buf = 1; 550*1da177e4SLinus Torvalds kioc->buf_vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL, 551*1da177e4SLinus Torvalds &kioc->buf_paddr); 552*1da177e4SLinus Torvalds spin_unlock_irqrestore(&pool->lock, flags); 553*1da177e4SLinus Torvalds 554*1da177e4SLinus Torvalds if (!kioc->buf_vaddr) 555*1da177e4SLinus Torvalds return -ENOMEM; 556*1da177e4SLinus Torvalds 557*1da177e4SLinus Torvalds return 0; 558*1da177e4SLinus Torvalds } 559*1da177e4SLinus Torvalds 560*1da177e4SLinus Torvalds /** 561*1da177e4SLinus Torvalds * mraid_mm_alloc_kioc - Returns a uioc_t from free list 562*1da177e4SLinus Torvalds * @adp : Adapter softstate for this module 563*1da177e4SLinus Torvalds * 564*1da177e4SLinus Torvalds * The kioc_semaphore is initialized with number of kioc nodes in the 565*1da177e4SLinus Torvalds * free kioc pool. If the kioc pool is empty, this function blocks till 566*1da177e4SLinus Torvalds * a kioc becomes free. 567*1da177e4SLinus Torvalds */ 568*1da177e4SLinus Torvalds static uioc_t * 569*1da177e4SLinus Torvalds mraid_mm_alloc_kioc(mraid_mmadp_t *adp) 570*1da177e4SLinus Torvalds { 571*1da177e4SLinus Torvalds uioc_t *kioc; 572*1da177e4SLinus Torvalds struct list_head* head; 573*1da177e4SLinus Torvalds unsigned long flags; 574*1da177e4SLinus Torvalds 575*1da177e4SLinus Torvalds down(&adp->kioc_semaphore); 576*1da177e4SLinus Torvalds 577*1da177e4SLinus Torvalds spin_lock_irqsave(&adp->kioc_pool_lock, flags); 578*1da177e4SLinus Torvalds 579*1da177e4SLinus Torvalds head = &adp->kioc_pool; 580*1da177e4SLinus Torvalds 581*1da177e4SLinus Torvalds if (list_empty(head)) { 582*1da177e4SLinus Torvalds up(&adp->kioc_semaphore); 583*1da177e4SLinus Torvalds spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); 584*1da177e4SLinus Torvalds 585*1da177e4SLinus Torvalds con_log(CL_ANN, ("megaraid cmm: kioc list empty!\n")); 586*1da177e4SLinus Torvalds return NULL; 587*1da177e4SLinus Torvalds } 588*1da177e4SLinus Torvalds 589*1da177e4SLinus Torvalds kioc = list_entry(head->next, uioc_t, list); 590*1da177e4SLinus Torvalds list_del_init(&kioc->list); 591*1da177e4SLinus Torvalds 592*1da177e4SLinus Torvalds spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); 593*1da177e4SLinus Torvalds 594*1da177e4SLinus Torvalds memset((caddr_t)(unsigned long)kioc->cmdbuf, 0, sizeof(mbox64_t)); 595*1da177e4SLinus Torvalds memset((caddr_t) kioc->pthru32, 0, sizeof(mraid_passthru_t)); 596*1da177e4SLinus Torvalds 597*1da177e4SLinus Torvalds kioc->buf_vaddr = NULL; 598*1da177e4SLinus Torvalds kioc->buf_paddr = 0; 599*1da177e4SLinus Torvalds kioc->pool_index =-1; 600*1da177e4SLinus Torvalds kioc->free_buf = 0; 601*1da177e4SLinus Torvalds kioc->user_data = NULL; 602*1da177e4SLinus Torvalds kioc->user_data_len = 0; 603*1da177e4SLinus Torvalds kioc->user_pthru = NULL; 604*1da177e4SLinus Torvalds kioc->timedout = 0; 605*1da177e4SLinus Torvalds 606*1da177e4SLinus Torvalds return kioc; 607*1da177e4SLinus Torvalds } 608*1da177e4SLinus Torvalds 609*1da177e4SLinus Torvalds /** 610*1da177e4SLinus Torvalds * mraid_mm_dealloc_kioc - Return kioc to free pool 611*1da177e4SLinus Torvalds * 612*1da177e4SLinus Torvalds * @adp : Adapter softstate 613*1da177e4SLinus Torvalds * @kioc : uioc_t node to be returned to free pool 614*1da177e4SLinus Torvalds */ 615*1da177e4SLinus Torvalds static void 616*1da177e4SLinus Torvalds mraid_mm_dealloc_kioc(mraid_mmadp_t *adp, uioc_t *kioc) 617*1da177e4SLinus Torvalds { 618*1da177e4SLinus Torvalds mm_dmapool_t *pool; 619*1da177e4SLinus Torvalds unsigned long flags; 620*1da177e4SLinus Torvalds 621*1da177e4SLinus Torvalds if (kioc->pool_index != -1) { 622*1da177e4SLinus Torvalds pool = &adp->dma_pool_list[kioc->pool_index]; 623*1da177e4SLinus Torvalds 624*1da177e4SLinus Torvalds /* This routine may be called in non-isr context also */ 625*1da177e4SLinus Torvalds spin_lock_irqsave(&pool->lock, flags); 626*1da177e4SLinus Torvalds 627*1da177e4SLinus Torvalds /* 628*1da177e4SLinus Torvalds * While attaching the dma buffer, if we didn't get the 629*1da177e4SLinus Torvalds * required buffer from the pool, we would have allocated 630*1da177e4SLinus Torvalds * it at the run time and set the free_buf flag. We must 631*1da177e4SLinus Torvalds * free that buffer. Otherwise, just mark that the buffer is 632*1da177e4SLinus Torvalds * not in use 633*1da177e4SLinus Torvalds */ 634*1da177e4SLinus Torvalds if (kioc->free_buf == 1) 635*1da177e4SLinus Torvalds pci_pool_free(pool->handle, kioc->buf_vaddr, 636*1da177e4SLinus Torvalds kioc->buf_paddr); 637*1da177e4SLinus Torvalds else 638*1da177e4SLinus Torvalds pool->in_use = 0; 639*1da177e4SLinus Torvalds 640*1da177e4SLinus Torvalds spin_unlock_irqrestore(&pool->lock, flags); 641*1da177e4SLinus Torvalds } 642*1da177e4SLinus Torvalds 643*1da177e4SLinus Torvalds /* Return the kioc to the free pool */ 644*1da177e4SLinus Torvalds spin_lock_irqsave(&adp->kioc_pool_lock, flags); 645*1da177e4SLinus Torvalds list_add(&kioc->list, &adp->kioc_pool); 646*1da177e4SLinus Torvalds spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); 647*1da177e4SLinus Torvalds 648*1da177e4SLinus Torvalds /* increment the free kioc count */ 649*1da177e4SLinus Torvalds up(&adp->kioc_semaphore); 650*1da177e4SLinus Torvalds 651*1da177e4SLinus Torvalds return; 652*1da177e4SLinus Torvalds } 653*1da177e4SLinus Torvalds 654*1da177e4SLinus Torvalds /** 655*1da177e4SLinus Torvalds * lld_ioctl - Routine to issue ioctl to low level drvr 656*1da177e4SLinus Torvalds * 657*1da177e4SLinus Torvalds * @adp : The adapter handle 658*1da177e4SLinus Torvalds * @kioc : The ioctl packet with kernel addresses 659*1da177e4SLinus Torvalds */ 660*1da177e4SLinus Torvalds static int 661*1da177e4SLinus Torvalds lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc) 662*1da177e4SLinus Torvalds { 663*1da177e4SLinus Torvalds int rval; 664*1da177e4SLinus Torvalds struct timer_list timer; 665*1da177e4SLinus Torvalds struct timer_list *tp = NULL; 666*1da177e4SLinus Torvalds 667*1da177e4SLinus Torvalds kioc->status = -ENODATA; 668*1da177e4SLinus Torvalds rval = adp->issue_uioc(adp->drvr_data, kioc, IOCTL_ISSUE); 669*1da177e4SLinus Torvalds 670*1da177e4SLinus Torvalds if (rval) return rval; 671*1da177e4SLinus Torvalds 672*1da177e4SLinus Torvalds /* 673*1da177e4SLinus Torvalds * Start the timer 674*1da177e4SLinus Torvalds */ 675*1da177e4SLinus Torvalds if (adp->timeout > 0) { 676*1da177e4SLinus Torvalds tp = &timer; 677*1da177e4SLinus Torvalds init_timer(tp); 678*1da177e4SLinus Torvalds 679*1da177e4SLinus Torvalds tp->function = lld_timedout; 680*1da177e4SLinus Torvalds tp->data = (unsigned long)kioc; 681*1da177e4SLinus Torvalds tp->expires = jiffies + adp->timeout * HZ; 682*1da177e4SLinus Torvalds 683*1da177e4SLinus Torvalds add_timer(tp); 684*1da177e4SLinus Torvalds } 685*1da177e4SLinus Torvalds 686*1da177e4SLinus Torvalds /* 687*1da177e4SLinus Torvalds * Wait till the low level driver completes the ioctl. After this 688*1da177e4SLinus Torvalds * call, the ioctl either completed successfully or timedout. 689*1da177e4SLinus Torvalds */ 690*1da177e4SLinus Torvalds wait_event(wait_q, (kioc->status != -ENODATA)); 691*1da177e4SLinus Torvalds if (tp) { 692*1da177e4SLinus Torvalds del_timer_sync(tp); 693*1da177e4SLinus Torvalds } 694*1da177e4SLinus Torvalds 695*1da177e4SLinus Torvalds /* 696*1da177e4SLinus Torvalds * If the command had timedout, we mark the controller offline 697*1da177e4SLinus Torvalds * before returning 698*1da177e4SLinus Torvalds */ 699*1da177e4SLinus Torvalds if (kioc->timedout) { 700*1da177e4SLinus Torvalds adp->quiescent = 0; 701*1da177e4SLinus Torvalds } 702*1da177e4SLinus Torvalds 703*1da177e4SLinus Torvalds return kioc->status; 704*1da177e4SLinus Torvalds } 705*1da177e4SLinus Torvalds 706*1da177e4SLinus Torvalds 707*1da177e4SLinus Torvalds /** 708*1da177e4SLinus Torvalds * ioctl_done - callback from the low level driver 709*1da177e4SLinus Torvalds * 710*1da177e4SLinus Torvalds * @kioc : completed ioctl packet 711*1da177e4SLinus Torvalds */ 712*1da177e4SLinus Torvalds static void 713*1da177e4SLinus Torvalds ioctl_done(uioc_t *kioc) 714*1da177e4SLinus Torvalds { 715*1da177e4SLinus Torvalds uint32_t adapno; 716*1da177e4SLinus Torvalds int iterator; 717*1da177e4SLinus Torvalds mraid_mmadp_t* adapter; 718*1da177e4SLinus Torvalds 719*1da177e4SLinus Torvalds /* 720*1da177e4SLinus Torvalds * When the kioc returns from driver, make sure it still doesn't 721*1da177e4SLinus Torvalds * have ENODATA in status. Otherwise, driver will hang on wait_event 722*1da177e4SLinus Torvalds * forever 723*1da177e4SLinus Torvalds */ 724*1da177e4SLinus Torvalds if (kioc->status == -ENODATA) { 725*1da177e4SLinus Torvalds con_log(CL_ANN, (KERN_WARNING 726*1da177e4SLinus Torvalds "megaraid cmm: lld didn't change status!\n")); 727*1da177e4SLinus Torvalds 728*1da177e4SLinus Torvalds kioc->status = -EINVAL; 729*1da177e4SLinus Torvalds } 730*1da177e4SLinus Torvalds 731*1da177e4SLinus Torvalds /* 732*1da177e4SLinus Torvalds * Check if this kioc was timedout before. If so, nobody is waiting 733*1da177e4SLinus Torvalds * on this kioc. We don't have to wake up anybody. Instead, we just 734*1da177e4SLinus Torvalds * have to free the kioc 735*1da177e4SLinus Torvalds */ 736*1da177e4SLinus Torvalds if (kioc->timedout) { 737*1da177e4SLinus Torvalds iterator = 0; 738*1da177e4SLinus Torvalds adapter = NULL; 739*1da177e4SLinus Torvalds adapno = kioc->adapno; 740*1da177e4SLinus Torvalds 741*1da177e4SLinus Torvalds con_log(CL_ANN, ( KERN_WARNING "megaraid cmm: completed " 742*1da177e4SLinus Torvalds "ioctl that was timedout before\n")); 743*1da177e4SLinus Torvalds 744*1da177e4SLinus Torvalds list_for_each_entry(adapter, &adapters_list_g, list) { 745*1da177e4SLinus Torvalds if (iterator++ == adapno) break; 746*1da177e4SLinus Torvalds } 747*1da177e4SLinus Torvalds 748*1da177e4SLinus Torvalds kioc->timedout = 0; 749*1da177e4SLinus Torvalds 750*1da177e4SLinus Torvalds if (adapter) { 751*1da177e4SLinus Torvalds mraid_mm_dealloc_kioc( adapter, kioc ); 752*1da177e4SLinus Torvalds } 753*1da177e4SLinus Torvalds } 754*1da177e4SLinus Torvalds else { 755*1da177e4SLinus Torvalds wake_up(&wait_q); 756*1da177e4SLinus Torvalds } 757*1da177e4SLinus Torvalds } 758*1da177e4SLinus Torvalds 759*1da177e4SLinus Torvalds 760*1da177e4SLinus Torvalds /* 761*1da177e4SLinus Torvalds * lld_timedout : callback from the expired timer 762*1da177e4SLinus Torvalds * 763*1da177e4SLinus Torvalds * @ptr : ioctl packet that timed out 764*1da177e4SLinus Torvalds */ 765*1da177e4SLinus Torvalds static void 766*1da177e4SLinus Torvalds lld_timedout(unsigned long ptr) 767*1da177e4SLinus Torvalds { 768*1da177e4SLinus Torvalds uioc_t *kioc = (uioc_t *)ptr; 769*1da177e4SLinus Torvalds 770*1da177e4SLinus Torvalds kioc->status = -ETIME; 771*1da177e4SLinus Torvalds kioc->timedout = 1; 772*1da177e4SLinus Torvalds 773*1da177e4SLinus Torvalds con_log(CL_ANN, (KERN_WARNING "megaraid cmm: ioctl timed out\n")); 774*1da177e4SLinus Torvalds 775*1da177e4SLinus Torvalds wake_up(&wait_q); 776*1da177e4SLinus Torvalds } 777*1da177e4SLinus Torvalds 778*1da177e4SLinus Torvalds 779*1da177e4SLinus Torvalds /** 780*1da177e4SLinus Torvalds * kioc_to_mimd : Converter from new back to old format 781*1da177e4SLinus Torvalds * 782*1da177e4SLinus Torvalds * @kioc : Kernel space IOCTL packet (successfully issued) 783*1da177e4SLinus Torvalds * @mimd : User space MIMD packet 784*1da177e4SLinus Torvalds */ 785*1da177e4SLinus Torvalds static int 786*1da177e4SLinus Torvalds kioc_to_mimd(uioc_t *kioc, mimd_t __user *mimd) 787*1da177e4SLinus Torvalds { 788*1da177e4SLinus Torvalds mimd_t kmimd; 789*1da177e4SLinus Torvalds uint8_t opcode; 790*1da177e4SLinus Torvalds uint8_t subopcode; 791*1da177e4SLinus Torvalds 792*1da177e4SLinus Torvalds mbox64_t *mbox64; 793*1da177e4SLinus Torvalds mraid_passthru_t __user *upthru32; 794*1da177e4SLinus Torvalds mraid_passthru_t *kpthru32; 795*1da177e4SLinus Torvalds mcontroller_t cinfo; 796*1da177e4SLinus Torvalds mraid_hba_info_t *hinfo; 797*1da177e4SLinus Torvalds 798*1da177e4SLinus Torvalds 799*1da177e4SLinus Torvalds if (copy_from_user(&kmimd, mimd, sizeof(mimd_t))) 800*1da177e4SLinus Torvalds return (-EFAULT); 801*1da177e4SLinus Torvalds 802*1da177e4SLinus Torvalds opcode = kmimd.ui.fcs.opcode; 803*1da177e4SLinus Torvalds subopcode = kmimd.ui.fcs.subopcode; 804*1da177e4SLinus Torvalds 805*1da177e4SLinus Torvalds if (opcode == 0x82) { 806*1da177e4SLinus Torvalds switch (subopcode) { 807*1da177e4SLinus Torvalds 808*1da177e4SLinus Torvalds case MEGAIOC_QADAPINFO: 809*1da177e4SLinus Torvalds 810*1da177e4SLinus Torvalds hinfo = (mraid_hba_info_t *)(unsigned long) 811*1da177e4SLinus Torvalds kioc->buf_vaddr; 812*1da177e4SLinus Torvalds 813*1da177e4SLinus Torvalds hinfo_to_cinfo(hinfo, &cinfo); 814*1da177e4SLinus Torvalds 815*1da177e4SLinus Torvalds if (copy_to_user(kmimd.data, &cinfo, sizeof(cinfo))) 816*1da177e4SLinus Torvalds return (-EFAULT); 817*1da177e4SLinus Torvalds 818*1da177e4SLinus Torvalds return 0; 819*1da177e4SLinus Torvalds 820*1da177e4SLinus Torvalds default: 821*1da177e4SLinus Torvalds return (-EINVAL); 822*1da177e4SLinus Torvalds } 823*1da177e4SLinus Torvalds 824*1da177e4SLinus Torvalds return 0; 825*1da177e4SLinus Torvalds } 826*1da177e4SLinus Torvalds 827*1da177e4SLinus Torvalds mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; 828*1da177e4SLinus Torvalds 829*1da177e4SLinus Torvalds if (kioc->user_pthru) { 830*1da177e4SLinus Torvalds 831*1da177e4SLinus Torvalds upthru32 = kioc->user_pthru; 832*1da177e4SLinus Torvalds kpthru32 = kioc->pthru32; 833*1da177e4SLinus Torvalds 834*1da177e4SLinus Torvalds if (copy_to_user(&upthru32->scsistatus, 835*1da177e4SLinus Torvalds &kpthru32->scsistatus, 836*1da177e4SLinus Torvalds sizeof(uint8_t))) { 837*1da177e4SLinus Torvalds return (-EFAULT); 838*1da177e4SLinus Torvalds } 839*1da177e4SLinus Torvalds } 840*1da177e4SLinus Torvalds 841*1da177e4SLinus Torvalds if (kioc->user_data) { 842*1da177e4SLinus Torvalds if (copy_to_user(kioc->user_data, kioc->buf_vaddr, 843*1da177e4SLinus Torvalds kioc->user_data_len)) { 844*1da177e4SLinus Torvalds return (-EFAULT); 845*1da177e4SLinus Torvalds } 846*1da177e4SLinus Torvalds } 847*1da177e4SLinus Torvalds 848*1da177e4SLinus Torvalds if (copy_to_user(&mimd->mbox[17], 849*1da177e4SLinus Torvalds &mbox64->mbox32.status, sizeof(uint8_t))) { 850*1da177e4SLinus Torvalds return (-EFAULT); 851*1da177e4SLinus Torvalds } 852*1da177e4SLinus Torvalds 853*1da177e4SLinus Torvalds return 0; 854*1da177e4SLinus Torvalds } 855*1da177e4SLinus Torvalds 856*1da177e4SLinus Torvalds 857*1da177e4SLinus Torvalds /** 858*1da177e4SLinus Torvalds * hinfo_to_cinfo - Convert new format hba info into old format 859*1da177e4SLinus Torvalds * 860*1da177e4SLinus Torvalds * @hinfo : New format, more comprehensive adapter info 861*1da177e4SLinus Torvalds * @cinfo : Old format adapter info to support mimd_t apps 862*1da177e4SLinus Torvalds */ 863*1da177e4SLinus Torvalds static void 864*1da177e4SLinus Torvalds hinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo) 865*1da177e4SLinus Torvalds { 866*1da177e4SLinus Torvalds if (!hinfo || !cinfo) 867*1da177e4SLinus Torvalds return; 868*1da177e4SLinus Torvalds 869*1da177e4SLinus Torvalds cinfo->base = hinfo->baseport; 870*1da177e4SLinus Torvalds cinfo->irq = hinfo->irq; 871*1da177e4SLinus Torvalds cinfo->numldrv = hinfo->num_ldrv; 872*1da177e4SLinus Torvalds cinfo->pcibus = hinfo->pci_bus; 873*1da177e4SLinus Torvalds cinfo->pcidev = hinfo->pci_slot; 874*1da177e4SLinus Torvalds cinfo->pcifun = PCI_FUNC(hinfo->pci_dev_fn); 875*1da177e4SLinus Torvalds cinfo->pciid = hinfo->pci_device_id; 876*1da177e4SLinus Torvalds cinfo->pcivendor = hinfo->pci_vendor_id; 877*1da177e4SLinus Torvalds cinfo->pcislot = hinfo->pci_slot; 878*1da177e4SLinus Torvalds cinfo->uid = hinfo->unique_id; 879*1da177e4SLinus Torvalds } 880*1da177e4SLinus Torvalds 881*1da177e4SLinus Torvalds 882*1da177e4SLinus Torvalds /* 883*1da177e4SLinus Torvalds * mraid_mm_register_adp - Registration routine for low level drvrs 884*1da177e4SLinus Torvalds * 885*1da177e4SLinus Torvalds * @adp : Adapter objejct 886*1da177e4SLinus Torvalds */ 887*1da177e4SLinus Torvalds int 888*1da177e4SLinus Torvalds mraid_mm_register_adp(mraid_mmadp_t *lld_adp) 889*1da177e4SLinus Torvalds { 890*1da177e4SLinus Torvalds mraid_mmadp_t *adapter; 891*1da177e4SLinus Torvalds mbox64_t *mbox_list; 892*1da177e4SLinus Torvalds uioc_t *kioc; 893*1da177e4SLinus Torvalds uint32_t rval; 894*1da177e4SLinus Torvalds int i; 895*1da177e4SLinus Torvalds 896*1da177e4SLinus Torvalds 897*1da177e4SLinus Torvalds if (lld_adp->drvr_type != DRVRTYPE_MBOX) 898*1da177e4SLinus Torvalds return (-EINVAL); 899*1da177e4SLinus Torvalds 900*1da177e4SLinus Torvalds adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL); 901*1da177e4SLinus Torvalds 902*1da177e4SLinus Torvalds if (!adapter) { 903*1da177e4SLinus Torvalds rval = -ENOMEM; 904*1da177e4SLinus Torvalds goto memalloc_error; 905*1da177e4SLinus Torvalds } 906*1da177e4SLinus Torvalds 907*1da177e4SLinus Torvalds memset(adapter, 0, sizeof(mraid_mmadp_t)); 908*1da177e4SLinus Torvalds 909*1da177e4SLinus Torvalds adapter->unique_id = lld_adp->unique_id; 910*1da177e4SLinus Torvalds adapter->drvr_type = lld_adp->drvr_type; 911*1da177e4SLinus Torvalds adapter->drvr_data = lld_adp->drvr_data; 912*1da177e4SLinus Torvalds adapter->pdev = lld_adp->pdev; 913*1da177e4SLinus Torvalds adapter->issue_uioc = lld_adp->issue_uioc; 914*1da177e4SLinus Torvalds adapter->timeout = lld_adp->timeout; 915*1da177e4SLinus Torvalds adapter->max_kioc = lld_adp->max_kioc; 916*1da177e4SLinus Torvalds adapter->quiescent = 1; 917*1da177e4SLinus Torvalds 918*1da177e4SLinus Torvalds /* 919*1da177e4SLinus Torvalds * Allocate single blocks of memory for all required kiocs, 920*1da177e4SLinus Torvalds * mailboxes and passthru structures. 921*1da177e4SLinus Torvalds */ 922*1da177e4SLinus Torvalds adapter->kioc_list = kmalloc(sizeof(uioc_t) * lld_adp->max_kioc, 923*1da177e4SLinus Torvalds GFP_KERNEL); 924*1da177e4SLinus Torvalds adapter->mbox_list = kmalloc(sizeof(mbox64_t) * lld_adp->max_kioc, 925*1da177e4SLinus Torvalds GFP_KERNEL); 926*1da177e4SLinus Torvalds adapter->pthru_dma_pool = pci_pool_create("megaraid mm pthru pool", 927*1da177e4SLinus Torvalds adapter->pdev, 928*1da177e4SLinus Torvalds sizeof(mraid_passthru_t), 929*1da177e4SLinus Torvalds 16, 0); 930*1da177e4SLinus Torvalds 931*1da177e4SLinus Torvalds if (!adapter->kioc_list || !adapter->mbox_list || 932*1da177e4SLinus Torvalds !adapter->pthru_dma_pool) { 933*1da177e4SLinus Torvalds 934*1da177e4SLinus Torvalds con_log(CL_ANN, (KERN_WARNING 935*1da177e4SLinus Torvalds "megaraid cmm: out of memory, %s %d\n", __FUNCTION__, 936*1da177e4SLinus Torvalds __LINE__)); 937*1da177e4SLinus Torvalds 938*1da177e4SLinus Torvalds rval = (-ENOMEM); 939*1da177e4SLinus Torvalds 940*1da177e4SLinus Torvalds goto memalloc_error; 941*1da177e4SLinus Torvalds } 942*1da177e4SLinus Torvalds 943*1da177e4SLinus Torvalds /* 944*1da177e4SLinus Torvalds * Slice kioc_list and make a kioc_pool with the individiual kiocs 945*1da177e4SLinus Torvalds */ 946*1da177e4SLinus Torvalds INIT_LIST_HEAD(&adapter->kioc_pool); 947*1da177e4SLinus Torvalds spin_lock_init(&adapter->kioc_pool_lock); 948*1da177e4SLinus Torvalds sema_init(&adapter->kioc_semaphore, lld_adp->max_kioc); 949*1da177e4SLinus Torvalds 950*1da177e4SLinus Torvalds mbox_list = (mbox64_t *)adapter->mbox_list; 951*1da177e4SLinus Torvalds 952*1da177e4SLinus Torvalds for (i = 0; i < lld_adp->max_kioc; i++) { 953*1da177e4SLinus Torvalds 954*1da177e4SLinus Torvalds kioc = adapter->kioc_list + i; 955*1da177e4SLinus Torvalds kioc->cmdbuf = (uint64_t)(unsigned long)(mbox_list + i); 956*1da177e4SLinus Torvalds kioc->pthru32 = pci_pool_alloc(adapter->pthru_dma_pool, 957*1da177e4SLinus Torvalds GFP_KERNEL, &kioc->pthru32_h); 958*1da177e4SLinus Torvalds 959*1da177e4SLinus Torvalds if (!kioc->pthru32) { 960*1da177e4SLinus Torvalds 961*1da177e4SLinus Torvalds con_log(CL_ANN, (KERN_WARNING 962*1da177e4SLinus Torvalds "megaraid cmm: out of memory, %s %d\n", 963*1da177e4SLinus Torvalds __FUNCTION__, __LINE__)); 964*1da177e4SLinus Torvalds 965*1da177e4SLinus Torvalds rval = (-ENOMEM); 966*1da177e4SLinus Torvalds 967*1da177e4SLinus Torvalds goto pthru_dma_pool_error; 968*1da177e4SLinus Torvalds } 969*1da177e4SLinus Torvalds 970*1da177e4SLinus Torvalds list_add_tail(&kioc->list, &adapter->kioc_pool); 971*1da177e4SLinus Torvalds } 972*1da177e4SLinus Torvalds 973*1da177e4SLinus Torvalds // Setup the dma pools for data buffers 974*1da177e4SLinus Torvalds if ((rval = mraid_mm_setup_dma_pools(adapter)) != 0) { 975*1da177e4SLinus Torvalds goto dma_pool_error; 976*1da177e4SLinus Torvalds } 977*1da177e4SLinus Torvalds 978*1da177e4SLinus Torvalds list_add_tail(&adapter->list, &adapters_list_g); 979*1da177e4SLinus Torvalds 980*1da177e4SLinus Torvalds adapters_count_g++; 981*1da177e4SLinus Torvalds 982*1da177e4SLinus Torvalds return 0; 983*1da177e4SLinus Torvalds 984*1da177e4SLinus Torvalds dma_pool_error: 985*1da177e4SLinus Torvalds /* Do nothing */ 986*1da177e4SLinus Torvalds 987*1da177e4SLinus Torvalds pthru_dma_pool_error: 988*1da177e4SLinus Torvalds 989*1da177e4SLinus Torvalds for (i = 0; i < lld_adp->max_kioc; i++) { 990*1da177e4SLinus Torvalds kioc = adapter->kioc_list + i; 991*1da177e4SLinus Torvalds if (kioc->pthru32) { 992*1da177e4SLinus Torvalds pci_pool_free(adapter->pthru_dma_pool, kioc->pthru32, 993*1da177e4SLinus Torvalds kioc->pthru32_h); 994*1da177e4SLinus Torvalds } 995*1da177e4SLinus Torvalds } 996*1da177e4SLinus Torvalds 997*1da177e4SLinus Torvalds memalloc_error: 998*1da177e4SLinus Torvalds 999*1da177e4SLinus Torvalds if (adapter->kioc_list) 1000*1da177e4SLinus Torvalds kfree(adapter->kioc_list); 1001*1da177e4SLinus Torvalds 1002*1da177e4SLinus Torvalds if (adapter->mbox_list) 1003*1da177e4SLinus Torvalds kfree(adapter->mbox_list); 1004*1da177e4SLinus Torvalds 1005*1da177e4SLinus Torvalds if (adapter->pthru_dma_pool) 1006*1da177e4SLinus Torvalds pci_pool_destroy(adapter->pthru_dma_pool); 1007*1da177e4SLinus Torvalds 1008*1da177e4SLinus Torvalds if (adapter) 1009*1da177e4SLinus Torvalds kfree(adapter); 1010*1da177e4SLinus Torvalds 1011*1da177e4SLinus Torvalds return rval; 1012*1da177e4SLinus Torvalds } 1013*1da177e4SLinus Torvalds 1014*1da177e4SLinus Torvalds 1015*1da177e4SLinus Torvalds /** 1016*1da177e4SLinus Torvalds * mraid_mm_adapter_app_handle - return the application handle for this adapter 1017*1da177e4SLinus Torvalds * 1018*1da177e4SLinus Torvalds * For the given driver data, locate the adadpter in our global list and 1019*1da177e4SLinus Torvalds * return the corresponding handle, which is also used by applications to 1020*1da177e4SLinus Torvalds * uniquely identify an adapter. 1021*1da177e4SLinus Torvalds * 1022*1da177e4SLinus Torvalds * @param unique_id : adapter unique identifier 1023*1da177e4SLinus Torvalds * 1024*1da177e4SLinus Torvalds * @return adapter handle if found in the list 1025*1da177e4SLinus Torvalds * @return 0 if adapter could not be located, should never happen though 1026*1da177e4SLinus Torvalds */ 1027*1da177e4SLinus Torvalds uint32_t 1028*1da177e4SLinus Torvalds mraid_mm_adapter_app_handle(uint32_t unique_id) 1029*1da177e4SLinus Torvalds { 1030*1da177e4SLinus Torvalds mraid_mmadp_t *adapter; 1031*1da177e4SLinus Torvalds mraid_mmadp_t *tmp; 1032*1da177e4SLinus Torvalds int index = 0; 1033*1da177e4SLinus Torvalds 1034*1da177e4SLinus Torvalds list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) { 1035*1da177e4SLinus Torvalds 1036*1da177e4SLinus Torvalds if (adapter->unique_id == unique_id) { 1037*1da177e4SLinus Torvalds 1038*1da177e4SLinus Torvalds return MKADAP(index); 1039*1da177e4SLinus Torvalds } 1040*1da177e4SLinus Torvalds 1041*1da177e4SLinus Torvalds index++; 1042*1da177e4SLinus Torvalds } 1043*1da177e4SLinus Torvalds 1044*1da177e4SLinus Torvalds return 0; 1045*1da177e4SLinus Torvalds } 1046*1da177e4SLinus Torvalds 1047*1da177e4SLinus Torvalds 1048*1da177e4SLinus Torvalds /** 1049*1da177e4SLinus Torvalds * mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter 1050*1da177e4SLinus Torvalds * 1051*1da177e4SLinus Torvalds * @adp : Adapter softstate 1052*1da177e4SLinus Torvalds * 1053*1da177e4SLinus Torvalds * We maintain a pool of dma buffers per each adapter. Each pool has one 1054*1da177e4SLinus Torvalds * buffer. E.g, we may have 5 dma pools - one each for 4k, 8k ... 64k buffers. 1055*1da177e4SLinus Torvalds * We have just one 4k buffer in 4k pool, one 8k buffer in 8k pool etc. We 1056*1da177e4SLinus Torvalds * dont' want to waste too much memory by allocating more buffers per each 1057*1da177e4SLinus Torvalds * pool. 1058*1da177e4SLinus Torvalds */ 1059*1da177e4SLinus Torvalds static int 1060*1da177e4SLinus Torvalds mraid_mm_setup_dma_pools(mraid_mmadp_t *adp) 1061*1da177e4SLinus Torvalds { 1062*1da177e4SLinus Torvalds mm_dmapool_t *pool; 1063*1da177e4SLinus Torvalds int bufsize; 1064*1da177e4SLinus Torvalds int i; 1065*1da177e4SLinus Torvalds 1066*1da177e4SLinus Torvalds /* 1067*1da177e4SLinus Torvalds * Create MAX_DMA_POOLS number of pools 1068*1da177e4SLinus Torvalds */ 1069*1da177e4SLinus Torvalds bufsize = MRAID_MM_INIT_BUFF_SIZE; 1070*1da177e4SLinus Torvalds 1071*1da177e4SLinus Torvalds for (i = 0; i < MAX_DMA_POOLS; i++){ 1072*1da177e4SLinus Torvalds 1073*1da177e4SLinus Torvalds pool = &adp->dma_pool_list[i]; 1074*1da177e4SLinus Torvalds 1075*1da177e4SLinus Torvalds pool->buf_size = bufsize; 1076*1da177e4SLinus Torvalds spin_lock_init(&pool->lock); 1077*1da177e4SLinus Torvalds 1078*1da177e4SLinus Torvalds pool->handle = pci_pool_create("megaraid mm data buffer", 1079*1da177e4SLinus Torvalds adp->pdev, bufsize, 16, 0); 1080*1da177e4SLinus Torvalds 1081*1da177e4SLinus Torvalds if (!pool->handle) { 1082*1da177e4SLinus Torvalds goto dma_pool_setup_error; 1083*1da177e4SLinus Torvalds } 1084*1da177e4SLinus Torvalds 1085*1da177e4SLinus Torvalds pool->vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL, 1086*1da177e4SLinus Torvalds &pool->paddr); 1087*1da177e4SLinus Torvalds 1088*1da177e4SLinus Torvalds if (!pool->vaddr) 1089*1da177e4SLinus Torvalds goto dma_pool_setup_error; 1090*1da177e4SLinus Torvalds 1091*1da177e4SLinus Torvalds bufsize = bufsize * 2; 1092*1da177e4SLinus Torvalds } 1093*1da177e4SLinus Torvalds 1094*1da177e4SLinus Torvalds return 0; 1095*1da177e4SLinus Torvalds 1096*1da177e4SLinus Torvalds dma_pool_setup_error: 1097*1da177e4SLinus Torvalds 1098*1da177e4SLinus Torvalds mraid_mm_teardown_dma_pools(adp); 1099*1da177e4SLinus Torvalds return (-ENOMEM); 1100*1da177e4SLinus Torvalds } 1101*1da177e4SLinus Torvalds 1102*1da177e4SLinus Torvalds 1103*1da177e4SLinus Torvalds /* 1104*1da177e4SLinus Torvalds * mraid_mm_unregister_adp - Unregister routine for low level drivers 1105*1da177e4SLinus Torvalds * Assume no outstanding ioctls to llds. 1106*1da177e4SLinus Torvalds * 1107*1da177e4SLinus Torvalds * @unique_id : UID of the adpater 1108*1da177e4SLinus Torvalds */ 1109*1da177e4SLinus Torvalds int 1110*1da177e4SLinus Torvalds mraid_mm_unregister_adp(uint32_t unique_id) 1111*1da177e4SLinus Torvalds { 1112*1da177e4SLinus Torvalds mraid_mmadp_t *adapter; 1113*1da177e4SLinus Torvalds mraid_mmadp_t *tmp; 1114*1da177e4SLinus Torvalds 1115*1da177e4SLinus Torvalds list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) { 1116*1da177e4SLinus Torvalds 1117*1da177e4SLinus Torvalds 1118*1da177e4SLinus Torvalds if (adapter->unique_id == unique_id) { 1119*1da177e4SLinus Torvalds 1120*1da177e4SLinus Torvalds adapters_count_g--; 1121*1da177e4SLinus Torvalds 1122*1da177e4SLinus Torvalds list_del_init(&adapter->list); 1123*1da177e4SLinus Torvalds 1124*1da177e4SLinus Torvalds mraid_mm_free_adp_resources(adapter); 1125*1da177e4SLinus Torvalds 1126*1da177e4SLinus Torvalds kfree(adapter); 1127*1da177e4SLinus Torvalds 1128*1da177e4SLinus Torvalds con_log(CL_ANN, ( 1129*1da177e4SLinus Torvalds "megaraid cmm: Unregistered one adapter:%#x\n", 1130*1da177e4SLinus Torvalds unique_id)); 1131*1da177e4SLinus Torvalds 1132*1da177e4SLinus Torvalds return 0; 1133*1da177e4SLinus Torvalds } 1134*1da177e4SLinus Torvalds } 1135*1da177e4SLinus Torvalds 1136*1da177e4SLinus Torvalds return (-ENODEV); 1137*1da177e4SLinus Torvalds } 1138*1da177e4SLinus Torvalds 1139*1da177e4SLinus Torvalds /** 1140*1da177e4SLinus Torvalds * mraid_mm_free_adp_resources - Free adapter softstate 1141*1da177e4SLinus Torvalds * 1142*1da177e4SLinus Torvalds * @adp : Adapter softstate 1143*1da177e4SLinus Torvalds */ 1144*1da177e4SLinus Torvalds static void 1145*1da177e4SLinus Torvalds mraid_mm_free_adp_resources(mraid_mmadp_t *adp) 1146*1da177e4SLinus Torvalds { 1147*1da177e4SLinus Torvalds uioc_t *kioc; 1148*1da177e4SLinus Torvalds int i; 1149*1da177e4SLinus Torvalds 1150*1da177e4SLinus Torvalds mraid_mm_teardown_dma_pools(adp); 1151*1da177e4SLinus Torvalds 1152*1da177e4SLinus Torvalds for (i = 0; i < adp->max_kioc; i++) { 1153*1da177e4SLinus Torvalds 1154*1da177e4SLinus Torvalds kioc = adp->kioc_list + i; 1155*1da177e4SLinus Torvalds 1156*1da177e4SLinus Torvalds pci_pool_free(adp->pthru_dma_pool, kioc->pthru32, 1157*1da177e4SLinus Torvalds kioc->pthru32_h); 1158*1da177e4SLinus Torvalds } 1159*1da177e4SLinus Torvalds 1160*1da177e4SLinus Torvalds kfree(adp->kioc_list); 1161*1da177e4SLinus Torvalds 1162*1da177e4SLinus Torvalds kfree(adp->mbox_list); 1163*1da177e4SLinus Torvalds 1164*1da177e4SLinus Torvalds pci_pool_destroy(adp->pthru_dma_pool); 1165*1da177e4SLinus Torvalds 1166*1da177e4SLinus Torvalds 1167*1da177e4SLinus Torvalds return; 1168*1da177e4SLinus Torvalds } 1169*1da177e4SLinus Torvalds 1170*1da177e4SLinus Torvalds 1171*1da177e4SLinus Torvalds /** 1172*1da177e4SLinus Torvalds * mraid_mm_teardown_dma_pools - Free all per adapter dma buffers 1173*1da177e4SLinus Torvalds * 1174*1da177e4SLinus Torvalds * @adp : Adapter softstate 1175*1da177e4SLinus Torvalds */ 1176*1da177e4SLinus Torvalds static void 1177*1da177e4SLinus Torvalds mraid_mm_teardown_dma_pools(mraid_mmadp_t *adp) 1178*1da177e4SLinus Torvalds { 1179*1da177e4SLinus Torvalds int i; 1180*1da177e4SLinus Torvalds mm_dmapool_t *pool; 1181*1da177e4SLinus Torvalds 1182*1da177e4SLinus Torvalds for (i = 0; i < MAX_DMA_POOLS; i++) { 1183*1da177e4SLinus Torvalds 1184*1da177e4SLinus Torvalds pool = &adp->dma_pool_list[i]; 1185*1da177e4SLinus Torvalds 1186*1da177e4SLinus Torvalds if (pool->handle) { 1187*1da177e4SLinus Torvalds 1188*1da177e4SLinus Torvalds if (pool->vaddr) 1189*1da177e4SLinus Torvalds pci_pool_free(pool->handle, pool->vaddr, 1190*1da177e4SLinus Torvalds pool->paddr); 1191*1da177e4SLinus Torvalds 1192*1da177e4SLinus Torvalds pci_pool_destroy(pool->handle); 1193*1da177e4SLinus Torvalds pool->handle = NULL; 1194*1da177e4SLinus Torvalds } 1195*1da177e4SLinus Torvalds } 1196*1da177e4SLinus Torvalds 1197*1da177e4SLinus Torvalds return; 1198*1da177e4SLinus Torvalds } 1199*1da177e4SLinus Torvalds 1200*1da177e4SLinus Torvalds /** 1201*1da177e4SLinus Torvalds * mraid_mm_init : Module entry point 1202*1da177e4SLinus Torvalds */ 1203*1da177e4SLinus Torvalds static int __init 1204*1da177e4SLinus Torvalds mraid_mm_init(void) 1205*1da177e4SLinus Torvalds { 1206*1da177e4SLinus Torvalds // Announce the driver version 1207*1da177e4SLinus Torvalds con_log(CL_ANN, (KERN_INFO "megaraid cmm: %s %s\n", 1208*1da177e4SLinus Torvalds LSI_COMMON_MOD_VERSION, LSI_COMMON_MOD_EXT_VERSION)); 1209*1da177e4SLinus Torvalds 1210*1da177e4SLinus Torvalds majorno = register_chrdev(0, "megadev", &lsi_fops); 1211*1da177e4SLinus Torvalds 1212*1da177e4SLinus Torvalds if (majorno < 0) { 1213*1da177e4SLinus Torvalds con_log(CL_ANN, ("megaraid cmm: cannot get major\n")); 1214*1da177e4SLinus Torvalds return majorno; 1215*1da177e4SLinus Torvalds } 1216*1da177e4SLinus Torvalds 1217*1da177e4SLinus Torvalds init_waitqueue_head(&wait_q); 1218*1da177e4SLinus Torvalds 1219*1da177e4SLinus Torvalds INIT_LIST_HEAD(&adapters_list_g); 1220*1da177e4SLinus Torvalds 1221*1da177e4SLinus Torvalds return 0; 1222*1da177e4SLinus Torvalds } 1223*1da177e4SLinus Torvalds 1224*1da177e4SLinus Torvalds 1225*1da177e4SLinus Torvalds /** 1226*1da177e4SLinus Torvalds * mraid_mm_compat_ioctl : 32bit to 64bit ioctl conversion routine 1227*1da177e4SLinus Torvalds */ 1228*1da177e4SLinus Torvalds #ifdef CONFIG_COMPAT 1229*1da177e4SLinus Torvalds static long 1230*1da177e4SLinus Torvalds mraid_mm_compat_ioctl(struct file *filep, unsigned int cmd, 1231*1da177e4SLinus Torvalds unsigned long arg) 1232*1da177e4SLinus Torvalds { 1233*1da177e4SLinus Torvalds int err; 1234*1da177e4SLinus Torvalds lock_kernel(); 1235*1da177e4SLinus Torvalds err = mraid_mm_ioctl(NULL, filep, cmd, arg); 1236*1da177e4SLinus Torvalds unlock_kernel(); 1237*1da177e4SLinus Torvalds return err; 1238*1da177e4SLinus Torvalds } 1239*1da177e4SLinus Torvalds #endif 1240*1da177e4SLinus Torvalds 1241*1da177e4SLinus Torvalds /** 1242*1da177e4SLinus Torvalds * mraid_mm_exit : Module exit point 1243*1da177e4SLinus Torvalds */ 1244*1da177e4SLinus Torvalds static void __exit 1245*1da177e4SLinus Torvalds mraid_mm_exit(void) 1246*1da177e4SLinus Torvalds { 1247*1da177e4SLinus Torvalds con_log(CL_DLEVEL1 , ("exiting common mod\n")); 1248*1da177e4SLinus Torvalds 1249*1da177e4SLinus Torvalds unregister_chrdev(majorno, "megadev"); 1250*1da177e4SLinus Torvalds } 1251*1da177e4SLinus Torvalds 1252*1da177e4SLinus Torvalds module_init(mraid_mm_init); 1253*1da177e4SLinus Torvalds module_exit(mraid_mm_exit); 1254*1da177e4SLinus Torvalds 1255*1da177e4SLinus Torvalds /* vi: set ts=8 sw=8 tw=78: */ 1256