1c82ee6d3SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Adaptec AAC series RAID controller driver 4fa195afeSAlan Cox * (c) Copyright 2001 Red Hat Inc. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * based on the old aacraid driver that is.. 71da177e4SLinus Torvalds * Adaptec aacraid device driver for Linux. 81da177e4SLinus Torvalds * 9e8b12f0fSMahesh Rajashekhara * Copyright (c) 2000-2010 Adaptec, Inc. 10f4babba0SRaghava Aditya Renukunta * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 11f4babba0SRaghava Aditya Renukunta * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * Module Name: 141da177e4SLinus Torvalds * commctrl.c 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * Abstract: Contains all routines for control of the AFA comm layer 171da177e4SLinus Torvalds */ 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #include <linux/kernel.h> 201da177e4SLinus Torvalds #include <linux/init.h> 211da177e4SLinus Torvalds #include <linux/types.h> 221da177e4SLinus Torvalds #include <linux/pci.h> 231da177e4SLinus Torvalds #include <linux/spinlock.h> 241da177e4SLinus Torvalds #include <linux/slab.h> 251da177e4SLinus Torvalds #include <linux/completion.h> 261da177e4SLinus Torvalds #include <linux/dma-mapping.h> 271da177e4SLinus Torvalds #include <linux/blkdev.h> 28c8f7b073SMark Haverkamp #include <linux/delay.h> /* ssleep prototype */ 29dc4adbf4SMark Haverkamp #include <linux/kthread.h> 307c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 3109050715SMark Salyzyn #include <scsi/scsi_host.h> 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds #include "aacraid.h" 341da177e4SLinus Torvalds 35cf93fffaSLee Jones # define AAC_DEBUG_PREAMBLE KERN_INFO 36cf93fffaSLee Jones # define AAC_DEBUG_POSTAMBLE 371da177e4SLinus Torvalds /** 381da177e4SLinus Torvalds * ioctl_send_fib - send a FIB from userspace 391da177e4SLinus Torvalds * @dev: adapter is being processed 401da177e4SLinus Torvalds * @arg: arguments to the ioctl call 411da177e4SLinus Torvalds * 421da177e4SLinus Torvalds * This routine sends a fib to the adapter on behalf of a user level 431da177e4SLinus Torvalds * program. 441da177e4SLinus Torvalds */ 451da177e4SLinus Torvalds static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds struct hw_fib * kfib; 481da177e4SLinus Torvalds struct fib *fibptr; 497c00ffa3SMark Haverkamp struct hw_fib * hw_fib = (struct hw_fib *)0; 507c00ffa3SMark Haverkamp dma_addr_t hw_fib_pa = (dma_addr_t)0LL; 51fa00c437SDave Carroll unsigned int size, osize; 527c00ffa3SMark Haverkamp int retval; 531da177e4SLinus Torvalds 5433bb3b29SMark Haverkamp if (dev->in_reset) { 5533bb3b29SMark Haverkamp return -EBUSY; 5633bb3b29SMark Haverkamp } 57bfb35aa8SMark Haverkamp fibptr = aac_fib_alloc(dev); 587c00ffa3SMark Haverkamp if(fibptr == NULL) { 591da177e4SLinus Torvalds return -ENOMEM; 607c00ffa3SMark Haverkamp } 611da177e4SLinus Torvalds 62a8166a52SMark Haverkamp kfib = fibptr->hw_fib_va; 631da177e4SLinus Torvalds /* 641da177e4SLinus Torvalds * First copy in the header so that we can check the size field. 651da177e4SLinus Torvalds */ 661da177e4SLinus Torvalds if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) { 67bfb35aa8SMark Haverkamp aac_fib_free(fibptr); 681da177e4SLinus Torvalds return -EFAULT; 691da177e4SLinus Torvalds } 701da177e4SLinus Torvalds /* 711da177e4SLinus Torvalds * Since we copy based on the fib header size, make sure that we 721da177e4SLinus Torvalds * will not overrun the buffer when we copy the memory. Return 731da177e4SLinus Torvalds * an error if we would. 741da177e4SLinus Torvalds */ 75fa00c437SDave Carroll osize = size = le16_to_cpu(kfib->header.Size) + 76fa00c437SDave Carroll sizeof(struct aac_fibhdr); 777c00ffa3SMark Haverkamp if (size < le16_to_cpu(kfib->header.SenderSize)) 787c00ffa3SMark Haverkamp size = le16_to_cpu(kfib->header.SenderSize); 797c00ffa3SMark Haverkamp if (size > dev->max_fib_size) { 80e9899113SFUJITA Tomonori dma_addr_t daddr; 81e9899113SFUJITA Tomonori 826e289a90SMark Haverkamp if (size > 2048) { 836e289a90SMark Haverkamp retval = -EINVAL; 846e289a90SMark Haverkamp goto cleanup; 856e289a90SMark Haverkamp } 86e9899113SFUJITA Tomonori 87f481973dSMahesh Rajashekhara kfib = dma_alloc_coherent(&dev->pdev->dev, size, &daddr, 88f481973dSMahesh Rajashekhara GFP_KERNEL); 89e9899113SFUJITA Tomonori if (!kfib) { 90e9899113SFUJITA Tomonori retval = -ENOMEM; 91e9899113SFUJITA Tomonori goto cleanup; 92e9899113SFUJITA Tomonori } 93e9899113SFUJITA Tomonori 947c00ffa3SMark Haverkamp /* Highjack the hw_fib */ 95a8166a52SMark Haverkamp hw_fib = fibptr->hw_fib_va; 967c00ffa3SMark Haverkamp hw_fib_pa = fibptr->hw_fib_pa; 97e9899113SFUJITA Tomonori fibptr->hw_fib_va = kfib; 98e9899113SFUJITA Tomonori fibptr->hw_fib_pa = daddr; 997c00ffa3SMark Haverkamp memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size); 1007c00ffa3SMark Haverkamp memcpy(kfib, hw_fib, dev->max_fib_size); 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 1037c00ffa3SMark Haverkamp if (copy_from_user(kfib, arg, size)) { 1047c00ffa3SMark Haverkamp retval = -EFAULT; 1057c00ffa3SMark Haverkamp goto cleanup; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 108fa00c437SDave Carroll /* Sanity check the second copy */ 109fa00c437SDave Carroll if ((osize != le16_to_cpu(kfib->header.Size) + 110fa00c437SDave Carroll sizeof(struct aac_fibhdr)) 111fa00c437SDave Carroll || (size < le16_to_cpu(kfib->header.SenderSize))) { 112fa00c437SDave Carroll retval = -EINVAL; 113fa00c437SDave Carroll goto cleanup; 114fa00c437SDave Carroll } 115fa00c437SDave Carroll 11656b58712SMark Haverkamp if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) { 1171da177e4SLinus Torvalds aac_adapter_interrupt(dev); 1181da177e4SLinus Torvalds /* 1191da177e4SLinus Torvalds * Since we didn't really send a fib, zero out the state to allow 1201da177e4SLinus Torvalds * cleanup code not to assert. 1211da177e4SLinus Torvalds */ 1221da177e4SLinus Torvalds kfib->header.XferState = 0; 1231da177e4SLinus Torvalds } else { 124bfb35aa8SMark Haverkamp retval = aac_fib_send(le16_to_cpu(kfib->header.Command), fibptr, 1251da177e4SLinus Torvalds le16_to_cpu(kfib->header.Size) , FsaNormal, 1261da177e4SLinus Torvalds 1, 1, NULL, NULL); 1271da177e4SLinus Torvalds if (retval) { 1287c00ffa3SMark Haverkamp goto cleanup; 1291da177e4SLinus Torvalds } 130bfb35aa8SMark Haverkamp if (aac_fib_complete(fibptr) != 0) { 1317c00ffa3SMark Haverkamp retval = -EINVAL; 1327c00ffa3SMark Haverkamp goto cleanup; 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds /* 1361da177e4SLinus Torvalds * Make sure that the size returned by the adapter (which includes 1371da177e4SLinus Torvalds * the header) is less than or equal to the size of a fib, so we 1381da177e4SLinus Torvalds * don't corrupt application data. Then copy that size to the user 1391da177e4SLinus Torvalds * buffer. (Don't try to add the header information again, since it 1401da177e4SLinus Torvalds * was already included by the adapter.) 1411da177e4SLinus Torvalds */ 1421da177e4SLinus Torvalds 1437c00ffa3SMark Haverkamp retval = 0; 1447c00ffa3SMark Haverkamp if (copy_to_user(arg, (void *)kfib, size)) 1457c00ffa3SMark Haverkamp retval = -EFAULT; 1467c00ffa3SMark Haverkamp cleanup: 1477c00ffa3SMark Haverkamp if (hw_fib) { 148f481973dSMahesh Rajashekhara dma_free_coherent(&dev->pdev->dev, size, kfib, 149f481973dSMahesh Rajashekhara fibptr->hw_fib_pa); 1507c00ffa3SMark Haverkamp fibptr->hw_fib_pa = hw_fib_pa; 151a8166a52SMark Haverkamp fibptr->hw_fib_va = hw_fib; 1521da177e4SLinus Torvalds } 153cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (retval != -ERESTARTSYS) 154bfb35aa8SMark Haverkamp aac_fib_free(fibptr); 1557c00ffa3SMark Haverkamp return retval; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds /** 1591da177e4SLinus Torvalds * open_getadapter_fib - Get the next fib 160cf93fffaSLee Jones * @dev: adapter is being processed 161cf93fffaSLee Jones * @arg: arguments to the open call 1621da177e4SLinus Torvalds * 1631da177e4SLinus Torvalds * This routine will get the next Fib, if available, from the AdapterFibContext 1641da177e4SLinus Torvalds * passed in from the user. 1651da177e4SLinus Torvalds */ 1661da177e4SLinus Torvalds static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) 1671da177e4SLinus Torvalds { 1681da177e4SLinus Torvalds struct aac_fib_context * fibctx; 1691da177e4SLinus Torvalds int status; 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); 1721da177e4SLinus Torvalds if (fibctx == NULL) { 1731da177e4SLinus Torvalds status = -ENOMEM; 1741da177e4SLinus Torvalds } else { 1751da177e4SLinus Torvalds unsigned long flags; 1761da177e4SLinus Torvalds struct list_head * entry; 1771da177e4SLinus Torvalds struct aac_fib_context * context; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; 1801da177e4SLinus Torvalds fibctx->size = sizeof(struct aac_fib_context); 1811da177e4SLinus Torvalds /* 1821da177e4SLinus Torvalds * Yes yes, I know this could be an index, but we have a 1831da177e4SLinus Torvalds * better guarantee of uniqueness for the locked loop below. 1841da177e4SLinus Torvalds * Without the aid of a persistent history, this also helps 1851da177e4SLinus Torvalds * reduce the chance that the opaque context would be reused. 1861da177e4SLinus Torvalds */ 1871da177e4SLinus Torvalds fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF); 1881da177e4SLinus Torvalds /* 1891da177e4SLinus Torvalds * Initialize the mutex used to wait for the next AIF. 1901da177e4SLinus Torvalds */ 191dc71ecccSArnd Bergmann init_completion(&fibctx->completion); 1921da177e4SLinus Torvalds fibctx->wait = 0; 1931da177e4SLinus Torvalds /* 1941da177e4SLinus Torvalds * Initialize the fibs and set the count of fibs on 1951da177e4SLinus Torvalds * the list to 0. 1961da177e4SLinus Torvalds */ 1971da177e4SLinus Torvalds fibctx->count = 0; 1981da177e4SLinus Torvalds INIT_LIST_HEAD(&fibctx->fib_list); 1991da177e4SLinus Torvalds fibctx->jiffies = jiffies/HZ; 2001da177e4SLinus Torvalds /* 2011da177e4SLinus Torvalds * Now add this context onto the adapter's 2021da177e4SLinus Torvalds * AdapterFibContext list. 2031da177e4SLinus Torvalds */ 2041da177e4SLinus Torvalds spin_lock_irqsave(&dev->fib_lock, flags); 2051da177e4SLinus Torvalds /* Ensure that we have a unique identifier */ 2061da177e4SLinus Torvalds entry = dev->fib_list.next; 2071da177e4SLinus Torvalds while (entry != &dev->fib_list) { 2081da177e4SLinus Torvalds context = list_entry(entry, struct aac_fib_context, next); 2091da177e4SLinus Torvalds if (context->unique == fibctx->unique) { 2101da177e4SLinus Torvalds /* Not unique (32 bits) */ 2111da177e4SLinus Torvalds fibctx->unique++; 2121da177e4SLinus Torvalds entry = dev->fib_list.next; 2131da177e4SLinus Torvalds } else { 2141da177e4SLinus Torvalds entry = entry->next; 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds list_add_tail(&fibctx->next, &dev->fib_list); 2181da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 2191da177e4SLinus Torvalds if (copy_to_user(arg, &fibctx->unique, 2201da177e4SLinus Torvalds sizeof(fibctx->unique))) { 2211da177e4SLinus Torvalds status = -EFAULT; 2221da177e4SLinus Torvalds } else { 2231da177e4SLinus Torvalds status = 0; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds return status; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds /** 2301da177e4SLinus Torvalds * next_getadapter_fib - get the next fib 2311da177e4SLinus Torvalds * @dev: adapter to use 2321da177e4SLinus Torvalds * @arg: ioctl argument 2331da177e4SLinus Torvalds * 2341da177e4SLinus Torvalds * This routine will get the next Fib, if available, from the AdapterFibContext 2351da177e4SLinus Torvalds * passed in from the user. 2361da177e4SLinus Torvalds */ 2371da177e4SLinus Torvalds static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds struct fib_ioctl f; 2401da177e4SLinus Torvalds struct fib *fib; 2411da177e4SLinus Torvalds struct aac_fib_context *fibctx; 2421da177e4SLinus Torvalds int status; 2431da177e4SLinus Torvalds struct list_head * entry; 2441da177e4SLinus Torvalds unsigned long flags; 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) 2471da177e4SLinus Torvalds return -EFAULT; 2481da177e4SLinus Torvalds /* 2491da177e4SLinus Torvalds * Verify that the HANDLE passed in was a valid AdapterFibContext 2501da177e4SLinus Torvalds * 2511da177e4SLinus Torvalds * Search the list of AdapterFibContext addresses on the adapter 2521da177e4SLinus Torvalds * to be sure this is a valid address 2531da177e4SLinus Torvalds */ 2545234e25cSSalyzyn, Mark spin_lock_irqsave(&dev->fib_lock, flags); 2551da177e4SLinus Torvalds entry = dev->fib_list.next; 2561da177e4SLinus Torvalds fibctx = NULL; 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds while (entry != &dev->fib_list) { 2591da177e4SLinus Torvalds fibctx = list_entry(entry, struct aac_fib_context, next); 2601da177e4SLinus Torvalds /* 2611da177e4SLinus Torvalds * Extract the AdapterFibContext from the Input parameters. 2621da177e4SLinus Torvalds */ 2631da177e4SLinus Torvalds if (fibctx->unique == f.fibctx) { /* We found a winner */ 2641da177e4SLinus Torvalds break; 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds entry = entry->next; 2671da177e4SLinus Torvalds fibctx = NULL; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds if (!fibctx) { 2705234e25cSSalyzyn, Mark spin_unlock_irqrestore(&dev->fib_lock, flags); 2711da177e4SLinus Torvalds dprintk ((KERN_INFO "Fib Context not found\n")); 2721da177e4SLinus Torvalds return -EINVAL; 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || 2761da177e4SLinus Torvalds (fibctx->size != sizeof(struct aac_fib_context))) { 2775234e25cSSalyzyn, Mark spin_unlock_irqrestore(&dev->fib_lock, flags); 2781da177e4SLinus Torvalds dprintk ((KERN_INFO "Fib Context corrupt?\n")); 2791da177e4SLinus Torvalds return -EINVAL; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds status = 0; 2821da177e4SLinus Torvalds /* 2831da177e4SLinus Torvalds * If there are no fibs to send back, then either wait or return 2841da177e4SLinus Torvalds * -EAGAIN 2851da177e4SLinus Torvalds */ 2861da177e4SLinus Torvalds return_fib: 2871da177e4SLinus Torvalds if (!list_empty(&fibctx->fib_list)) { 2881da177e4SLinus Torvalds /* 2891da177e4SLinus Torvalds * Pull the next fib from the fibs 2901da177e4SLinus Torvalds */ 2911da177e4SLinus Torvalds entry = fibctx->fib_list.next; 2921da177e4SLinus Torvalds list_del(entry); 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds fib = list_entry(entry, struct fib, fiblink); 2951da177e4SLinus Torvalds fibctx->count--; 2961da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 297a8166a52SMark Haverkamp if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) { 298a8166a52SMark Haverkamp kfree(fib->hw_fib_va); 2991da177e4SLinus Torvalds kfree(fib); 3001da177e4SLinus Torvalds return -EFAULT; 3011da177e4SLinus Torvalds } 3021da177e4SLinus Torvalds /* 3031da177e4SLinus Torvalds * Free the space occupied by this copy of the fib. 3041da177e4SLinus Torvalds */ 305a8166a52SMark Haverkamp kfree(fib->hw_fib_va); 3061da177e4SLinus Torvalds kfree(fib); 3071da177e4SLinus Torvalds status = 0; 3081da177e4SLinus Torvalds } else { 3091da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 310dc4adbf4SMark Haverkamp /* If someone killed the AIF aacraid thread, restart it */ 311dc4adbf4SMark Haverkamp status = !dev->aif_thread; 3128c867b25SMark Haverkamp if (status && !dev->in_reset && dev->queues && dev->fsa_dev) { 313dc4adbf4SMark Haverkamp /* Be paranoid, be very paranoid! */ 314dc4adbf4SMark Haverkamp kthread_stop(dev->thread); 315dc4adbf4SMark Haverkamp ssleep(1); 316dc4adbf4SMark Haverkamp dev->aif_thread = 0; 317f170168bSKees Cook dev->thread = kthread_run(aac_command_thread, dev, 318f170168bSKees Cook "%s", dev->name); 319dc4adbf4SMark Haverkamp ssleep(1); 320dc4adbf4SMark Haverkamp } 3211da177e4SLinus Torvalds if (f.wait) { 322dc71ecccSArnd Bergmann if (wait_for_completion_interruptible(&fibctx->completion) < 0) { 323cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech status = -ERESTARTSYS; 3241da177e4SLinus Torvalds } else { 3251da177e4SLinus Torvalds /* Lock again and retry */ 3261da177e4SLinus Torvalds spin_lock_irqsave(&dev->fib_lock, flags); 3271da177e4SLinus Torvalds goto return_fib; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds } else { 3301da177e4SLinus Torvalds status = -EAGAIN; 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds } 33312a26d08SMark Haverkamp fibctx->jiffies = jiffies/HZ; 3341da177e4SLinus Torvalds return status; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) 3381da177e4SLinus Torvalds { 3391da177e4SLinus Torvalds struct fib *fib; 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds /* 3421da177e4SLinus Torvalds * First free any FIBs that have not been consumed. 3431da177e4SLinus Torvalds */ 3441da177e4SLinus Torvalds while (!list_empty(&fibctx->fib_list)) { 3451da177e4SLinus Torvalds struct list_head * entry; 3461da177e4SLinus Torvalds /* 3471da177e4SLinus Torvalds * Pull the next fib from the fibs 3481da177e4SLinus Torvalds */ 3491da177e4SLinus Torvalds entry = fibctx->fib_list.next; 3501da177e4SLinus Torvalds list_del(entry); 3511da177e4SLinus Torvalds fib = list_entry(entry, struct fib, fiblink); 3521da177e4SLinus Torvalds fibctx->count--; 3531da177e4SLinus Torvalds /* 3541da177e4SLinus Torvalds * Free the space occupied by this copy of the fib. 3551da177e4SLinus Torvalds */ 356a8166a52SMark Haverkamp kfree(fib->hw_fib_va); 3571da177e4SLinus Torvalds kfree(fib); 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds /* 3601da177e4SLinus Torvalds * Remove the Context from the AdapterFibContext List 3611da177e4SLinus Torvalds */ 3621da177e4SLinus Torvalds list_del(&fibctx->next); 3631da177e4SLinus Torvalds /* 3641da177e4SLinus Torvalds * Invalidate context 3651da177e4SLinus Torvalds */ 3661da177e4SLinus Torvalds fibctx->type = 0; 3671da177e4SLinus Torvalds /* 3681da177e4SLinus Torvalds * Free the space occupied by the Context 3691da177e4SLinus Torvalds */ 3701da177e4SLinus Torvalds kfree(fibctx); 3711da177e4SLinus Torvalds return 0; 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds /** 3751da177e4SLinus Torvalds * close_getadapter_fib - close down user fib context 3761da177e4SLinus Torvalds * @dev: adapter 3771da177e4SLinus Torvalds * @arg: ioctl arguments 3781da177e4SLinus Torvalds * 3791da177e4SLinus Torvalds * This routine will close down the fibctx passed in from the user. 3801da177e4SLinus Torvalds */ 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) 3831da177e4SLinus Torvalds { 3841da177e4SLinus Torvalds struct aac_fib_context *fibctx; 3851da177e4SLinus Torvalds int status; 3861da177e4SLinus Torvalds unsigned long flags; 3871da177e4SLinus Torvalds struct list_head * entry; 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds /* 3901da177e4SLinus Torvalds * Verify that the HANDLE passed in was a valid AdapterFibContext 3911da177e4SLinus Torvalds * 3921da177e4SLinus Torvalds * Search the list of AdapterFibContext addresses on the adapter 3931da177e4SLinus Torvalds * to be sure this is a valid address 3941da177e4SLinus Torvalds */ 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds entry = dev->fib_list.next; 3971da177e4SLinus Torvalds fibctx = NULL; 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds while(entry != &dev->fib_list) { 4001da177e4SLinus Torvalds fibctx = list_entry(entry, struct aac_fib_context, next); 4011da177e4SLinus Torvalds /* 4021da177e4SLinus Torvalds * Extract the fibctx from the input parameters 4031da177e4SLinus Torvalds */ 404142956afSAl Viro if (fibctx->unique == (u32)(uintptr_t)arg) /* We found a winner */ 4051da177e4SLinus Torvalds break; 4061da177e4SLinus Torvalds entry = entry->next; 4071da177e4SLinus Torvalds fibctx = NULL; 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds if (!fibctx) 4111da177e4SLinus Torvalds return 0; /* Already gone */ 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || 4141da177e4SLinus Torvalds (fibctx->size != sizeof(struct aac_fib_context))) 4151da177e4SLinus Torvalds return -EINVAL; 4161da177e4SLinus Torvalds spin_lock_irqsave(&dev->fib_lock, flags); 4171da177e4SLinus Torvalds status = aac_close_fib_context(dev, fibctx); 4181da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 4191da177e4SLinus Torvalds return status; 4201da177e4SLinus Torvalds } 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds /** 4231da177e4SLinus Torvalds * check_revision - close down user fib context 4241da177e4SLinus Torvalds * @dev: adapter 4251da177e4SLinus Torvalds * @arg: ioctl arguments 4261da177e4SLinus Torvalds * 4271da177e4SLinus Torvalds * This routine returns the driver version. 4281da177e4SLinus Torvalds * Under Linux, there have been no version incompatibilities, so this is 4291da177e4SLinus Torvalds * simple! 4301da177e4SLinus Torvalds */ 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds static int check_revision(struct aac_dev *dev, void __user *arg) 4331da177e4SLinus Torvalds { 4341da177e4SLinus Torvalds struct revision response; 435c7f47602SMark Haverkamp char *driver_version = aac_driver_version; 436c7f47602SMark Haverkamp u32 version; 4371da177e4SLinus Torvalds 4389f30a323SMark Haverkamp response.compat = 1; 439c7f47602SMark Haverkamp version = (simple_strtol(driver_version, 440c7f47602SMark Haverkamp &driver_version, 10) << 24) | 0x00000400; 441c7f47602SMark Haverkamp version += simple_strtol(driver_version + 1, &driver_version, 10) << 16; 442c7f47602SMark Haverkamp version += simple_strtol(driver_version + 1, NULL, 10); 443c7f47602SMark Haverkamp response.version = cpu_to_le32(version); 4448ce3eca4SSalyzyn, Mark # ifdef AAC_DRIVER_BUILD 445c7f47602SMark Haverkamp response.build = cpu_to_le32(AAC_DRIVER_BUILD); 446c7f47602SMark Haverkamp # else 447c7f47602SMark Haverkamp response.build = cpu_to_le32(9999); 448c7f47602SMark Haverkamp # endif 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds if (copy_to_user(arg, &response, sizeof(response))) 4511da177e4SLinus Torvalds return -EFAULT; 4521da177e4SLinus Torvalds return 0; 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 4557c00ffa3SMark Haverkamp 4561da177e4SLinus Torvalds /** 4571da177e4SLinus Torvalds * aac_send_raw_scb 458cf93fffaSLee Jones * @dev: adapter is being processed 459cf93fffaSLee Jones * @arg: arguments to the send call 4601da177e4SLinus Torvalds */ 4614833869eSAdrian Bunk static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) 4621da177e4SLinus Torvalds { 4631da177e4SLinus Torvalds struct fib* srbfib; 4641da177e4SLinus Torvalds int status; 46556b58712SMark Haverkamp struct aac_srb *srbcmd = NULL; 466423400e6SRaghava Aditya Renukunta struct aac_hba_cmd_req *hbacmd = NULL; 46756b58712SMark Haverkamp struct user_aac_srb *user_srbcmd = NULL; 46856b58712SMark Haverkamp struct user_aac_srb __user *user_srb = arg; 4691da177e4SLinus Torvalds struct aac_srb_reply __user *user_reply; 470423400e6SRaghava Aditya Renukunta u32 chn; 4711da177e4SLinus Torvalds u32 fibsize = 0; 4721da177e4SLinus Torvalds u32 flags = 0; 4731da177e4SLinus Torvalds s32 rcode = 0; 4741da177e4SLinus Torvalds u32 data_dir; 475423400e6SRaghava Aditya Renukunta void __user *sg_user[HBA_MAX_SG_EMBEDDED]; 476423400e6SRaghava Aditya Renukunta void *sg_list[HBA_MAX_SG_EMBEDDED]; 477423400e6SRaghava Aditya Renukunta u32 sg_count[HBA_MAX_SG_EMBEDDED]; 4781da177e4SLinus Torvalds u32 sg_indx = 0; 4791da177e4SLinus Torvalds u32 byte_count = 0; 480f2b1a06aSMark Haverkamp u32 actual_fibsize64, actual_fibsize = 0; 4811da177e4SLinus Torvalds int i; 482423400e6SRaghava Aditya Renukunta int is_native_device; 483423400e6SRaghava Aditya Renukunta u64 address; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds 48633bb3b29SMark Haverkamp if (dev->in_reset) { 48733bb3b29SMark Haverkamp dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n")); 48833bb3b29SMark Haverkamp return -EBUSY; 48933bb3b29SMark Haverkamp } 4901da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)){ 4917c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 4921da177e4SLinus Torvalds return -EPERM; 4931da177e4SLinus Torvalds } 4941da177e4SLinus Torvalds /* 495f2b1a06aSMark Haverkamp * Allocate and initialize a Fib then setup a SRB command 4961da177e4SLinus Torvalds */ 497bfb35aa8SMark Haverkamp if (!(srbfib = aac_fib_alloc(dev))) { 4985d497cecSMark Haverkamp return -ENOMEM; 4991da177e4SLinus Torvalds } 5001da177e4SLinus Torvalds 5017c00ffa3SMark Haverkamp memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */ 5021da177e4SLinus Torvalds if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){ 5037c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); 5041da177e4SLinus Torvalds rcode = -EFAULT; 5051da177e4SLinus Torvalds goto cleanup; 5061da177e4SLinus Torvalds } 5071da177e4SLinus Torvalds 508b4789b8eSMahesh Rajashekhara if ((fibsize < (sizeof(struct user_aac_srb) - sizeof(struct user_sgentry))) || 509b4789b8eSMahesh Rajashekhara (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))) { 5101da177e4SLinus Torvalds rcode = -EINVAL; 5111da177e4SLinus Torvalds goto cleanup; 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 5148d925b1fSZou Wei user_srbcmd = memdup_user(user_srb, fibsize); 5158d925b1fSZou Wei if (IS_ERR(user_srbcmd)) { 5168d925b1fSZou Wei rcode = PTR_ERR(user_srbcmd); 51725c21d20SDan Carpenter user_srbcmd = NULL; 5181da177e4SLinus Torvalds goto cleanup; 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds 52156b58712SMark Haverkamp flags = user_srbcmd->flags; /* from user in cpu order */ 52256b58712SMark Haverkamp switch (flags & (SRB_DataIn | SRB_DataOut)) { 5231da177e4SLinus Torvalds case SRB_DataOut: 5241da177e4SLinus Torvalds data_dir = DMA_TO_DEVICE; 5251da177e4SLinus Torvalds break; 5261da177e4SLinus Torvalds case (SRB_DataIn | SRB_DataOut): 5271da177e4SLinus Torvalds data_dir = DMA_BIDIRECTIONAL; 5281da177e4SLinus Torvalds break; 5291da177e4SLinus Torvalds case SRB_DataIn: 5301da177e4SLinus Torvalds data_dir = DMA_FROM_DEVICE; 5311da177e4SLinus Torvalds break; 5321da177e4SLinus Torvalds default: 5331da177e4SLinus Torvalds data_dir = DMA_NONE; 5341da177e4SLinus Torvalds } 5356391a113STobias Klauser if (user_srbcmd->sg.count > ARRAY_SIZE(sg_list)) { 5367c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: too many sg entries %d\n", 537423400e6SRaghava Aditya Renukunta user_srbcmd->sg.count)); 538423400e6SRaghava Aditya Renukunta rcode = -EINVAL; 539423400e6SRaghava Aditya Renukunta goto cleanup; 540423400e6SRaghava Aditya Renukunta } 541423400e6SRaghava Aditya Renukunta if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) { 542423400e6SRaghava Aditya Renukunta dprintk((KERN_DEBUG"aacraid:SG with no direction specified\n")); 5437c00ffa3SMark Haverkamp rcode = -EINVAL; 5447c00ffa3SMark Haverkamp goto cleanup; 5457c00ffa3SMark Haverkamp } 546f2b1a06aSMark Haverkamp actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + 547f2b1a06aSMark Haverkamp ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry)); 548f2b1a06aSMark Haverkamp actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) * 549f2b1a06aSMark Haverkamp (sizeof(struct sgentry64) - sizeof(struct sgentry)); 550f2b1a06aSMark Haverkamp /* User made a mistake - should not continue */ 551f2b1a06aSMark Haverkamp if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) { 552f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Bad Size specified in " 553f2b1a06aSMark Haverkamp "Raw SRB command calculated fibsize=%lu;%lu " 554f2b1a06aSMark Haverkamp "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu " 555f2b1a06aSMark Haverkamp "issued fibsize=%d\n", 556f2b1a06aSMark Haverkamp actual_fibsize, actual_fibsize64, user_srbcmd->sg.count, 557f2b1a06aSMark Haverkamp sizeof(struct aac_srb), sizeof(struct sgentry), 558f2b1a06aSMark Haverkamp sizeof(struct sgentry64), fibsize)); 559f2b1a06aSMark Haverkamp rcode = -EINVAL; 560f2b1a06aSMark Haverkamp goto cleanup; 561f2b1a06aSMark Haverkamp } 562423400e6SRaghava Aditya Renukunta 563f3ef4a74SRaghava Aditya Renukunta chn = user_srbcmd->channel; 564423400e6SRaghava Aditya Renukunta if (chn < AAC_MAX_BUSES && user_srbcmd->id < AAC_MAX_TARGETS && 565423400e6SRaghava Aditya Renukunta dev->hba_map[chn][user_srbcmd->id].devtype == 566423400e6SRaghava Aditya Renukunta AAC_DEVTYPE_NATIVE_RAW) { 567423400e6SRaghava Aditya Renukunta is_native_device = 1; 568423400e6SRaghava Aditya Renukunta hbacmd = (struct aac_hba_cmd_req *)srbfib->hw_fib_va; 569423400e6SRaghava Aditya Renukunta memset(hbacmd, 0, 96); /* sizeof(*hbacmd) is not necessary */ 570423400e6SRaghava Aditya Renukunta 571423400e6SRaghava Aditya Renukunta /* iu_type is a parameter of aac_hba_send */ 572423400e6SRaghava Aditya Renukunta switch (data_dir) { 573423400e6SRaghava Aditya Renukunta case DMA_TO_DEVICE: 574423400e6SRaghava Aditya Renukunta hbacmd->byte1 = 2; 575423400e6SRaghava Aditya Renukunta break; 576423400e6SRaghava Aditya Renukunta case DMA_FROM_DEVICE: 577423400e6SRaghava Aditya Renukunta case DMA_BIDIRECTIONAL: 578423400e6SRaghava Aditya Renukunta hbacmd->byte1 = 1; 579423400e6SRaghava Aditya Renukunta break; 580423400e6SRaghava Aditya Renukunta case DMA_NONE: 581423400e6SRaghava Aditya Renukunta default: 582423400e6SRaghava Aditya Renukunta break; 583423400e6SRaghava Aditya Renukunta } 584423400e6SRaghava Aditya Renukunta hbacmd->lun[1] = cpu_to_le32(user_srbcmd->lun); 585423400e6SRaghava Aditya Renukunta hbacmd->it_nexus = dev->hba_map[chn][user_srbcmd->id].rmw_nexus; 586423400e6SRaghava Aditya Renukunta 587423400e6SRaghava Aditya Renukunta /* 588423400e6SRaghava Aditya Renukunta * we fill in reply_qid later in aac_src_deliver_message 589423400e6SRaghava Aditya Renukunta * we fill in iu_type, request_id later in aac_hba_send 590423400e6SRaghava Aditya Renukunta * we fill in emb_data_desc_count, data_length later 591423400e6SRaghava Aditya Renukunta * in sg list build 592423400e6SRaghava Aditya Renukunta */ 593423400e6SRaghava Aditya Renukunta 594423400e6SRaghava Aditya Renukunta memcpy(hbacmd->cdb, user_srbcmd->cdb, sizeof(hbacmd->cdb)); 595423400e6SRaghava Aditya Renukunta 596423400e6SRaghava Aditya Renukunta address = (u64)srbfib->hw_error_pa; 597423400e6SRaghava Aditya Renukunta hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); 598423400e6SRaghava Aditya Renukunta hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff)); 599423400e6SRaghava Aditya Renukunta hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); 600423400e6SRaghava Aditya Renukunta hbacmd->emb_data_desc_count = 601423400e6SRaghava Aditya Renukunta cpu_to_le32(user_srbcmd->sg.count); 602423400e6SRaghava Aditya Renukunta srbfib->hbacmd_size = 64 + 603423400e6SRaghava Aditya Renukunta user_srbcmd->sg.count * sizeof(struct aac_hba_sgl); 604423400e6SRaghava Aditya Renukunta 605423400e6SRaghava Aditya Renukunta } else { 606423400e6SRaghava Aditya Renukunta is_native_device = 0; 607423400e6SRaghava Aditya Renukunta aac_fib_init(srbfib); 608423400e6SRaghava Aditya Renukunta 609423400e6SRaghava Aditya Renukunta /* raw_srb FIB is not FastResponseCapable */ 610423400e6SRaghava Aditya Renukunta srbfib->hw_fib_va->header.XferState &= 611423400e6SRaghava Aditya Renukunta ~cpu_to_le32(FastResponseCapable); 612423400e6SRaghava Aditya Renukunta 613423400e6SRaghava Aditya Renukunta srbcmd = (struct aac_srb *) fib_data(srbfib); 614423400e6SRaghava Aditya Renukunta 615423400e6SRaghava Aditya Renukunta // Fix up srb for endian and force some values 616423400e6SRaghava Aditya Renukunta 617423400e6SRaghava Aditya Renukunta srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this 618423400e6SRaghava Aditya Renukunta srbcmd->channel = cpu_to_le32(user_srbcmd->channel); 619423400e6SRaghava Aditya Renukunta srbcmd->id = cpu_to_le32(user_srbcmd->id); 620423400e6SRaghava Aditya Renukunta srbcmd->lun = cpu_to_le32(user_srbcmd->lun); 621423400e6SRaghava Aditya Renukunta srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); 622423400e6SRaghava Aditya Renukunta srbcmd->flags = cpu_to_le32(flags); 623423400e6SRaghava Aditya Renukunta srbcmd->retry_limit = 0; // Obsolete parameter 624423400e6SRaghava Aditya Renukunta srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); 625423400e6SRaghava Aditya Renukunta memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); 626423400e6SRaghava Aditya Renukunta } 627423400e6SRaghava Aditya Renukunta 628423400e6SRaghava Aditya Renukunta byte_count = 0; 629423400e6SRaghava Aditya Renukunta if (is_native_device) { 630423400e6SRaghava Aditya Renukunta struct user_sgmap *usg32 = &user_srbcmd->sg; 631423400e6SRaghava Aditya Renukunta struct user_sgmap64 *usg64 = 632423400e6SRaghava Aditya Renukunta (struct user_sgmap64 *)&user_srbcmd->sg; 633423400e6SRaghava Aditya Renukunta 634423400e6SRaghava Aditya Renukunta for (i = 0; i < usg32->count; i++) { 635423400e6SRaghava Aditya Renukunta void *p; 636423400e6SRaghava Aditya Renukunta u64 addr; 637423400e6SRaghava Aditya Renukunta 638423400e6SRaghava Aditya Renukunta sg_count[i] = (actual_fibsize64 == fibsize) ? 639423400e6SRaghava Aditya Renukunta usg64->sg[i].count : usg32->sg[i].count; 640423400e6SRaghava Aditya Renukunta if (sg_count[i] > 641423400e6SRaghava Aditya Renukunta (dev->scsi_host_ptr->max_sectors << 9)) { 642423400e6SRaghava Aditya Renukunta pr_err("aacraid: upsg->sg[%d].count=%u>%u\n", 643423400e6SRaghava Aditya Renukunta i, sg_count[i], 644423400e6SRaghava Aditya Renukunta dev->scsi_host_ptr->max_sectors << 9); 645f2b1a06aSMark Haverkamp rcode = -EINVAL; 646f2b1a06aSMark Haverkamp goto cleanup; 647f2b1a06aSMark Haverkamp } 648423400e6SRaghava Aditya Renukunta 649c831a4a0SRaghava Aditya Renukunta p = kmalloc(sg_count[i], GFP_KERNEL); 650423400e6SRaghava Aditya Renukunta if (!p) { 651423400e6SRaghava Aditya Renukunta rcode = -ENOMEM; 652423400e6SRaghava Aditya Renukunta goto cleanup; 653423400e6SRaghava Aditya Renukunta } 654423400e6SRaghava Aditya Renukunta 655423400e6SRaghava Aditya Renukunta if (actual_fibsize64 == fibsize) { 656423400e6SRaghava Aditya Renukunta addr = (u64)usg64->sg[i].addr[0]; 657423400e6SRaghava Aditya Renukunta addr += ((u64)usg64->sg[i].addr[1]) << 32; 658423400e6SRaghava Aditya Renukunta } else { 659423400e6SRaghava Aditya Renukunta addr = (u64)usg32->sg[i].addr; 660423400e6SRaghava Aditya Renukunta } 661423400e6SRaghava Aditya Renukunta 662423400e6SRaghava Aditya Renukunta sg_user[i] = (void __user *)(uintptr_t)addr; 663423400e6SRaghava Aditya Renukunta sg_list[i] = p; // save so we can clean up later 664423400e6SRaghava Aditya Renukunta sg_indx = i; 665423400e6SRaghava Aditya Renukunta 666423400e6SRaghava Aditya Renukunta if (flags & SRB_DataOut) { 667423400e6SRaghava Aditya Renukunta if (copy_from_user(p, sg_user[i], 668423400e6SRaghava Aditya Renukunta sg_count[i])) { 669423400e6SRaghava Aditya Renukunta rcode = -EFAULT; 670423400e6SRaghava Aditya Renukunta goto cleanup; 671423400e6SRaghava Aditya Renukunta } 672423400e6SRaghava Aditya Renukunta } 673e555cd5fSSuraj Upadhyay addr = dma_map_single(&dev->pdev->dev, p, sg_count[i], 674423400e6SRaghava Aditya Renukunta data_dir); 675423400e6SRaghava Aditya Renukunta hbacmd->sge[i].addr_hi = cpu_to_le32((u32)(addr>>32)); 676423400e6SRaghava Aditya Renukunta hbacmd->sge[i].addr_lo = cpu_to_le32( 677423400e6SRaghava Aditya Renukunta (u32)(addr & 0xffffffff)); 678423400e6SRaghava Aditya Renukunta hbacmd->sge[i].len = cpu_to_le32(sg_count[i]); 679423400e6SRaghava Aditya Renukunta hbacmd->sge[i].flags = 0; 680423400e6SRaghava Aditya Renukunta byte_count += sg_count[i]; 681423400e6SRaghava Aditya Renukunta } 682423400e6SRaghava Aditya Renukunta 683423400e6SRaghava Aditya Renukunta if (usg32->count > 0) /* embedded sglist */ 684423400e6SRaghava Aditya Renukunta hbacmd->sge[usg32->count-1].flags = 685423400e6SRaghava Aditya Renukunta cpu_to_le32(0x40000000); 686423400e6SRaghava Aditya Renukunta hbacmd->data_length = cpu_to_le32(byte_count); 687423400e6SRaghava Aditya Renukunta 688423400e6SRaghava Aditya Renukunta status = aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, srbfib, 689423400e6SRaghava Aditya Renukunta NULL, NULL); 690423400e6SRaghava Aditya Renukunta 691423400e6SRaghava Aditya Renukunta } else if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) { 69256b58712SMark Haverkamp struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg; 69384e29308SMark Haverkamp struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds /* 6961da177e4SLinus Torvalds * This should also catch if user used the 32 bit sgmap 6971da177e4SLinus Torvalds */ 698f2b1a06aSMark Haverkamp if (actual_fibsize64 == fibsize) { 699f2b1a06aSMark Haverkamp actual_fibsize = actual_fibsize64; 700f2b1a06aSMark Haverkamp for (i = 0; i < upsg->count; i++) { 701f2b1a06aSMark Haverkamp u64 addr; 702f2b1a06aSMark Haverkamp void* p; 703423400e6SRaghava Aditya Renukunta 704423400e6SRaghava Aditya Renukunta sg_count[i] = upsg->sg[i].count; 705423400e6SRaghava Aditya Renukunta if (sg_count[i] > 706cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 70709050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 70809050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 709cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 71009050715SMark Salyzyn rcode = -EINVAL; 71109050715SMark Salyzyn goto cleanup; 71209050715SMark Salyzyn } 713c831a4a0SRaghava Aditya Renukunta 714c831a4a0SRaghava Aditya Renukunta p = kmalloc(sg_count[i], GFP_KERNEL); 7156dcd4a7fSSalyzyn, Mark if(!p) { 716f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 717423400e6SRaghava Aditya Renukunta sg_count[i], i, upsg->count)); 718f2b1a06aSMark Haverkamp rcode = -ENOMEM; 7191da177e4SLinus Torvalds goto cleanup; 7201da177e4SLinus Torvalds } 721f2b1a06aSMark Haverkamp addr = (u64)upsg->sg[i].addr[0]; 722f2b1a06aSMark Haverkamp addr += ((u64)upsg->sg[i].addr[1]) << 32; 723142956afSAl Viro sg_user[i] = (void __user *)(uintptr_t)addr; 724f2b1a06aSMark Haverkamp sg_list[i] = p; // save so we can clean up later 725f2b1a06aSMark Haverkamp sg_indx = i; 726f2b1a06aSMark Haverkamp 727f2b1a06aSMark Haverkamp if (flags & SRB_DataOut) { 728423400e6SRaghava Aditya Renukunta if (copy_from_user(p, sg_user[i], 729423400e6SRaghava Aditya Renukunta sg_count[i])){ 730f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 731f2b1a06aSMark Haverkamp rcode = -EFAULT; 732f2b1a06aSMark Haverkamp goto cleanup; 733f2b1a06aSMark Haverkamp } 734f2b1a06aSMark Haverkamp } 735e555cd5fSSuraj Upadhyay addr = dma_map_single(&dev->pdev->dev, p, 736423400e6SRaghava Aditya Renukunta sg_count[i], data_dir); 737f2b1a06aSMark Haverkamp 738f2b1a06aSMark Haverkamp psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 739f2b1a06aSMark Haverkamp psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 740423400e6SRaghava Aditya Renukunta byte_count += sg_count[i]; 741423400e6SRaghava Aditya Renukunta psg->sg[i].count = cpu_to_le32(sg_count[i]); 742f2b1a06aSMark Haverkamp } 743f2b1a06aSMark Haverkamp } else { 744f2b1a06aSMark Haverkamp struct user_sgmap* usg; 74522e9f5a6SMuhammad Falak R Wani usg = kmemdup(upsg, 74622e9f5a6SMuhammad Falak R Wani actual_fibsize - sizeof(struct aac_srb) 7477c00ffa3SMark Haverkamp + sizeof(struct sgmap), GFP_KERNEL); 7487c00ffa3SMark Haverkamp if (!usg) { 7497c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); 7507c00ffa3SMark Haverkamp rcode = -ENOMEM; 7517c00ffa3SMark Haverkamp goto cleanup; 7527c00ffa3SMark Haverkamp } 753f2b1a06aSMark Haverkamp actual_fibsize = actual_fibsize64; 7541da177e4SLinus Torvalds 7557c00ffa3SMark Haverkamp for (i = 0; i < usg->count; i++) { 75656b58712SMark Haverkamp u64 addr; 7571da177e4SLinus Torvalds void* p; 758423400e6SRaghava Aditya Renukunta 759423400e6SRaghava Aditya Renukunta sg_count[i] = usg->sg[i].count; 760423400e6SRaghava Aditya Renukunta if (sg_count[i] > 761cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 76209050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 76309050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 764cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 7657dd72f51SJesper Juhl kfree(usg); 76609050715SMark Salyzyn rcode = -EINVAL; 76709050715SMark Salyzyn goto cleanup; 76809050715SMark Salyzyn } 769c831a4a0SRaghava Aditya Renukunta 770c831a4a0SRaghava Aditya Renukunta p = kmalloc(sg_count[i], GFP_KERNEL); 7716dcd4a7fSSalyzyn, Mark if(!p) { 7727c00ffa3SMark Haverkamp dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 773423400e6SRaghava Aditya Renukunta sg_count[i], i, usg->count)); 7748a52da63SJulia Lawall kfree(usg); 7751da177e4SLinus Torvalds rcode = -ENOMEM; 7761da177e4SLinus Torvalds goto cleanup; 7771da177e4SLinus Torvalds } 778142956afSAl Viro sg_user[i] = (void __user *)(uintptr_t)usg->sg[i].addr; 7791da177e4SLinus Torvalds sg_list[i] = p; // save so we can clean up later 7801da177e4SLinus Torvalds sg_indx = i; 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds if (flags & SRB_DataOut) { 783423400e6SRaghava Aditya Renukunta if (copy_from_user(p, sg_user[i], 784423400e6SRaghava Aditya Renukunta sg_count[i])) { 7857c00ffa3SMark Haverkamp kfree (usg); 7867c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 7871da177e4SLinus Torvalds rcode = -EFAULT; 7881da177e4SLinus Torvalds goto cleanup; 7891da177e4SLinus Torvalds } 7901da177e4SLinus Torvalds } 791e555cd5fSSuraj Upadhyay addr = dma_map_single(&dev->pdev->dev, p, 792423400e6SRaghava Aditya Renukunta sg_count[i], data_dir); 7931da177e4SLinus Torvalds 79456b58712SMark Haverkamp psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 79556b58712SMark Haverkamp psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 796423400e6SRaghava Aditya Renukunta byte_count += sg_count[i]; 797423400e6SRaghava Aditya Renukunta psg->sg[i].count = cpu_to_le32(sg_count[i]); 7981da177e4SLinus Torvalds } 7997c00ffa3SMark Haverkamp kfree (usg); 800f2b1a06aSMark Haverkamp } 8011da177e4SLinus Torvalds srbcmd->count = cpu_to_le32(byte_count); 8022f5d1f79SMahesh Rajashekhara if (user_srbcmd->sg.count) 8037c00ffa3SMark Haverkamp psg->count = cpu_to_le32(sg_indx+1); 8042f5d1f79SMahesh Rajashekhara else 8052f5d1f79SMahesh Rajashekhara psg->count = 0; 806bfb35aa8SMark Haverkamp status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); 8071da177e4SLinus Torvalds } else { 80856b58712SMark Haverkamp struct user_sgmap* upsg = &user_srbcmd->sg; 8091da177e4SLinus Torvalds struct sgmap* psg = &srbcmd->sg; 8101da177e4SLinus Torvalds 811f2b1a06aSMark Haverkamp if (actual_fibsize64 == fibsize) { 812f2b1a06aSMark Haverkamp struct user_sgmap64* usg = (struct user_sgmap64 *)upsg; 813f2b1a06aSMark Haverkamp for (i = 0; i < upsg->count; i++) { 814142956afSAl Viro uintptr_t addr; 815f2b1a06aSMark Haverkamp void* p; 816423400e6SRaghava Aditya Renukunta 817423400e6SRaghava Aditya Renukunta sg_count[i] = usg->sg[i].count; 818423400e6SRaghava Aditya Renukunta if (sg_count[i] > 819cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 82009050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 82109050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 822cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 82309050715SMark Salyzyn rcode = -EINVAL; 82409050715SMark Salyzyn goto cleanup; 82509050715SMark Salyzyn } 826a0c1c185SChristoph Hellwig p = kmalloc(sg_count[i], GFP_KERNEL); 8276dcd4a7fSSalyzyn, Mark if (!p) { 828f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 829423400e6SRaghava Aditya Renukunta sg_count[i], i, usg->count)); 830f2b1a06aSMark Haverkamp rcode = -ENOMEM; 8311da177e4SLinus Torvalds goto cleanup; 8321da177e4SLinus Torvalds } 833f2b1a06aSMark Haverkamp addr = (u64)usg->sg[i].addr[0]; 834f2b1a06aSMark Haverkamp addr += ((u64)usg->sg[i].addr[1]) << 32; 835142956afSAl Viro sg_user[i] = (void __user *)addr; 836f2b1a06aSMark Haverkamp sg_list[i] = p; // save so we can clean up later 837f2b1a06aSMark Haverkamp sg_indx = i; 838f2b1a06aSMark Haverkamp 839f2b1a06aSMark Haverkamp if (flags & SRB_DataOut) { 840423400e6SRaghava Aditya Renukunta if (copy_from_user(p, sg_user[i], 841423400e6SRaghava Aditya Renukunta sg_count[i])){ 842f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 843f2b1a06aSMark Haverkamp rcode = -EFAULT; 8441da177e4SLinus Torvalds goto cleanup; 8451da177e4SLinus Torvalds } 846f2b1a06aSMark Haverkamp } 847e555cd5fSSuraj Upadhyay addr = dma_map_single(&dev->pdev->dev, p, 848e555cd5fSSuraj Upadhyay usg->sg[i].count, 849e555cd5fSSuraj Upadhyay data_dir); 850f2b1a06aSMark Haverkamp 851f2b1a06aSMark Haverkamp psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff); 852f2b1a06aSMark Haverkamp byte_count += usg->sg[i].count; 853423400e6SRaghava Aditya Renukunta psg->sg[i].count = cpu_to_le32(sg_count[i]); 854f2b1a06aSMark Haverkamp } 855f2b1a06aSMark Haverkamp } else { 85656b58712SMark Haverkamp for (i = 0; i < upsg->count; i++) { 8571da177e4SLinus Torvalds dma_addr_t addr; 8581da177e4SLinus Torvalds void* p; 859423400e6SRaghava Aditya Renukunta 860423400e6SRaghava Aditya Renukunta sg_count[i] = upsg->sg[i].count; 861423400e6SRaghava Aditya Renukunta if (sg_count[i] > 862cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 86309050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 86409050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 865cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 86609050715SMark Salyzyn rcode = -EINVAL; 86709050715SMark Salyzyn goto cleanup; 86809050715SMark Salyzyn } 869a0c1c185SChristoph Hellwig p = kmalloc(sg_count[i], GFP_KERNEL); 8706dcd4a7fSSalyzyn, Mark if (!p) { 8717c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 872423400e6SRaghava Aditya Renukunta sg_count[i], i, upsg->count)); 8731da177e4SLinus Torvalds rcode = -ENOMEM; 8741da177e4SLinus Torvalds goto cleanup; 8751da177e4SLinus Torvalds } 876142956afSAl Viro sg_user[i] = (void __user *)(uintptr_t)upsg->sg[i].addr; 8771da177e4SLinus Torvalds sg_list[i] = p; // save so we can clean up later 8781da177e4SLinus Torvalds sg_indx = i; 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds if (flags & SRB_DataOut) { 88156b58712SMark Haverkamp if (copy_from_user(p, sg_user[i], 882423400e6SRaghava Aditya Renukunta sg_count[i])) { 8837c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 8841da177e4SLinus Torvalds rcode = -EFAULT; 8851da177e4SLinus Torvalds goto cleanup; 8861da177e4SLinus Torvalds } 8871da177e4SLinus Torvalds } 888e555cd5fSSuraj Upadhyay addr = dma_map_single(&dev->pdev->dev, p, 889423400e6SRaghava Aditya Renukunta sg_count[i], data_dir); 8901da177e4SLinus Torvalds 8911da177e4SLinus Torvalds psg->sg[i].addr = cpu_to_le32(addr); 892423400e6SRaghava Aditya Renukunta byte_count += sg_count[i]; 893423400e6SRaghava Aditya Renukunta psg->sg[i].count = cpu_to_le32(sg_count[i]); 894f2b1a06aSMark Haverkamp } 8951da177e4SLinus Torvalds } 8961da177e4SLinus Torvalds srbcmd->count = cpu_to_le32(byte_count); 8972f5d1f79SMahesh Rajashekhara if (user_srbcmd->sg.count) 8987c00ffa3SMark Haverkamp psg->count = cpu_to_le32(sg_indx+1); 8992f5d1f79SMahesh Rajashekhara else 9002f5d1f79SMahesh Rajashekhara psg->count = 0; 901bfb35aa8SMark Haverkamp status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL); 9021da177e4SLinus Torvalds } 903423400e6SRaghava Aditya Renukunta 904cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (status == -ERESTARTSYS) { 905cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech rcode = -ERESTARTSYS; 906c8f7b073SMark Haverkamp goto cleanup; 907c8f7b073SMark Haverkamp } 9081da177e4SLinus Torvalds 9091da177e4SLinus Torvalds if (status != 0) { 9107c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); 9115d497cecSMark Haverkamp rcode = -ENXIO; 9121da177e4SLinus Torvalds goto cleanup; 9131da177e4SLinus Torvalds } 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds if (flags & SRB_DataIn) { 9161da177e4SLinus Torvalds for(i = 0 ; i <= sg_indx; i++){ 917423400e6SRaghava Aditya Renukunta if (copy_to_user(sg_user[i], sg_list[i], sg_count[i])) { 9187c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); 9191da177e4SLinus Torvalds rcode = -EFAULT; 9201da177e4SLinus Torvalds goto cleanup; 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds } 9231da177e4SLinus Torvalds } 9241da177e4SLinus Torvalds } 9251da177e4SLinus Torvalds 926423400e6SRaghava Aditya Renukunta user_reply = arg + fibsize; 927423400e6SRaghava Aditya Renukunta if (is_native_device) { 928423400e6SRaghava Aditya Renukunta struct aac_hba_resp *err = 929423400e6SRaghava Aditya Renukunta &((struct aac_native_hba *)srbfib->hw_fib_va)->resp.err; 930423400e6SRaghava Aditya Renukunta struct aac_srb_reply reply; 931423400e6SRaghava Aditya Renukunta 932342ffc26SSeth Forshee memset(&reply, 0, sizeof(reply)); 933423400e6SRaghava Aditya Renukunta reply.status = ST_OK; 934423400e6SRaghava Aditya Renukunta if (srbfib->flags & FIB_CONTEXT_FLAG_FASTRESP) { 935423400e6SRaghava Aditya Renukunta /* fast response */ 936423400e6SRaghava Aditya Renukunta reply.srb_status = SRB_STATUS_SUCCESS; 937423400e6SRaghava Aditya Renukunta reply.scsi_status = 0; 938423400e6SRaghava Aditya Renukunta reply.data_xfer_length = byte_count; 9395cc973f0SColin Ian King reply.sense_data_size = 0; 9405cc973f0SColin Ian King memset(reply.sense_data, 0, AAC_SENSE_BUFFERSIZE); 941423400e6SRaghava Aditya Renukunta } else { 942423400e6SRaghava Aditya Renukunta reply.srb_status = err->service_response; 943423400e6SRaghava Aditya Renukunta reply.scsi_status = err->status; 944423400e6SRaghava Aditya Renukunta reply.data_xfer_length = byte_count - 945423400e6SRaghava Aditya Renukunta le32_to_cpu(err->residual_count); 946423400e6SRaghava Aditya Renukunta reply.sense_data_size = err->sense_response_data_len; 947423400e6SRaghava Aditya Renukunta memcpy(reply.sense_data, err->sense_response_buf, 948423400e6SRaghava Aditya Renukunta AAC_SENSE_BUFFERSIZE); 949423400e6SRaghava Aditya Renukunta } 950423400e6SRaghava Aditya Renukunta if (copy_to_user(user_reply, &reply, 951423400e6SRaghava Aditya Renukunta sizeof(struct aac_srb_reply))) { 952423400e6SRaghava Aditya Renukunta dprintk((KERN_DEBUG"aacraid: Copy to user failed\n")); 9531da177e4SLinus Torvalds rcode = -EFAULT; 9541da177e4SLinus Torvalds goto cleanup; 9551da177e4SLinus Torvalds } 956423400e6SRaghava Aditya Renukunta } else { 957423400e6SRaghava Aditya Renukunta struct aac_srb_reply *reply; 958423400e6SRaghava Aditya Renukunta 959423400e6SRaghava Aditya Renukunta reply = (struct aac_srb_reply *) fib_data(srbfib); 960423400e6SRaghava Aditya Renukunta if (copy_to_user(user_reply, reply, 961423400e6SRaghava Aditya Renukunta sizeof(struct aac_srb_reply))) { 962423400e6SRaghava Aditya Renukunta dprintk((KERN_DEBUG"aacraid: Copy to user failed\n")); 963423400e6SRaghava Aditya Renukunta rcode = -EFAULT; 964423400e6SRaghava Aditya Renukunta goto cleanup; 965423400e6SRaghava Aditya Renukunta } 966423400e6SRaghava Aditya Renukunta } 9671da177e4SLinus Torvalds 9681da177e4SLinus Torvalds cleanup: 96956b58712SMark Haverkamp kfree(user_srbcmd); 970cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (rcode != -ERESTARTSYS) { 971423400e6SRaghava Aditya Renukunta for (i = 0; i <= sg_indx; i++) 972423400e6SRaghava Aditya Renukunta kfree(sg_list[i]); 973bfb35aa8SMark Haverkamp aac_fib_complete(srbfib); 974bfb35aa8SMark Haverkamp aac_fib_free(srbfib); 975c8f7b073SMark Haverkamp } 9761da177e4SLinus Torvalds 9771da177e4SLinus Torvalds return rcode; 9781da177e4SLinus Torvalds } 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds struct aac_pci_info { 9811da177e4SLinus Torvalds u32 bus; 9821da177e4SLinus Torvalds u32 slot; 9831da177e4SLinus Torvalds }; 9841da177e4SLinus Torvalds 9851da177e4SLinus Torvalds 9864833869eSAdrian Bunk static int aac_get_pci_info(struct aac_dev* dev, void __user *arg) 9871da177e4SLinus Torvalds { 9881da177e4SLinus Torvalds struct aac_pci_info pci_info; 9891da177e4SLinus Torvalds 9901da177e4SLinus Torvalds pci_info.bus = dev->pdev->bus->number; 9911da177e4SLinus Torvalds pci_info.slot = PCI_SLOT(dev->pdev->devfn); 9921da177e4SLinus Torvalds 9931da177e4SLinus Torvalds if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { 9947c00ffa3SMark Haverkamp dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); 9951da177e4SLinus Torvalds return -EFAULT; 9961da177e4SLinus Torvalds } 9971da177e4SLinus Torvalds return 0; 9981da177e4SLinus Torvalds } 999c799d519SRaghava Aditya Renukunta 1000c799d519SRaghava Aditya Renukunta static int aac_get_hba_info(struct aac_dev *dev, void __user *arg) 1001c799d519SRaghava Aditya Renukunta { 1002c799d519SRaghava Aditya Renukunta struct aac_hba_info hbainfo; 1003c799d519SRaghava Aditya Renukunta 1004342ffc26SSeth Forshee memset(&hbainfo, 0, sizeof(hbainfo)); 1005c799d519SRaghava Aditya Renukunta hbainfo.adapter_number = (u8) dev->id; 1006c799d519SRaghava Aditya Renukunta hbainfo.system_io_bus_number = dev->pdev->bus->number; 1007c799d519SRaghava Aditya Renukunta hbainfo.device_number = (dev->pdev->devfn >> 3); 1008c799d519SRaghava Aditya Renukunta hbainfo.function_number = (dev->pdev->devfn & 0x0007); 1009c799d519SRaghava Aditya Renukunta 1010c799d519SRaghava Aditya Renukunta hbainfo.vendor_id = dev->pdev->vendor; 1011c799d519SRaghava Aditya Renukunta hbainfo.device_id = dev->pdev->device; 1012c799d519SRaghava Aditya Renukunta hbainfo.sub_vendor_id = dev->pdev->subsystem_vendor; 1013c799d519SRaghava Aditya Renukunta hbainfo.sub_system_id = dev->pdev->subsystem_device; 1014c799d519SRaghava Aditya Renukunta 1015c799d519SRaghava Aditya Renukunta if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { 1016c799d519SRaghava Aditya Renukunta dprintk((KERN_DEBUG "aacraid: Could not copy hba info\n")); 1017c799d519SRaghava Aditya Renukunta return -EFAULT; 1018c799d519SRaghava Aditya Renukunta } 1019c799d519SRaghava Aditya Renukunta 1020c799d519SRaghava Aditya Renukunta return 0; 1021c799d519SRaghava Aditya Renukunta } 1022c799d519SRaghava Aditya Renukunta 102309867a0eSRaghava Aditya Renukunta struct aac_reset_iop { 102409867a0eSRaghava Aditya Renukunta u8 reset_type; 102509867a0eSRaghava Aditya Renukunta }; 10261da177e4SLinus Torvalds 102709867a0eSRaghava Aditya Renukunta static int aac_send_reset_adapter(struct aac_dev *dev, void __user *arg) 102809867a0eSRaghava Aditya Renukunta { 102909867a0eSRaghava Aditya Renukunta struct aac_reset_iop reset; 103009867a0eSRaghava Aditya Renukunta int retval; 103109867a0eSRaghava Aditya Renukunta 103209867a0eSRaghava Aditya Renukunta if (copy_from_user((void *)&reset, arg, sizeof(struct aac_reset_iop))) 103309867a0eSRaghava Aditya Renukunta return -EFAULT; 103409867a0eSRaghava Aditya Renukunta 1035f3a23277SRaghava Aditya Renukunta dev->adapter_shutdown = 1; 103609867a0eSRaghava Aditya Renukunta 1037f3a23277SRaghava Aditya Renukunta mutex_unlock(&dev->ioctl_mutex); 1038f3a23277SRaghava Aditya Renukunta retval = aac_reset_adapter(dev, 0, reset.reset_type); 1039f3a23277SRaghava Aditya Renukunta mutex_lock(&dev->ioctl_mutex); 1040f3a23277SRaghava Aditya Renukunta 1041f3a23277SRaghava Aditya Renukunta return retval; 104209867a0eSRaghava Aditya Renukunta } 10431da177e4SLinus Torvalds 10446f4e626fSNathan Chancellor int aac_do_ioctl(struct aac_dev *dev, unsigned int cmd, void __user *arg) 10451da177e4SLinus Torvalds { 10461da177e4SLinus Torvalds int status; 10471da177e4SLinus Torvalds 1048222a9fb3SRaghava Aditya Renukunta mutex_lock(&dev->ioctl_mutex); 1049222a9fb3SRaghava Aditya Renukunta 1050fbd18598SRaghava Aditya Renukunta if (dev->adapter_shutdown) { 1051fbd18598SRaghava Aditya Renukunta status = -EACCES; 1052fbd18598SRaghava Aditya Renukunta goto cleanup; 1053fbd18598SRaghava Aditya Renukunta } 1054fbd18598SRaghava Aditya Renukunta 10551da177e4SLinus Torvalds /* 10561da177e4SLinus Torvalds * HBA gets first crack 10571da177e4SLinus Torvalds */ 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds status = aac_dev_ioctl(dev, cmd, arg); 10601da177e4SLinus Torvalds if (status != -ENOTTY) 1061222a9fb3SRaghava Aditya Renukunta goto cleanup; 10621da177e4SLinus Torvalds 10631da177e4SLinus Torvalds switch (cmd) { 10641da177e4SLinus Torvalds case FSACTL_MINIPORT_REV_CHECK: 10651da177e4SLinus Torvalds status = check_revision(dev, arg); 10661da177e4SLinus Torvalds break; 10677c00ffa3SMark Haverkamp case FSACTL_SEND_LARGE_FIB: 10681da177e4SLinus Torvalds case FSACTL_SENDFIB: 10691da177e4SLinus Torvalds status = ioctl_send_fib(dev, arg); 10701da177e4SLinus Torvalds break; 10711da177e4SLinus Torvalds case FSACTL_OPEN_GET_ADAPTER_FIB: 10721da177e4SLinus Torvalds status = open_getadapter_fib(dev, arg); 10731da177e4SLinus Torvalds break; 10741da177e4SLinus Torvalds case FSACTL_GET_NEXT_ADAPTER_FIB: 10751da177e4SLinus Torvalds status = next_getadapter_fib(dev, arg); 10761da177e4SLinus Torvalds break; 10771da177e4SLinus Torvalds case FSACTL_CLOSE_GET_ADAPTER_FIB: 10781da177e4SLinus Torvalds status = close_getadapter_fib(dev, arg); 10791da177e4SLinus Torvalds break; 10801da177e4SLinus Torvalds case FSACTL_SEND_RAW_SRB: 10811da177e4SLinus Torvalds status = aac_send_raw_srb(dev,arg); 10821da177e4SLinus Torvalds break; 10831da177e4SLinus Torvalds case FSACTL_GET_PCI_INFO: 10841da177e4SLinus Torvalds status = aac_get_pci_info(dev,arg); 10851da177e4SLinus Torvalds break; 1086c799d519SRaghava Aditya Renukunta case FSACTL_GET_HBA_INFO: 1087c799d519SRaghava Aditya Renukunta status = aac_get_hba_info(dev, arg); 1088c799d519SRaghava Aditya Renukunta break; 108909867a0eSRaghava Aditya Renukunta case FSACTL_RESET_IOP: 109009867a0eSRaghava Aditya Renukunta status = aac_send_reset_adapter(dev, arg); 109109867a0eSRaghava Aditya Renukunta break; 109209867a0eSRaghava Aditya Renukunta 10931da177e4SLinus Torvalds default: 10941da177e4SLinus Torvalds status = -ENOTTY; 10951da177e4SLinus Torvalds break; 10961da177e4SLinus Torvalds } 1097222a9fb3SRaghava Aditya Renukunta 1098222a9fb3SRaghava Aditya Renukunta cleanup: 1099222a9fb3SRaghava Aditya Renukunta mutex_unlock(&dev->ioctl_mutex); 1100222a9fb3SRaghava Aditya Renukunta 11011da177e4SLinus Torvalds return status; 11021da177e4SLinus Torvalds } 11031da177e4SLinus Torvalds 1104