11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Adaptec AAC series RAID controller driver 3fa195afeSAlan Cox * (c) Copyright 2001 Red Hat Inc. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * based on the old aacraid driver that is.. 61da177e4SLinus Torvalds * Adaptec aacraid device driver for Linux. 71da177e4SLinus Torvalds * 8e8b12f0fSMahesh Rajashekhara * Copyright (c) 2000-2010 Adaptec, Inc. 9e8b12f0fSMahesh Rajashekhara * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 121da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 131da177e4SLinus Torvalds * the Free Software Foundation; either version 2, or (at your option) 141da177e4SLinus Torvalds * any later version. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 171da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 181da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 191da177e4SLinus Torvalds * GNU General Public License for more details. 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 221da177e4SLinus Torvalds * along with this program; see the file COPYING. If not, write to 231da177e4SLinus Torvalds * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds * Module Name: 261da177e4SLinus Torvalds * commctrl.c 271da177e4SLinus Torvalds * 281da177e4SLinus Torvalds * Abstract: Contains all routines for control of the AFA comm layer 291da177e4SLinus Torvalds * 301da177e4SLinus Torvalds */ 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds #include <linux/kernel.h> 331da177e4SLinus Torvalds #include <linux/init.h> 341da177e4SLinus Torvalds #include <linux/types.h> 351da177e4SLinus Torvalds #include <linux/pci.h> 361da177e4SLinus Torvalds #include <linux/spinlock.h> 371da177e4SLinus Torvalds #include <linux/slab.h> 381da177e4SLinus Torvalds #include <linux/completion.h> 391da177e4SLinus Torvalds #include <linux/dma-mapping.h> 401da177e4SLinus Torvalds #include <linux/blkdev.h> 41c8f7b073SMark Haverkamp #include <linux/delay.h> /* ssleep prototype */ 42dc4adbf4SMark Haverkamp #include <linux/kthread.h> 436188e10dSMatthew Wilcox #include <linux/semaphore.h> 441da177e4SLinus Torvalds #include <asm/uaccess.h> 4509050715SMark Salyzyn #include <scsi/scsi_host.h> 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds #include "aacraid.h" 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds /** 501da177e4SLinus Torvalds * ioctl_send_fib - send a FIB from userspace 511da177e4SLinus Torvalds * @dev: adapter is being processed 521da177e4SLinus Torvalds * @arg: arguments to the ioctl call 531da177e4SLinus Torvalds * 541da177e4SLinus Torvalds * This routine sends a fib to the adapter on behalf of a user level 551da177e4SLinus Torvalds * program. 561da177e4SLinus Torvalds */ 577c00ffa3SMark Haverkamp # define AAC_DEBUG_PREAMBLE KERN_INFO 587c00ffa3SMark Haverkamp # define AAC_DEBUG_POSTAMBLE 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) 611da177e4SLinus Torvalds { 621da177e4SLinus Torvalds struct hw_fib * kfib; 631da177e4SLinus Torvalds struct fib *fibptr; 647c00ffa3SMark Haverkamp struct hw_fib * hw_fib = (struct hw_fib *)0; 657c00ffa3SMark Haverkamp dma_addr_t hw_fib_pa = (dma_addr_t)0LL; 667c00ffa3SMark Haverkamp unsigned size; 677c00ffa3SMark Haverkamp int retval; 681da177e4SLinus Torvalds 6933bb3b29SMark Haverkamp if (dev->in_reset) { 7033bb3b29SMark Haverkamp return -EBUSY; 7133bb3b29SMark Haverkamp } 72bfb35aa8SMark Haverkamp fibptr = aac_fib_alloc(dev); 737c00ffa3SMark Haverkamp if(fibptr == NULL) { 741da177e4SLinus Torvalds return -ENOMEM; 757c00ffa3SMark Haverkamp } 761da177e4SLinus Torvalds 77a8166a52SMark Haverkamp kfib = fibptr->hw_fib_va; 781da177e4SLinus Torvalds /* 791da177e4SLinus Torvalds * First copy in the header so that we can check the size field. 801da177e4SLinus Torvalds */ 811da177e4SLinus Torvalds if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) { 82bfb35aa8SMark Haverkamp aac_fib_free(fibptr); 831da177e4SLinus Torvalds return -EFAULT; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds /* 861da177e4SLinus Torvalds * Since we copy based on the fib header size, make sure that we 871da177e4SLinus Torvalds * will not overrun the buffer when we copy the memory. Return 881da177e4SLinus Torvalds * an error if we would. 891da177e4SLinus Torvalds */ 907c00ffa3SMark Haverkamp size = le16_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr); 917c00ffa3SMark Haverkamp if (size < le16_to_cpu(kfib->header.SenderSize)) 927c00ffa3SMark Haverkamp size = le16_to_cpu(kfib->header.SenderSize); 937c00ffa3SMark Haverkamp if (size > dev->max_fib_size) { 94e9899113SFUJITA Tomonori dma_addr_t daddr; 95e9899113SFUJITA Tomonori 966e289a90SMark Haverkamp if (size > 2048) { 976e289a90SMark Haverkamp retval = -EINVAL; 986e289a90SMark Haverkamp goto cleanup; 996e289a90SMark Haverkamp } 100e9899113SFUJITA Tomonori 101e9899113SFUJITA Tomonori kfib = pci_alloc_consistent(dev->pdev, size, &daddr); 102e9899113SFUJITA Tomonori if (!kfib) { 103e9899113SFUJITA Tomonori retval = -ENOMEM; 104e9899113SFUJITA Tomonori goto cleanup; 105e9899113SFUJITA Tomonori } 106e9899113SFUJITA Tomonori 1077c00ffa3SMark Haverkamp /* Highjack the hw_fib */ 108a8166a52SMark Haverkamp hw_fib = fibptr->hw_fib_va; 1097c00ffa3SMark Haverkamp hw_fib_pa = fibptr->hw_fib_pa; 110e9899113SFUJITA Tomonori fibptr->hw_fib_va = kfib; 111e9899113SFUJITA Tomonori fibptr->hw_fib_pa = daddr; 1127c00ffa3SMark Haverkamp memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size); 1137c00ffa3SMark Haverkamp memcpy(kfib, hw_fib, dev->max_fib_size); 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds 1167c00ffa3SMark Haverkamp if (copy_from_user(kfib, arg, size)) { 1177c00ffa3SMark Haverkamp retval = -EFAULT; 1187c00ffa3SMark Haverkamp goto cleanup; 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 12156b58712SMark Haverkamp if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) { 1221da177e4SLinus Torvalds aac_adapter_interrupt(dev); 1231da177e4SLinus Torvalds /* 1241da177e4SLinus Torvalds * Since we didn't really send a fib, zero out the state to allow 1251da177e4SLinus Torvalds * cleanup code not to assert. 1261da177e4SLinus Torvalds */ 1271da177e4SLinus Torvalds kfib->header.XferState = 0; 1281da177e4SLinus Torvalds } else { 129bfb35aa8SMark Haverkamp retval = aac_fib_send(le16_to_cpu(kfib->header.Command), fibptr, 1301da177e4SLinus Torvalds le16_to_cpu(kfib->header.Size) , FsaNormal, 1311da177e4SLinus Torvalds 1, 1, NULL, NULL); 1321da177e4SLinus Torvalds if (retval) { 1337c00ffa3SMark Haverkamp goto cleanup; 1341da177e4SLinus Torvalds } 135bfb35aa8SMark Haverkamp if (aac_fib_complete(fibptr) != 0) { 1367c00ffa3SMark Haverkamp retval = -EINVAL; 1377c00ffa3SMark Haverkamp goto cleanup; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds /* 1411da177e4SLinus Torvalds * Make sure that the size returned by the adapter (which includes 1421da177e4SLinus Torvalds * the header) is less than or equal to the size of a fib, so we 1431da177e4SLinus Torvalds * don't corrupt application data. Then copy that size to the user 1441da177e4SLinus Torvalds * buffer. (Don't try to add the header information again, since it 1451da177e4SLinus Torvalds * was already included by the adapter.) 1461da177e4SLinus Torvalds */ 1471da177e4SLinus Torvalds 1487c00ffa3SMark Haverkamp retval = 0; 1497c00ffa3SMark Haverkamp if (copy_to_user(arg, (void *)kfib, size)) 1507c00ffa3SMark Haverkamp retval = -EFAULT; 1517c00ffa3SMark Haverkamp cleanup: 1527c00ffa3SMark Haverkamp if (hw_fib) { 1537c00ffa3SMark Haverkamp pci_free_consistent(dev->pdev, size, kfib, fibptr->hw_fib_pa); 1547c00ffa3SMark Haverkamp fibptr->hw_fib_pa = hw_fib_pa; 155a8166a52SMark Haverkamp fibptr->hw_fib_va = hw_fib; 1561da177e4SLinus Torvalds } 157cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (retval != -ERESTARTSYS) 158bfb35aa8SMark Haverkamp aac_fib_free(fibptr); 1597c00ffa3SMark Haverkamp return retval; 1601da177e4SLinus Torvalds } 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds /** 1631da177e4SLinus Torvalds * open_getadapter_fib - Get the next fib 1641da177e4SLinus Torvalds * 1651da177e4SLinus Torvalds * This routine will get the next Fib, if available, from the AdapterFibContext 1661da177e4SLinus Torvalds * passed in from the user. 1671da177e4SLinus Torvalds */ 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) 1701da177e4SLinus Torvalds { 1711da177e4SLinus Torvalds struct aac_fib_context * fibctx; 1721da177e4SLinus Torvalds int status; 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); 1751da177e4SLinus Torvalds if (fibctx == NULL) { 1761da177e4SLinus Torvalds status = -ENOMEM; 1771da177e4SLinus Torvalds } else { 1781da177e4SLinus Torvalds unsigned long flags; 1791da177e4SLinus Torvalds struct list_head * entry; 1801da177e4SLinus Torvalds struct aac_fib_context * context; 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; 1831da177e4SLinus Torvalds fibctx->size = sizeof(struct aac_fib_context); 1841da177e4SLinus Torvalds /* 1851da177e4SLinus Torvalds * Yes yes, I know this could be an index, but we have a 1861da177e4SLinus Torvalds * better guarantee of uniqueness for the locked loop below. 1871da177e4SLinus Torvalds * Without the aid of a persistent history, this also helps 1881da177e4SLinus Torvalds * reduce the chance that the opaque context would be reused. 1891da177e4SLinus Torvalds */ 1901da177e4SLinus Torvalds fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF); 1911da177e4SLinus Torvalds /* 1921da177e4SLinus Torvalds * Initialize the mutex used to wait for the next AIF. 1931da177e4SLinus Torvalds */ 1946de76cfcSThomas Gleixner sema_init(&fibctx->wait_sem, 0); 1951da177e4SLinus Torvalds fibctx->wait = 0; 1961da177e4SLinus Torvalds /* 1971da177e4SLinus Torvalds * Initialize the fibs and set the count of fibs on 1981da177e4SLinus Torvalds * the list to 0. 1991da177e4SLinus Torvalds */ 2001da177e4SLinus Torvalds fibctx->count = 0; 2011da177e4SLinus Torvalds INIT_LIST_HEAD(&fibctx->fib_list); 2021da177e4SLinus Torvalds fibctx->jiffies = jiffies/HZ; 2031da177e4SLinus Torvalds /* 2041da177e4SLinus Torvalds * Now add this context onto the adapter's 2051da177e4SLinus Torvalds * AdapterFibContext list. 2061da177e4SLinus Torvalds */ 2071da177e4SLinus Torvalds spin_lock_irqsave(&dev->fib_lock, flags); 2081da177e4SLinus Torvalds /* Ensure that we have a unique identifier */ 2091da177e4SLinus Torvalds entry = dev->fib_list.next; 2101da177e4SLinus Torvalds while (entry != &dev->fib_list) { 2111da177e4SLinus Torvalds context = list_entry(entry, struct aac_fib_context, next); 2121da177e4SLinus Torvalds if (context->unique == fibctx->unique) { 2131da177e4SLinus Torvalds /* Not unique (32 bits) */ 2141da177e4SLinus Torvalds fibctx->unique++; 2151da177e4SLinus Torvalds entry = dev->fib_list.next; 2161da177e4SLinus Torvalds } else { 2171da177e4SLinus Torvalds entry = entry->next; 2181da177e4SLinus Torvalds } 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds list_add_tail(&fibctx->next, &dev->fib_list); 2211da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 2221da177e4SLinus Torvalds if (copy_to_user(arg, &fibctx->unique, 2231da177e4SLinus Torvalds sizeof(fibctx->unique))) { 2241da177e4SLinus Torvalds status = -EFAULT; 2251da177e4SLinus Torvalds } else { 2261da177e4SLinus Torvalds status = 0; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds return status; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds /** 2331da177e4SLinus Torvalds * next_getadapter_fib - get the next fib 2341da177e4SLinus Torvalds * @dev: adapter to use 2351da177e4SLinus Torvalds * @arg: ioctl argument 2361da177e4SLinus Torvalds * 2371da177e4SLinus Torvalds * This routine will get the next Fib, if available, from the AdapterFibContext 2381da177e4SLinus Torvalds * passed in from the user. 2391da177e4SLinus Torvalds */ 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) 2421da177e4SLinus Torvalds { 2431da177e4SLinus Torvalds struct fib_ioctl f; 2441da177e4SLinus Torvalds struct fib *fib; 2451da177e4SLinus Torvalds struct aac_fib_context *fibctx; 2461da177e4SLinus Torvalds int status; 2471da177e4SLinus Torvalds struct list_head * entry; 2481da177e4SLinus Torvalds unsigned long flags; 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) 2511da177e4SLinus Torvalds return -EFAULT; 2521da177e4SLinus Torvalds /* 2531da177e4SLinus Torvalds * Verify that the HANDLE passed in was a valid AdapterFibContext 2541da177e4SLinus Torvalds * 2551da177e4SLinus Torvalds * Search the list of AdapterFibContext addresses on the adapter 2561da177e4SLinus Torvalds * to be sure this is a valid address 2571da177e4SLinus Torvalds */ 2585234e25cSSalyzyn, Mark spin_lock_irqsave(&dev->fib_lock, flags); 2591da177e4SLinus Torvalds entry = dev->fib_list.next; 2601da177e4SLinus Torvalds fibctx = NULL; 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds while (entry != &dev->fib_list) { 2631da177e4SLinus Torvalds fibctx = list_entry(entry, struct aac_fib_context, next); 2641da177e4SLinus Torvalds /* 2651da177e4SLinus Torvalds * Extract the AdapterFibContext from the Input parameters. 2661da177e4SLinus Torvalds */ 2671da177e4SLinus Torvalds if (fibctx->unique == f.fibctx) { /* We found a winner */ 2681da177e4SLinus Torvalds break; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds entry = entry->next; 2711da177e4SLinus Torvalds fibctx = NULL; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds if (!fibctx) { 2745234e25cSSalyzyn, Mark spin_unlock_irqrestore(&dev->fib_lock, flags); 2751da177e4SLinus Torvalds dprintk ((KERN_INFO "Fib Context not found\n")); 2761da177e4SLinus Torvalds return -EINVAL; 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || 2801da177e4SLinus Torvalds (fibctx->size != sizeof(struct aac_fib_context))) { 2815234e25cSSalyzyn, Mark spin_unlock_irqrestore(&dev->fib_lock, flags); 2821da177e4SLinus Torvalds dprintk ((KERN_INFO "Fib Context corrupt?\n")); 2831da177e4SLinus Torvalds return -EINVAL; 2841da177e4SLinus Torvalds } 2851da177e4SLinus Torvalds status = 0; 2861da177e4SLinus Torvalds /* 2871da177e4SLinus Torvalds * If there are no fibs to send back, then either wait or return 2881da177e4SLinus Torvalds * -EAGAIN 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds return_fib: 2911da177e4SLinus Torvalds if (!list_empty(&fibctx->fib_list)) { 2921da177e4SLinus Torvalds /* 2931da177e4SLinus Torvalds * Pull the next fib from the fibs 2941da177e4SLinus Torvalds */ 2951da177e4SLinus Torvalds entry = fibctx->fib_list.next; 2961da177e4SLinus Torvalds list_del(entry); 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds fib = list_entry(entry, struct fib, fiblink); 2991da177e4SLinus Torvalds fibctx->count--; 3001da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 301a8166a52SMark Haverkamp if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) { 302a8166a52SMark Haverkamp kfree(fib->hw_fib_va); 3031da177e4SLinus Torvalds kfree(fib); 3041da177e4SLinus Torvalds return -EFAULT; 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds /* 3071da177e4SLinus Torvalds * Free the space occupied by this copy of the fib. 3081da177e4SLinus Torvalds */ 309a8166a52SMark Haverkamp kfree(fib->hw_fib_va); 3101da177e4SLinus Torvalds kfree(fib); 3111da177e4SLinus Torvalds status = 0; 3121da177e4SLinus Torvalds } else { 3131da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 314dc4adbf4SMark Haverkamp /* If someone killed the AIF aacraid thread, restart it */ 315dc4adbf4SMark Haverkamp status = !dev->aif_thread; 3168c867b25SMark Haverkamp if (status && !dev->in_reset && dev->queues && dev->fsa_dev) { 317dc4adbf4SMark Haverkamp /* Be paranoid, be very paranoid! */ 318dc4adbf4SMark Haverkamp kthread_stop(dev->thread); 319dc4adbf4SMark Haverkamp ssleep(1); 320dc4adbf4SMark Haverkamp dev->aif_thread = 0; 321f170168bSKees Cook dev->thread = kthread_run(aac_command_thread, dev, 322f170168bSKees Cook "%s", dev->name); 323dc4adbf4SMark Haverkamp ssleep(1); 324dc4adbf4SMark Haverkamp } 3251da177e4SLinus Torvalds if (f.wait) { 3261da177e4SLinus Torvalds if(down_interruptible(&fibctx->wait_sem) < 0) { 327cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech status = -ERESTARTSYS; 3281da177e4SLinus Torvalds } else { 3291da177e4SLinus Torvalds /* Lock again and retry */ 3301da177e4SLinus Torvalds spin_lock_irqsave(&dev->fib_lock, flags); 3311da177e4SLinus Torvalds goto return_fib; 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds } else { 3341da177e4SLinus Torvalds status = -EAGAIN; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds } 33712a26d08SMark Haverkamp fibctx->jiffies = jiffies/HZ; 3381da177e4SLinus Torvalds return status; 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) 3421da177e4SLinus Torvalds { 3431da177e4SLinus Torvalds struct fib *fib; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* 3461da177e4SLinus Torvalds * First free any FIBs that have not been consumed. 3471da177e4SLinus Torvalds */ 3481da177e4SLinus Torvalds while (!list_empty(&fibctx->fib_list)) { 3491da177e4SLinus Torvalds struct list_head * entry; 3501da177e4SLinus Torvalds /* 3511da177e4SLinus Torvalds * Pull the next fib from the fibs 3521da177e4SLinus Torvalds */ 3531da177e4SLinus Torvalds entry = fibctx->fib_list.next; 3541da177e4SLinus Torvalds list_del(entry); 3551da177e4SLinus Torvalds fib = list_entry(entry, struct fib, fiblink); 3561da177e4SLinus Torvalds fibctx->count--; 3571da177e4SLinus Torvalds /* 3581da177e4SLinus Torvalds * Free the space occupied by this copy of the fib. 3591da177e4SLinus Torvalds */ 360a8166a52SMark Haverkamp kfree(fib->hw_fib_va); 3611da177e4SLinus Torvalds kfree(fib); 3621da177e4SLinus Torvalds } 3631da177e4SLinus Torvalds /* 3641da177e4SLinus Torvalds * Remove the Context from the AdapterFibContext List 3651da177e4SLinus Torvalds */ 3661da177e4SLinus Torvalds list_del(&fibctx->next); 3671da177e4SLinus Torvalds /* 3681da177e4SLinus Torvalds * Invalidate context 3691da177e4SLinus Torvalds */ 3701da177e4SLinus Torvalds fibctx->type = 0; 3711da177e4SLinus Torvalds /* 3721da177e4SLinus Torvalds * Free the space occupied by the Context 3731da177e4SLinus Torvalds */ 3741da177e4SLinus Torvalds kfree(fibctx); 3751da177e4SLinus Torvalds return 0; 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds /** 3791da177e4SLinus Torvalds * close_getadapter_fib - close down user fib context 3801da177e4SLinus Torvalds * @dev: adapter 3811da177e4SLinus Torvalds * @arg: ioctl arguments 3821da177e4SLinus Torvalds * 3831da177e4SLinus Torvalds * This routine will close down the fibctx passed in from the user. 3841da177e4SLinus Torvalds */ 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) 3871da177e4SLinus Torvalds { 3881da177e4SLinus Torvalds struct aac_fib_context *fibctx; 3891da177e4SLinus Torvalds int status; 3901da177e4SLinus Torvalds unsigned long flags; 3911da177e4SLinus Torvalds struct list_head * entry; 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds /* 3941da177e4SLinus Torvalds * Verify that the HANDLE passed in was a valid AdapterFibContext 3951da177e4SLinus Torvalds * 3961da177e4SLinus Torvalds * Search the list of AdapterFibContext addresses on the adapter 3971da177e4SLinus Torvalds * to be sure this is a valid address 3981da177e4SLinus Torvalds */ 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds entry = dev->fib_list.next; 4011da177e4SLinus Torvalds fibctx = NULL; 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds while(entry != &dev->fib_list) { 4041da177e4SLinus Torvalds fibctx = list_entry(entry, struct aac_fib_context, next); 4051da177e4SLinus Torvalds /* 4061da177e4SLinus Torvalds * Extract the fibctx from the input parameters 4071da177e4SLinus Torvalds */ 408142956afSAl Viro if (fibctx->unique == (u32)(uintptr_t)arg) /* We found a winner */ 4091da177e4SLinus Torvalds break; 4101da177e4SLinus Torvalds entry = entry->next; 4111da177e4SLinus Torvalds fibctx = NULL; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds if (!fibctx) 4151da177e4SLinus Torvalds return 0; /* Already gone */ 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || 4181da177e4SLinus Torvalds (fibctx->size != sizeof(struct aac_fib_context))) 4191da177e4SLinus Torvalds return -EINVAL; 4201da177e4SLinus Torvalds spin_lock_irqsave(&dev->fib_lock, flags); 4211da177e4SLinus Torvalds status = aac_close_fib_context(dev, fibctx); 4221da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 4231da177e4SLinus Torvalds return status; 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds /** 4271da177e4SLinus Torvalds * check_revision - close down user fib context 4281da177e4SLinus Torvalds * @dev: adapter 4291da177e4SLinus Torvalds * @arg: ioctl arguments 4301da177e4SLinus Torvalds * 4311da177e4SLinus Torvalds * This routine returns the driver version. 4321da177e4SLinus Torvalds * Under Linux, there have been no version incompatibilities, so this is 4331da177e4SLinus Torvalds * simple! 4341da177e4SLinus Torvalds */ 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds static int check_revision(struct aac_dev *dev, void __user *arg) 4371da177e4SLinus Torvalds { 4381da177e4SLinus Torvalds struct revision response; 439c7f47602SMark Haverkamp char *driver_version = aac_driver_version; 440c7f47602SMark Haverkamp u32 version; 4411da177e4SLinus Torvalds 4429f30a323SMark Haverkamp response.compat = 1; 443c7f47602SMark Haverkamp version = (simple_strtol(driver_version, 444c7f47602SMark Haverkamp &driver_version, 10) << 24) | 0x00000400; 445c7f47602SMark Haverkamp version += simple_strtol(driver_version + 1, &driver_version, 10) << 16; 446c7f47602SMark Haverkamp version += simple_strtol(driver_version + 1, NULL, 10); 447c7f47602SMark Haverkamp response.version = cpu_to_le32(version); 4488ce3eca4SSalyzyn, Mark # ifdef AAC_DRIVER_BUILD 449c7f47602SMark Haverkamp response.build = cpu_to_le32(AAC_DRIVER_BUILD); 450c7f47602SMark Haverkamp # else 451c7f47602SMark Haverkamp response.build = cpu_to_le32(9999); 452c7f47602SMark Haverkamp # endif 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds if (copy_to_user(arg, &response, sizeof(response))) 4551da177e4SLinus Torvalds return -EFAULT; 4561da177e4SLinus Torvalds return 0; 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds 4597c00ffa3SMark Haverkamp 4601da177e4SLinus Torvalds /** 4611da177e4SLinus Torvalds * 4621da177e4SLinus Torvalds * aac_send_raw_scb 4631da177e4SLinus Torvalds * 4641da177e4SLinus Torvalds */ 4651da177e4SLinus Torvalds 4664833869eSAdrian Bunk static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) 4671da177e4SLinus Torvalds { 4681da177e4SLinus Torvalds struct fib* srbfib; 4691da177e4SLinus Torvalds int status; 47056b58712SMark Haverkamp struct aac_srb *srbcmd = NULL; 47156b58712SMark Haverkamp struct user_aac_srb *user_srbcmd = NULL; 47256b58712SMark Haverkamp struct user_aac_srb __user *user_srb = arg; 4731da177e4SLinus Torvalds struct aac_srb_reply __user *user_reply; 4741da177e4SLinus Torvalds struct aac_srb_reply* reply; 4751da177e4SLinus Torvalds u32 fibsize = 0; 4761da177e4SLinus Torvalds u32 flags = 0; 4771da177e4SLinus Torvalds s32 rcode = 0; 4781da177e4SLinus Torvalds u32 data_dir; 4791da177e4SLinus Torvalds void __user *sg_user[32]; 4801da177e4SLinus Torvalds void *sg_list[32]; 4811da177e4SLinus Torvalds u32 sg_indx = 0; 4821da177e4SLinus Torvalds u32 byte_count = 0; 483f2b1a06aSMark Haverkamp u32 actual_fibsize64, actual_fibsize = 0; 4841da177e4SLinus Torvalds int i; 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds 48733bb3b29SMark Haverkamp if (dev->in_reset) { 48833bb3b29SMark Haverkamp dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n")); 48933bb3b29SMark Haverkamp return -EBUSY; 49033bb3b29SMark Haverkamp } 4911da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)){ 4927c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 4931da177e4SLinus Torvalds return -EPERM; 4941da177e4SLinus Torvalds } 4951da177e4SLinus Torvalds /* 496f2b1a06aSMark Haverkamp * Allocate and initialize a Fib then setup a SRB command 4971da177e4SLinus Torvalds */ 498bfb35aa8SMark Haverkamp if (!(srbfib = aac_fib_alloc(dev))) { 4995d497cecSMark Haverkamp return -ENOMEM; 5001da177e4SLinus Torvalds } 501bfb35aa8SMark Haverkamp aac_fib_init(srbfib); 50285d22bbfSMahesh Rajashekhara /* raw_srb FIB is not FastResponseCapable */ 50385d22bbfSMahesh Rajashekhara srbfib->hw_fib_va->header.XferState &= ~cpu_to_le32(FastResponseCapable); 5041da177e4SLinus Torvalds 5051da177e4SLinus Torvalds srbcmd = (struct aac_srb*) fib_data(srbfib); 5061da177e4SLinus Torvalds 5077c00ffa3SMark Haverkamp memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */ 5081da177e4SLinus Torvalds if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){ 5097c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); 5101da177e4SLinus Torvalds rcode = -EFAULT; 5111da177e4SLinus Torvalds goto cleanup; 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 514b4789b8eSMahesh Rajashekhara if ((fibsize < (sizeof(struct user_aac_srb) - sizeof(struct user_sgentry))) || 515b4789b8eSMahesh Rajashekhara (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))) { 5161da177e4SLinus Torvalds rcode = -EINVAL; 5171da177e4SLinus Torvalds goto cleanup; 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds 5204645df10SDave Jones user_srbcmd = kmalloc(fibsize, GFP_KERNEL); 5217c00ffa3SMark Haverkamp if (!user_srbcmd) { 5227c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not make a copy of the srb\n")); 5237c00ffa3SMark Haverkamp rcode = -ENOMEM; 5247c00ffa3SMark Haverkamp goto cleanup; 5257c00ffa3SMark Haverkamp } 52656b58712SMark Haverkamp if(copy_from_user(user_srbcmd, user_srb,fibsize)){ 5277c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n")); 5281da177e4SLinus Torvalds rcode = -EFAULT; 5291da177e4SLinus Torvalds goto cleanup; 5301da177e4SLinus Torvalds } 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds user_reply = arg+fibsize; 5331da177e4SLinus Torvalds 53456b58712SMark Haverkamp flags = user_srbcmd->flags; /* from user in cpu order */ 5351da177e4SLinus Torvalds // Fix up srb for endian and force some values 5361da177e4SLinus Torvalds 53756b58712SMark Haverkamp srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this 53856b58712SMark Haverkamp srbcmd->channel = cpu_to_le32(user_srbcmd->channel); 53956b58712SMark Haverkamp srbcmd->id = cpu_to_le32(user_srbcmd->id); 54056b58712SMark Haverkamp srbcmd->lun = cpu_to_le32(user_srbcmd->lun); 54156b58712SMark Haverkamp srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); 5425d497cecSMark Haverkamp srbcmd->flags = cpu_to_le32(flags); 5435d497cecSMark Haverkamp srbcmd->retry_limit = 0; // Obsolete parameter 54456b58712SMark Haverkamp srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); 5455d497cecSMark Haverkamp memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); 54656b58712SMark Haverkamp 54756b58712SMark Haverkamp switch (flags & (SRB_DataIn | SRB_DataOut)) { 5481da177e4SLinus Torvalds case SRB_DataOut: 5491da177e4SLinus Torvalds data_dir = DMA_TO_DEVICE; 5501da177e4SLinus Torvalds break; 5511da177e4SLinus Torvalds case (SRB_DataIn | SRB_DataOut): 5521da177e4SLinus Torvalds data_dir = DMA_BIDIRECTIONAL; 5531da177e4SLinus Torvalds break; 5541da177e4SLinus Torvalds case SRB_DataIn: 5551da177e4SLinus Torvalds data_dir = DMA_FROM_DEVICE; 5561da177e4SLinus Torvalds break; 5571da177e4SLinus Torvalds default: 5581da177e4SLinus Torvalds data_dir = DMA_NONE; 5591da177e4SLinus Torvalds } 5606391a113STobias Klauser if (user_srbcmd->sg.count > ARRAY_SIZE(sg_list)) { 5617c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: too many sg entries %d\n", 5627c00ffa3SMark Haverkamp le32_to_cpu(srbcmd->sg.count))); 5637c00ffa3SMark Haverkamp rcode = -EINVAL; 5647c00ffa3SMark Haverkamp goto cleanup; 5657c00ffa3SMark Haverkamp } 566f2b1a06aSMark Haverkamp actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + 567f2b1a06aSMark Haverkamp ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry)); 568f2b1a06aSMark Haverkamp actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) * 569f2b1a06aSMark Haverkamp (sizeof(struct sgentry64) - sizeof(struct sgentry)); 570f2b1a06aSMark Haverkamp /* User made a mistake - should not continue */ 571f2b1a06aSMark Haverkamp if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) { 572f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Bad Size specified in " 573f2b1a06aSMark Haverkamp "Raw SRB command calculated fibsize=%lu;%lu " 574f2b1a06aSMark Haverkamp "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu " 575f2b1a06aSMark Haverkamp "issued fibsize=%d\n", 576f2b1a06aSMark Haverkamp actual_fibsize, actual_fibsize64, user_srbcmd->sg.count, 577f2b1a06aSMark Haverkamp sizeof(struct aac_srb), sizeof(struct sgentry), 578f2b1a06aSMark Haverkamp sizeof(struct sgentry64), fibsize)); 579f2b1a06aSMark Haverkamp rcode = -EINVAL; 580f2b1a06aSMark Haverkamp goto cleanup; 581f2b1a06aSMark Haverkamp } 582f2b1a06aSMark Haverkamp if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) { 583f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n")); 584f2b1a06aSMark Haverkamp rcode = -EINVAL; 585f2b1a06aSMark Haverkamp goto cleanup; 586f2b1a06aSMark Haverkamp } 587f2b1a06aSMark Haverkamp byte_count = 0; 588f2b1a06aSMark Haverkamp if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) { 58956b58712SMark Haverkamp struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg; 59084e29308SMark Haverkamp struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds /* 5931da177e4SLinus Torvalds * This should also catch if user used the 32 bit sgmap 5941da177e4SLinus Torvalds */ 595f2b1a06aSMark Haverkamp if (actual_fibsize64 == fibsize) { 596f2b1a06aSMark Haverkamp actual_fibsize = actual_fibsize64; 597f2b1a06aSMark Haverkamp for (i = 0; i < upsg->count; i++) { 598f2b1a06aSMark Haverkamp u64 addr; 599f2b1a06aSMark Haverkamp void* p; 60009050715SMark Salyzyn if (upsg->sg[i].count > 601cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 60209050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 60309050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 604cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 60509050715SMark Salyzyn rcode = -EINVAL; 60609050715SMark Salyzyn goto cleanup; 60709050715SMark Salyzyn } 608f2b1a06aSMark Haverkamp /* Does this really need to be GFP_DMA? */ 609f2b1a06aSMark Haverkamp p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA); 6106dcd4a7fSSalyzyn, Mark if(!p) { 611f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 612f2b1a06aSMark Haverkamp upsg->sg[i].count,i,upsg->count)); 613f2b1a06aSMark Haverkamp rcode = -ENOMEM; 6141da177e4SLinus Torvalds goto cleanup; 6151da177e4SLinus Torvalds } 616f2b1a06aSMark Haverkamp addr = (u64)upsg->sg[i].addr[0]; 617f2b1a06aSMark Haverkamp addr += ((u64)upsg->sg[i].addr[1]) << 32; 618142956afSAl Viro sg_user[i] = (void __user *)(uintptr_t)addr; 619f2b1a06aSMark Haverkamp sg_list[i] = p; // save so we can clean up later 620f2b1a06aSMark Haverkamp sg_indx = i; 621f2b1a06aSMark Haverkamp 622f2b1a06aSMark Haverkamp if (flags & SRB_DataOut) { 623f2b1a06aSMark Haverkamp if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ 624f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 625f2b1a06aSMark Haverkamp rcode = -EFAULT; 626f2b1a06aSMark Haverkamp goto cleanup; 627f2b1a06aSMark Haverkamp } 628f2b1a06aSMark Haverkamp } 629f2b1a06aSMark Haverkamp addr = pci_map_single(dev->pdev, p, upsg->sg[i].count, data_dir); 630f2b1a06aSMark Haverkamp 631f2b1a06aSMark Haverkamp psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 632f2b1a06aSMark Haverkamp psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 633f2b1a06aSMark Haverkamp byte_count += upsg->sg[i].count; 634f2b1a06aSMark Haverkamp psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); 635f2b1a06aSMark Haverkamp } 636f2b1a06aSMark Haverkamp } else { 637f2b1a06aSMark Haverkamp struct user_sgmap* usg; 6387c00ffa3SMark Haverkamp usg = kmalloc(actual_fibsize - sizeof(struct aac_srb) 6397c00ffa3SMark Haverkamp + sizeof(struct sgmap), GFP_KERNEL); 6407c00ffa3SMark Haverkamp if (!usg) { 6417c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); 6427c00ffa3SMark Haverkamp rcode = -ENOMEM; 6437c00ffa3SMark Haverkamp goto cleanup; 6447c00ffa3SMark Haverkamp } 6457c00ffa3SMark Haverkamp memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb) 6467c00ffa3SMark Haverkamp + sizeof(struct sgmap)); 647f2b1a06aSMark Haverkamp actual_fibsize = actual_fibsize64; 6481da177e4SLinus Torvalds 6497c00ffa3SMark Haverkamp for (i = 0; i < usg->count; i++) { 65056b58712SMark Haverkamp u64 addr; 6511da177e4SLinus Torvalds void* p; 65209050715SMark Salyzyn if (usg->sg[i].count > 653cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 65409050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 65509050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 656cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 6577dd72f51SJesper Juhl kfree(usg); 65809050715SMark Salyzyn rcode = -EINVAL; 65909050715SMark Salyzyn goto cleanup; 66009050715SMark Salyzyn } 6617c00ffa3SMark Haverkamp /* Does this really need to be GFP_DMA? */ 6627c00ffa3SMark Haverkamp p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); 6636dcd4a7fSSalyzyn, Mark if(!p) { 6647c00ffa3SMark Haverkamp dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 6657c00ffa3SMark Haverkamp usg->sg[i].count,i,usg->count)); 6668a52da63SJulia Lawall kfree(usg); 6671da177e4SLinus Torvalds rcode = -ENOMEM; 6681da177e4SLinus Torvalds goto cleanup; 6691da177e4SLinus Torvalds } 670142956afSAl Viro sg_user[i] = (void __user *)(uintptr_t)usg->sg[i].addr; 6711da177e4SLinus Torvalds sg_list[i] = p; // save so we can clean up later 6721da177e4SLinus Torvalds sg_indx = i; 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds if (flags & SRB_DataOut) { 67556b58712SMark Haverkamp if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ 6767c00ffa3SMark Haverkamp kfree (usg); 6777c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 6781da177e4SLinus Torvalds rcode = -EFAULT; 6791da177e4SLinus Torvalds goto cleanup; 6801da177e4SLinus Torvalds } 6811da177e4SLinus Torvalds } 6827c00ffa3SMark Haverkamp addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); 6831da177e4SLinus Torvalds 68456b58712SMark Haverkamp psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 68556b58712SMark Haverkamp psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 6867c00ffa3SMark Haverkamp byte_count += usg->sg[i].count; 687f2b1a06aSMark Haverkamp psg->sg[i].count = cpu_to_le32(usg->sg[i].count); 6881da177e4SLinus Torvalds } 6897c00ffa3SMark Haverkamp kfree (usg); 690f2b1a06aSMark Haverkamp } 6911da177e4SLinus Torvalds srbcmd->count = cpu_to_le32(byte_count); 6922f5d1f79SMahesh Rajashekhara if (user_srbcmd->sg.count) 6937c00ffa3SMark Haverkamp psg->count = cpu_to_le32(sg_indx+1); 6942f5d1f79SMahesh Rajashekhara else 6952f5d1f79SMahesh Rajashekhara psg->count = 0; 696bfb35aa8SMark Haverkamp status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); 6971da177e4SLinus Torvalds } else { 69856b58712SMark Haverkamp struct user_sgmap* upsg = &user_srbcmd->sg; 6991da177e4SLinus Torvalds struct sgmap* psg = &srbcmd->sg; 7001da177e4SLinus Torvalds 701f2b1a06aSMark Haverkamp if (actual_fibsize64 == fibsize) { 702f2b1a06aSMark Haverkamp struct user_sgmap64* usg = (struct user_sgmap64 *)upsg; 703f2b1a06aSMark Haverkamp for (i = 0; i < upsg->count; i++) { 704142956afSAl Viro uintptr_t addr; 705f2b1a06aSMark Haverkamp void* p; 70609050715SMark Salyzyn if (usg->sg[i].count > 707cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 70809050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 70909050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 710cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 71109050715SMark Salyzyn rcode = -EINVAL; 71209050715SMark Salyzyn goto cleanup; 71309050715SMark Salyzyn } 714f2b1a06aSMark Haverkamp /* Does this really need to be GFP_DMA? */ 715f2b1a06aSMark Haverkamp p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); 7166dcd4a7fSSalyzyn, Mark if(!p) { 717f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 718f2b1a06aSMark Haverkamp usg->sg[i].count,i,usg->count)); 719f2b1a06aSMark Haverkamp rcode = -ENOMEM; 7201da177e4SLinus Torvalds goto cleanup; 7211da177e4SLinus Torvalds } 722f2b1a06aSMark Haverkamp addr = (u64)usg->sg[i].addr[0]; 723f2b1a06aSMark Haverkamp addr += ((u64)usg->sg[i].addr[1]) << 32; 724142956afSAl Viro sg_user[i] = (void __user *)addr; 725f2b1a06aSMark Haverkamp sg_list[i] = p; // save so we can clean up later 726f2b1a06aSMark Haverkamp sg_indx = i; 727f2b1a06aSMark Haverkamp 728f2b1a06aSMark Haverkamp if (flags & SRB_DataOut) { 729f2b1a06aSMark Haverkamp if(copy_from_user(p,sg_user[i],usg->sg[i].count)){ 730f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 731f2b1a06aSMark Haverkamp rcode = -EFAULT; 7321da177e4SLinus Torvalds goto cleanup; 7331da177e4SLinus Torvalds } 734f2b1a06aSMark Haverkamp } 735f2b1a06aSMark Haverkamp addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); 736f2b1a06aSMark Haverkamp 737f2b1a06aSMark Haverkamp psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff); 738f2b1a06aSMark Haverkamp byte_count += usg->sg[i].count; 739f2b1a06aSMark Haverkamp psg->sg[i].count = cpu_to_le32(usg->sg[i].count); 740f2b1a06aSMark Haverkamp } 741f2b1a06aSMark Haverkamp } else { 74256b58712SMark Haverkamp for (i = 0; i < upsg->count; i++) { 7431da177e4SLinus Torvalds dma_addr_t addr; 7441da177e4SLinus Torvalds void* p; 74509050715SMark Salyzyn if (upsg->sg[i].count > 746cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 74709050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 74809050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 749cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 75009050715SMark Salyzyn rcode = -EINVAL; 75109050715SMark Salyzyn goto cleanup; 75209050715SMark Salyzyn } 75356b58712SMark Haverkamp p = kmalloc(upsg->sg[i].count, GFP_KERNEL); 7546dcd4a7fSSalyzyn, Mark if (!p) { 7557c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 7567c00ffa3SMark Haverkamp upsg->sg[i].count, i, upsg->count)); 7571da177e4SLinus Torvalds rcode = -ENOMEM; 7581da177e4SLinus Torvalds goto cleanup; 7591da177e4SLinus Torvalds } 760142956afSAl Viro sg_user[i] = (void __user *)(uintptr_t)upsg->sg[i].addr; 7611da177e4SLinus Torvalds sg_list[i] = p; // save so we can clean up later 7621da177e4SLinus Torvalds sg_indx = i; 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds if (flags & SRB_DataOut) { 76556b58712SMark Haverkamp if(copy_from_user(p, sg_user[i], 76656b58712SMark Haverkamp upsg->sg[i].count)) { 7677c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 7681da177e4SLinus Torvalds rcode = -EFAULT; 7691da177e4SLinus Torvalds goto cleanup; 7701da177e4SLinus Torvalds } 7711da177e4SLinus Torvalds } 77256b58712SMark Haverkamp addr = pci_map_single(dev->pdev, p, 77356b58712SMark Haverkamp upsg->sg[i].count, data_dir); 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds psg->sg[i].addr = cpu_to_le32(addr); 77656b58712SMark Haverkamp byte_count += upsg->sg[i].count; 777f2b1a06aSMark Haverkamp psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); 778f2b1a06aSMark Haverkamp } 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds srbcmd->count = cpu_to_le32(byte_count); 7812f5d1f79SMahesh Rajashekhara if (user_srbcmd->sg.count) 7827c00ffa3SMark Haverkamp psg->count = cpu_to_le32(sg_indx+1); 7832f5d1f79SMahesh Rajashekhara else 7842f5d1f79SMahesh Rajashekhara psg->count = 0; 785bfb35aa8SMark Haverkamp status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL); 7861da177e4SLinus Torvalds } 787cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (status == -ERESTARTSYS) { 788cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech rcode = -ERESTARTSYS; 789c8f7b073SMark Haverkamp goto cleanup; 790c8f7b073SMark Haverkamp } 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds if (status != 0){ 7937c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); 7945d497cecSMark Haverkamp rcode = -ENXIO; 7951da177e4SLinus Torvalds goto cleanup; 7961da177e4SLinus Torvalds } 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds if (flags & SRB_DataIn) { 7991da177e4SLinus Torvalds for(i = 0 ; i <= sg_indx; i++){ 800f2b1a06aSMark Haverkamp byte_count = le32_to_cpu( 801f2b1a06aSMark Haverkamp (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) 8027c00ffa3SMark Haverkamp ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count 8037c00ffa3SMark Haverkamp : srbcmd->sg.sg[i].count); 8047c00ffa3SMark Haverkamp if(copy_to_user(sg_user[i], sg_list[i], byte_count)){ 8057c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); 8061da177e4SLinus Torvalds rcode = -EFAULT; 8071da177e4SLinus Torvalds goto cleanup; 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds } 8101da177e4SLinus Torvalds } 8111da177e4SLinus Torvalds } 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds reply = (struct aac_srb_reply *) fib_data(srbfib); 8141da177e4SLinus Torvalds if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){ 8157c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n")); 8161da177e4SLinus Torvalds rcode = -EFAULT; 8171da177e4SLinus Torvalds goto cleanup; 8181da177e4SLinus Torvalds } 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds cleanup: 82156b58712SMark Haverkamp kfree(user_srbcmd); 8221da177e4SLinus Torvalds for(i=0; i <= sg_indx; i++){ 8231da177e4SLinus Torvalds kfree(sg_list[i]); 8241da177e4SLinus Torvalds } 825cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (rcode != -ERESTARTSYS) { 826bfb35aa8SMark Haverkamp aac_fib_complete(srbfib); 827bfb35aa8SMark Haverkamp aac_fib_free(srbfib); 828c8f7b073SMark Haverkamp } 8291da177e4SLinus Torvalds 8301da177e4SLinus Torvalds return rcode; 8311da177e4SLinus Torvalds } 8321da177e4SLinus Torvalds 8331da177e4SLinus Torvalds struct aac_pci_info { 8341da177e4SLinus Torvalds u32 bus; 8351da177e4SLinus Torvalds u32 slot; 8361da177e4SLinus Torvalds }; 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds 8394833869eSAdrian Bunk static int aac_get_pci_info(struct aac_dev* dev, void __user *arg) 8401da177e4SLinus Torvalds { 8411da177e4SLinus Torvalds struct aac_pci_info pci_info; 8421da177e4SLinus Torvalds 8431da177e4SLinus Torvalds pci_info.bus = dev->pdev->bus->number; 8441da177e4SLinus Torvalds pci_info.slot = PCI_SLOT(dev->pdev->devfn); 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { 8477c00ffa3SMark Haverkamp dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); 8481da177e4SLinus Torvalds return -EFAULT; 8491da177e4SLinus Torvalds } 8501da177e4SLinus Torvalds return 0; 8511da177e4SLinus Torvalds } 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds 8541da177e4SLinus Torvalds int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg) 8551da177e4SLinus Torvalds { 8561da177e4SLinus Torvalds int status; 8571da177e4SLinus Torvalds 858222a9fb3SRaghava Aditya Renukunta mutex_lock(&dev->ioctl_mutex); 859222a9fb3SRaghava Aditya Renukunta 860fbd18598SRaghava Aditya Renukunta if (dev->adapter_shutdown) { 861fbd18598SRaghava Aditya Renukunta status = -EACCES; 862fbd18598SRaghava Aditya Renukunta goto cleanup; 863fbd18598SRaghava Aditya Renukunta } 864fbd18598SRaghava Aditya Renukunta 8651da177e4SLinus Torvalds /* 8661da177e4SLinus Torvalds * HBA gets first crack 8671da177e4SLinus Torvalds */ 8681da177e4SLinus Torvalds 8691da177e4SLinus Torvalds status = aac_dev_ioctl(dev, cmd, arg); 8701da177e4SLinus Torvalds if (status != -ENOTTY) 871222a9fb3SRaghava Aditya Renukunta goto cleanup; 8721da177e4SLinus Torvalds 8731da177e4SLinus Torvalds switch (cmd) { 8741da177e4SLinus Torvalds case FSACTL_MINIPORT_REV_CHECK: 8751da177e4SLinus Torvalds status = check_revision(dev, arg); 8761da177e4SLinus Torvalds break; 8777c00ffa3SMark Haverkamp case FSACTL_SEND_LARGE_FIB: 8781da177e4SLinus Torvalds case FSACTL_SENDFIB: 8791da177e4SLinus Torvalds status = ioctl_send_fib(dev, arg); 8801da177e4SLinus Torvalds break; 8811da177e4SLinus Torvalds case FSACTL_OPEN_GET_ADAPTER_FIB: 8821da177e4SLinus Torvalds status = open_getadapter_fib(dev, arg); 8831da177e4SLinus Torvalds break; 8841da177e4SLinus Torvalds case FSACTL_GET_NEXT_ADAPTER_FIB: 8851da177e4SLinus Torvalds status = next_getadapter_fib(dev, arg); 8861da177e4SLinus Torvalds break; 8871da177e4SLinus Torvalds case FSACTL_CLOSE_GET_ADAPTER_FIB: 8881da177e4SLinus Torvalds status = close_getadapter_fib(dev, arg); 8891da177e4SLinus Torvalds break; 8901da177e4SLinus Torvalds case FSACTL_SEND_RAW_SRB: 8911da177e4SLinus Torvalds status = aac_send_raw_srb(dev,arg); 8921da177e4SLinus Torvalds break; 8931da177e4SLinus Torvalds case FSACTL_GET_PCI_INFO: 8941da177e4SLinus Torvalds status = aac_get_pci_info(dev,arg); 8951da177e4SLinus Torvalds break; 8961da177e4SLinus Torvalds default: 8971da177e4SLinus Torvalds status = -ENOTTY; 8981da177e4SLinus Torvalds break; 8991da177e4SLinus Torvalds } 900222a9fb3SRaghava Aditya Renukunta 901222a9fb3SRaghava Aditya Renukunta cleanup: 902222a9fb3SRaghava Aditya Renukunta mutex_unlock(&dev->ioctl_mutex); 903222a9fb3SRaghava Aditya Renukunta 9041da177e4SLinus Torvalds return status; 9051da177e4SLinus Torvalds } 9061da177e4SLinus Torvalds 907