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. 9f4babba0SRaghava Aditya Renukunta * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 10f4babba0SRaghava Aditya Renukunta * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 131da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 141da177e4SLinus Torvalds * the Free Software Foundation; either version 2, or (at your option) 151da177e4SLinus Torvalds * any later version. 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 181da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 191da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 201da177e4SLinus Torvalds * GNU General Public License for more details. 211da177e4SLinus Torvalds * 221da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 231da177e4SLinus Torvalds * along with this program; see the file COPYING. If not, write to 241da177e4SLinus Torvalds * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 251da177e4SLinus Torvalds * 261da177e4SLinus Torvalds * Module Name: 271da177e4SLinus Torvalds * commctrl.c 281da177e4SLinus Torvalds * 291da177e4SLinus Torvalds * Abstract: Contains all routines for control of the AFA comm layer 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds #include <linux/kernel.h> 341da177e4SLinus Torvalds #include <linux/init.h> 351da177e4SLinus Torvalds #include <linux/types.h> 361da177e4SLinus Torvalds #include <linux/pci.h> 371da177e4SLinus Torvalds #include <linux/spinlock.h> 381da177e4SLinus Torvalds #include <linux/slab.h> 391da177e4SLinus Torvalds #include <linux/completion.h> 401da177e4SLinus Torvalds #include <linux/dma-mapping.h> 411da177e4SLinus Torvalds #include <linux/blkdev.h> 42c8f7b073SMark Haverkamp #include <linux/delay.h> /* ssleep prototype */ 43dc4adbf4SMark Haverkamp #include <linux/kthread.h> 446188e10dSMatthew Wilcox #include <linux/semaphore.h> 457c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 4609050715SMark Salyzyn #include <scsi/scsi_host.h> 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds #include "aacraid.h" 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /** 511da177e4SLinus Torvalds * ioctl_send_fib - send a FIB from userspace 521da177e4SLinus Torvalds * @dev: adapter is being processed 531da177e4SLinus Torvalds * @arg: arguments to the ioctl call 541da177e4SLinus Torvalds * 551da177e4SLinus Torvalds * This routine sends a fib to the adapter on behalf of a user level 561da177e4SLinus Torvalds * program. 571da177e4SLinus Torvalds */ 587c00ffa3SMark Haverkamp # define AAC_DEBUG_PREAMBLE KERN_INFO 597c00ffa3SMark Haverkamp # define AAC_DEBUG_POSTAMBLE 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) 621da177e4SLinus Torvalds { 631da177e4SLinus Torvalds struct hw_fib * kfib; 641da177e4SLinus Torvalds struct fib *fibptr; 657c00ffa3SMark Haverkamp struct hw_fib * hw_fib = (struct hw_fib *)0; 667c00ffa3SMark Haverkamp dma_addr_t hw_fib_pa = (dma_addr_t)0LL; 67fa00c437SDave Carroll unsigned int size, osize; 687c00ffa3SMark Haverkamp int retval; 691da177e4SLinus Torvalds 7033bb3b29SMark Haverkamp if (dev->in_reset) { 7133bb3b29SMark Haverkamp return -EBUSY; 7233bb3b29SMark Haverkamp } 73bfb35aa8SMark Haverkamp fibptr = aac_fib_alloc(dev); 747c00ffa3SMark Haverkamp if(fibptr == NULL) { 751da177e4SLinus Torvalds return -ENOMEM; 767c00ffa3SMark Haverkamp } 771da177e4SLinus Torvalds 78a8166a52SMark Haverkamp kfib = fibptr->hw_fib_va; 791da177e4SLinus Torvalds /* 801da177e4SLinus Torvalds * First copy in the header so that we can check the size field. 811da177e4SLinus Torvalds */ 821da177e4SLinus Torvalds if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) { 83bfb35aa8SMark Haverkamp aac_fib_free(fibptr); 841da177e4SLinus Torvalds return -EFAULT; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds /* 871da177e4SLinus Torvalds * Since we copy based on the fib header size, make sure that we 881da177e4SLinus Torvalds * will not overrun the buffer when we copy the memory. Return 891da177e4SLinus Torvalds * an error if we would. 901da177e4SLinus Torvalds */ 91fa00c437SDave Carroll osize = size = le16_to_cpu(kfib->header.Size) + 92fa00c437SDave Carroll sizeof(struct aac_fibhdr); 937c00ffa3SMark Haverkamp if (size < le16_to_cpu(kfib->header.SenderSize)) 947c00ffa3SMark Haverkamp size = le16_to_cpu(kfib->header.SenderSize); 957c00ffa3SMark Haverkamp if (size > dev->max_fib_size) { 96e9899113SFUJITA Tomonori dma_addr_t daddr; 97e9899113SFUJITA Tomonori 986e289a90SMark Haverkamp if (size > 2048) { 996e289a90SMark Haverkamp retval = -EINVAL; 1006e289a90SMark Haverkamp goto cleanup; 1016e289a90SMark Haverkamp } 102e9899113SFUJITA Tomonori 103f481973dSMahesh Rajashekhara kfib = dma_alloc_coherent(&dev->pdev->dev, size, &daddr, 104f481973dSMahesh Rajashekhara GFP_KERNEL); 105e9899113SFUJITA Tomonori if (!kfib) { 106e9899113SFUJITA Tomonori retval = -ENOMEM; 107e9899113SFUJITA Tomonori goto cleanup; 108e9899113SFUJITA Tomonori } 109e9899113SFUJITA Tomonori 1107c00ffa3SMark Haverkamp /* Highjack the hw_fib */ 111a8166a52SMark Haverkamp hw_fib = fibptr->hw_fib_va; 1127c00ffa3SMark Haverkamp hw_fib_pa = fibptr->hw_fib_pa; 113e9899113SFUJITA Tomonori fibptr->hw_fib_va = kfib; 114e9899113SFUJITA Tomonori fibptr->hw_fib_pa = daddr; 1157c00ffa3SMark Haverkamp memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size); 1167c00ffa3SMark Haverkamp memcpy(kfib, hw_fib, dev->max_fib_size); 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1197c00ffa3SMark Haverkamp if (copy_from_user(kfib, arg, size)) { 1207c00ffa3SMark Haverkamp retval = -EFAULT; 1217c00ffa3SMark Haverkamp goto cleanup; 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 124fa00c437SDave Carroll /* Sanity check the second copy */ 125fa00c437SDave Carroll if ((osize != le16_to_cpu(kfib->header.Size) + 126fa00c437SDave Carroll sizeof(struct aac_fibhdr)) 127fa00c437SDave Carroll || (size < le16_to_cpu(kfib->header.SenderSize))) { 128fa00c437SDave Carroll retval = -EINVAL; 129fa00c437SDave Carroll goto cleanup; 130fa00c437SDave Carroll } 131fa00c437SDave Carroll 13256b58712SMark Haverkamp if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) { 1331da177e4SLinus Torvalds aac_adapter_interrupt(dev); 1341da177e4SLinus Torvalds /* 1351da177e4SLinus Torvalds * Since we didn't really send a fib, zero out the state to allow 1361da177e4SLinus Torvalds * cleanup code not to assert. 1371da177e4SLinus Torvalds */ 1381da177e4SLinus Torvalds kfib->header.XferState = 0; 1391da177e4SLinus Torvalds } else { 140bfb35aa8SMark Haverkamp retval = aac_fib_send(le16_to_cpu(kfib->header.Command), fibptr, 1411da177e4SLinus Torvalds le16_to_cpu(kfib->header.Size) , FsaNormal, 1421da177e4SLinus Torvalds 1, 1, NULL, NULL); 1431da177e4SLinus Torvalds if (retval) { 1447c00ffa3SMark Haverkamp goto cleanup; 1451da177e4SLinus Torvalds } 146bfb35aa8SMark Haverkamp if (aac_fib_complete(fibptr) != 0) { 1477c00ffa3SMark Haverkamp retval = -EINVAL; 1487c00ffa3SMark Haverkamp goto cleanup; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds /* 1521da177e4SLinus Torvalds * Make sure that the size returned by the adapter (which includes 1531da177e4SLinus Torvalds * the header) is less than or equal to the size of a fib, so we 1541da177e4SLinus Torvalds * don't corrupt application data. Then copy that size to the user 1551da177e4SLinus Torvalds * buffer. (Don't try to add the header information again, since it 1561da177e4SLinus Torvalds * was already included by the adapter.) 1571da177e4SLinus Torvalds */ 1581da177e4SLinus Torvalds 1597c00ffa3SMark Haverkamp retval = 0; 1607c00ffa3SMark Haverkamp if (copy_to_user(arg, (void *)kfib, size)) 1617c00ffa3SMark Haverkamp retval = -EFAULT; 1627c00ffa3SMark Haverkamp cleanup: 1637c00ffa3SMark Haverkamp if (hw_fib) { 164f481973dSMahesh Rajashekhara dma_free_coherent(&dev->pdev->dev, size, kfib, 165f481973dSMahesh Rajashekhara fibptr->hw_fib_pa); 1667c00ffa3SMark Haverkamp fibptr->hw_fib_pa = hw_fib_pa; 167a8166a52SMark Haverkamp fibptr->hw_fib_va = hw_fib; 1681da177e4SLinus Torvalds } 169cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (retval != -ERESTARTSYS) 170bfb35aa8SMark Haverkamp aac_fib_free(fibptr); 1717c00ffa3SMark Haverkamp return retval; 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds /** 1751da177e4SLinus Torvalds * open_getadapter_fib - Get the next fib 1761da177e4SLinus Torvalds * 1771da177e4SLinus Torvalds * This routine will get the next Fib, if available, from the AdapterFibContext 1781da177e4SLinus Torvalds * passed in from the user. 1791da177e4SLinus Torvalds */ 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) 1821da177e4SLinus Torvalds { 1831da177e4SLinus Torvalds struct aac_fib_context * fibctx; 1841da177e4SLinus Torvalds int status; 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); 1871da177e4SLinus Torvalds if (fibctx == NULL) { 1881da177e4SLinus Torvalds status = -ENOMEM; 1891da177e4SLinus Torvalds } else { 1901da177e4SLinus Torvalds unsigned long flags; 1911da177e4SLinus Torvalds struct list_head * entry; 1921da177e4SLinus Torvalds struct aac_fib_context * context; 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; 1951da177e4SLinus Torvalds fibctx->size = sizeof(struct aac_fib_context); 1961da177e4SLinus Torvalds /* 1971da177e4SLinus Torvalds * Yes yes, I know this could be an index, but we have a 1981da177e4SLinus Torvalds * better guarantee of uniqueness for the locked loop below. 1991da177e4SLinus Torvalds * Without the aid of a persistent history, this also helps 2001da177e4SLinus Torvalds * reduce the chance that the opaque context would be reused. 2011da177e4SLinus Torvalds */ 2021da177e4SLinus Torvalds fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF); 2031da177e4SLinus Torvalds /* 2041da177e4SLinus Torvalds * Initialize the mutex used to wait for the next AIF. 2051da177e4SLinus Torvalds */ 2066de76cfcSThomas Gleixner sema_init(&fibctx->wait_sem, 0); 2071da177e4SLinus Torvalds fibctx->wait = 0; 2081da177e4SLinus Torvalds /* 2091da177e4SLinus Torvalds * Initialize the fibs and set the count of fibs on 2101da177e4SLinus Torvalds * the list to 0. 2111da177e4SLinus Torvalds */ 2121da177e4SLinus Torvalds fibctx->count = 0; 2131da177e4SLinus Torvalds INIT_LIST_HEAD(&fibctx->fib_list); 2141da177e4SLinus Torvalds fibctx->jiffies = jiffies/HZ; 2151da177e4SLinus Torvalds /* 2161da177e4SLinus Torvalds * Now add this context onto the adapter's 2171da177e4SLinus Torvalds * AdapterFibContext list. 2181da177e4SLinus Torvalds */ 2191da177e4SLinus Torvalds spin_lock_irqsave(&dev->fib_lock, flags); 2201da177e4SLinus Torvalds /* Ensure that we have a unique identifier */ 2211da177e4SLinus Torvalds entry = dev->fib_list.next; 2221da177e4SLinus Torvalds while (entry != &dev->fib_list) { 2231da177e4SLinus Torvalds context = list_entry(entry, struct aac_fib_context, next); 2241da177e4SLinus Torvalds if (context->unique == fibctx->unique) { 2251da177e4SLinus Torvalds /* Not unique (32 bits) */ 2261da177e4SLinus Torvalds fibctx->unique++; 2271da177e4SLinus Torvalds entry = dev->fib_list.next; 2281da177e4SLinus Torvalds } else { 2291da177e4SLinus Torvalds entry = entry->next; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds list_add_tail(&fibctx->next, &dev->fib_list); 2331da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 2341da177e4SLinus Torvalds if (copy_to_user(arg, &fibctx->unique, 2351da177e4SLinus Torvalds sizeof(fibctx->unique))) { 2361da177e4SLinus Torvalds status = -EFAULT; 2371da177e4SLinus Torvalds } else { 2381da177e4SLinus Torvalds status = 0; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds return status; 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds /** 2451da177e4SLinus Torvalds * next_getadapter_fib - get the next fib 2461da177e4SLinus Torvalds * @dev: adapter to use 2471da177e4SLinus Torvalds * @arg: ioctl argument 2481da177e4SLinus Torvalds * 2491da177e4SLinus Torvalds * This routine will get the next Fib, if available, from the AdapterFibContext 2501da177e4SLinus Torvalds * passed in from the user. 2511da177e4SLinus Torvalds */ 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) 2541da177e4SLinus Torvalds { 2551da177e4SLinus Torvalds struct fib_ioctl f; 2561da177e4SLinus Torvalds struct fib *fib; 2571da177e4SLinus Torvalds struct aac_fib_context *fibctx; 2581da177e4SLinus Torvalds int status; 2591da177e4SLinus Torvalds struct list_head * entry; 2601da177e4SLinus Torvalds unsigned long flags; 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) 2631da177e4SLinus Torvalds return -EFAULT; 2641da177e4SLinus Torvalds /* 2651da177e4SLinus Torvalds * Verify that the HANDLE passed in was a valid AdapterFibContext 2661da177e4SLinus Torvalds * 2671da177e4SLinus Torvalds * Search the list of AdapterFibContext addresses on the adapter 2681da177e4SLinus Torvalds * to be sure this is a valid address 2691da177e4SLinus Torvalds */ 2705234e25cSSalyzyn, Mark spin_lock_irqsave(&dev->fib_lock, flags); 2711da177e4SLinus Torvalds entry = dev->fib_list.next; 2721da177e4SLinus Torvalds fibctx = NULL; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds while (entry != &dev->fib_list) { 2751da177e4SLinus Torvalds fibctx = list_entry(entry, struct aac_fib_context, next); 2761da177e4SLinus Torvalds /* 2771da177e4SLinus Torvalds * Extract the AdapterFibContext from the Input parameters. 2781da177e4SLinus Torvalds */ 2791da177e4SLinus Torvalds if (fibctx->unique == f.fibctx) { /* We found a winner */ 2801da177e4SLinus Torvalds break; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds entry = entry->next; 2831da177e4SLinus Torvalds fibctx = NULL; 2841da177e4SLinus Torvalds } 2851da177e4SLinus Torvalds if (!fibctx) { 2865234e25cSSalyzyn, Mark spin_unlock_irqrestore(&dev->fib_lock, flags); 2871da177e4SLinus Torvalds dprintk ((KERN_INFO "Fib Context not found\n")); 2881da177e4SLinus Torvalds return -EINVAL; 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || 2921da177e4SLinus Torvalds (fibctx->size != sizeof(struct aac_fib_context))) { 2935234e25cSSalyzyn, Mark spin_unlock_irqrestore(&dev->fib_lock, flags); 2941da177e4SLinus Torvalds dprintk ((KERN_INFO "Fib Context corrupt?\n")); 2951da177e4SLinus Torvalds return -EINVAL; 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds status = 0; 2981da177e4SLinus Torvalds /* 2991da177e4SLinus Torvalds * If there are no fibs to send back, then either wait or return 3001da177e4SLinus Torvalds * -EAGAIN 3011da177e4SLinus Torvalds */ 3021da177e4SLinus Torvalds return_fib: 3031da177e4SLinus Torvalds if (!list_empty(&fibctx->fib_list)) { 3041da177e4SLinus Torvalds /* 3051da177e4SLinus Torvalds * Pull the next fib from the fibs 3061da177e4SLinus Torvalds */ 3071da177e4SLinus Torvalds entry = fibctx->fib_list.next; 3081da177e4SLinus Torvalds list_del(entry); 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds fib = list_entry(entry, struct fib, fiblink); 3111da177e4SLinus Torvalds fibctx->count--; 3121da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 313a8166a52SMark Haverkamp if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) { 314a8166a52SMark Haverkamp kfree(fib->hw_fib_va); 3151da177e4SLinus Torvalds kfree(fib); 3161da177e4SLinus Torvalds return -EFAULT; 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds /* 3191da177e4SLinus Torvalds * Free the space occupied by this copy of the fib. 3201da177e4SLinus Torvalds */ 321a8166a52SMark Haverkamp kfree(fib->hw_fib_va); 3221da177e4SLinus Torvalds kfree(fib); 3231da177e4SLinus Torvalds status = 0; 3241da177e4SLinus Torvalds } else { 3251da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 326dc4adbf4SMark Haverkamp /* If someone killed the AIF aacraid thread, restart it */ 327dc4adbf4SMark Haverkamp status = !dev->aif_thread; 3288c867b25SMark Haverkamp if (status && !dev->in_reset && dev->queues && dev->fsa_dev) { 329dc4adbf4SMark Haverkamp /* Be paranoid, be very paranoid! */ 330dc4adbf4SMark Haverkamp kthread_stop(dev->thread); 331dc4adbf4SMark Haverkamp ssleep(1); 332dc4adbf4SMark Haverkamp dev->aif_thread = 0; 333f170168bSKees Cook dev->thread = kthread_run(aac_command_thread, dev, 334f170168bSKees Cook "%s", dev->name); 335dc4adbf4SMark Haverkamp ssleep(1); 336dc4adbf4SMark Haverkamp } 3371da177e4SLinus Torvalds if (f.wait) { 3381da177e4SLinus Torvalds if(down_interruptible(&fibctx->wait_sem) < 0) { 339cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech status = -ERESTARTSYS; 3401da177e4SLinus Torvalds } else { 3411da177e4SLinus Torvalds /* Lock again and retry */ 3421da177e4SLinus Torvalds spin_lock_irqsave(&dev->fib_lock, flags); 3431da177e4SLinus Torvalds goto return_fib; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds } else { 3461da177e4SLinus Torvalds status = -EAGAIN; 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds } 34912a26d08SMark Haverkamp fibctx->jiffies = jiffies/HZ; 3501da177e4SLinus Torvalds return status; 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) 3541da177e4SLinus Torvalds { 3551da177e4SLinus Torvalds struct fib *fib; 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds /* 3581da177e4SLinus Torvalds * First free any FIBs that have not been consumed. 3591da177e4SLinus Torvalds */ 3601da177e4SLinus Torvalds while (!list_empty(&fibctx->fib_list)) { 3611da177e4SLinus Torvalds struct list_head * entry; 3621da177e4SLinus Torvalds /* 3631da177e4SLinus Torvalds * Pull the next fib from the fibs 3641da177e4SLinus Torvalds */ 3651da177e4SLinus Torvalds entry = fibctx->fib_list.next; 3661da177e4SLinus Torvalds list_del(entry); 3671da177e4SLinus Torvalds fib = list_entry(entry, struct fib, fiblink); 3681da177e4SLinus Torvalds fibctx->count--; 3691da177e4SLinus Torvalds /* 3701da177e4SLinus Torvalds * Free the space occupied by this copy of the fib. 3711da177e4SLinus Torvalds */ 372a8166a52SMark Haverkamp kfree(fib->hw_fib_va); 3731da177e4SLinus Torvalds kfree(fib); 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds /* 3761da177e4SLinus Torvalds * Remove the Context from the AdapterFibContext List 3771da177e4SLinus Torvalds */ 3781da177e4SLinus Torvalds list_del(&fibctx->next); 3791da177e4SLinus Torvalds /* 3801da177e4SLinus Torvalds * Invalidate context 3811da177e4SLinus Torvalds */ 3821da177e4SLinus Torvalds fibctx->type = 0; 3831da177e4SLinus Torvalds /* 3841da177e4SLinus Torvalds * Free the space occupied by the Context 3851da177e4SLinus Torvalds */ 3861da177e4SLinus Torvalds kfree(fibctx); 3871da177e4SLinus Torvalds return 0; 3881da177e4SLinus Torvalds } 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds /** 3911da177e4SLinus Torvalds * close_getadapter_fib - close down user fib context 3921da177e4SLinus Torvalds * @dev: adapter 3931da177e4SLinus Torvalds * @arg: ioctl arguments 3941da177e4SLinus Torvalds * 3951da177e4SLinus Torvalds * This routine will close down the fibctx passed in from the user. 3961da177e4SLinus Torvalds */ 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) 3991da177e4SLinus Torvalds { 4001da177e4SLinus Torvalds struct aac_fib_context *fibctx; 4011da177e4SLinus Torvalds int status; 4021da177e4SLinus Torvalds unsigned long flags; 4031da177e4SLinus Torvalds struct list_head * entry; 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds /* 4061da177e4SLinus Torvalds * Verify that the HANDLE passed in was a valid AdapterFibContext 4071da177e4SLinus Torvalds * 4081da177e4SLinus Torvalds * Search the list of AdapterFibContext addresses on the adapter 4091da177e4SLinus Torvalds * to be sure this is a valid address 4101da177e4SLinus Torvalds */ 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds entry = dev->fib_list.next; 4131da177e4SLinus Torvalds fibctx = NULL; 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds while(entry != &dev->fib_list) { 4161da177e4SLinus Torvalds fibctx = list_entry(entry, struct aac_fib_context, next); 4171da177e4SLinus Torvalds /* 4181da177e4SLinus Torvalds * Extract the fibctx from the input parameters 4191da177e4SLinus Torvalds */ 420142956afSAl Viro if (fibctx->unique == (u32)(uintptr_t)arg) /* We found a winner */ 4211da177e4SLinus Torvalds break; 4221da177e4SLinus Torvalds entry = entry->next; 4231da177e4SLinus Torvalds fibctx = NULL; 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds if (!fibctx) 4271da177e4SLinus Torvalds return 0; /* Already gone */ 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || 4301da177e4SLinus Torvalds (fibctx->size != sizeof(struct aac_fib_context))) 4311da177e4SLinus Torvalds return -EINVAL; 4321da177e4SLinus Torvalds spin_lock_irqsave(&dev->fib_lock, flags); 4331da177e4SLinus Torvalds status = aac_close_fib_context(dev, fibctx); 4341da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->fib_lock, flags); 4351da177e4SLinus Torvalds return status; 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds /** 4391da177e4SLinus Torvalds * check_revision - close down user fib context 4401da177e4SLinus Torvalds * @dev: adapter 4411da177e4SLinus Torvalds * @arg: ioctl arguments 4421da177e4SLinus Torvalds * 4431da177e4SLinus Torvalds * This routine returns the driver version. 4441da177e4SLinus Torvalds * Under Linux, there have been no version incompatibilities, so this is 4451da177e4SLinus Torvalds * simple! 4461da177e4SLinus Torvalds */ 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds static int check_revision(struct aac_dev *dev, void __user *arg) 4491da177e4SLinus Torvalds { 4501da177e4SLinus Torvalds struct revision response; 451c7f47602SMark Haverkamp char *driver_version = aac_driver_version; 452c7f47602SMark Haverkamp u32 version; 4531da177e4SLinus Torvalds 4549f30a323SMark Haverkamp response.compat = 1; 455c7f47602SMark Haverkamp version = (simple_strtol(driver_version, 456c7f47602SMark Haverkamp &driver_version, 10) << 24) | 0x00000400; 457c7f47602SMark Haverkamp version += simple_strtol(driver_version + 1, &driver_version, 10) << 16; 458c7f47602SMark Haverkamp version += simple_strtol(driver_version + 1, NULL, 10); 459c7f47602SMark Haverkamp response.version = cpu_to_le32(version); 4608ce3eca4SSalyzyn, Mark # ifdef AAC_DRIVER_BUILD 461c7f47602SMark Haverkamp response.build = cpu_to_le32(AAC_DRIVER_BUILD); 462c7f47602SMark Haverkamp # else 463c7f47602SMark Haverkamp response.build = cpu_to_le32(9999); 464c7f47602SMark Haverkamp # endif 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds if (copy_to_user(arg, &response, sizeof(response))) 4671da177e4SLinus Torvalds return -EFAULT; 4681da177e4SLinus Torvalds return 0; 4691da177e4SLinus Torvalds } 4701da177e4SLinus Torvalds 4717c00ffa3SMark Haverkamp 4721da177e4SLinus Torvalds /** 4731da177e4SLinus Torvalds * 4741da177e4SLinus Torvalds * aac_send_raw_scb 4751da177e4SLinus Torvalds * 4761da177e4SLinus Torvalds */ 4771da177e4SLinus Torvalds 4784833869eSAdrian Bunk static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) 4791da177e4SLinus Torvalds { 4801da177e4SLinus Torvalds struct fib* srbfib; 4811da177e4SLinus Torvalds int status; 48256b58712SMark Haverkamp struct aac_srb *srbcmd = NULL; 483423400e6SRaghava Aditya Renukunta struct aac_hba_cmd_req *hbacmd = NULL; 48456b58712SMark Haverkamp struct user_aac_srb *user_srbcmd = NULL; 48556b58712SMark Haverkamp struct user_aac_srb __user *user_srb = arg; 4861da177e4SLinus Torvalds struct aac_srb_reply __user *user_reply; 487423400e6SRaghava Aditya Renukunta u32 chn; 4881da177e4SLinus Torvalds u32 fibsize = 0; 4891da177e4SLinus Torvalds u32 flags = 0; 4901da177e4SLinus Torvalds s32 rcode = 0; 4911da177e4SLinus Torvalds u32 data_dir; 492423400e6SRaghava Aditya Renukunta void __user *sg_user[HBA_MAX_SG_EMBEDDED]; 493423400e6SRaghava Aditya Renukunta void *sg_list[HBA_MAX_SG_EMBEDDED]; 494423400e6SRaghava Aditya Renukunta u32 sg_count[HBA_MAX_SG_EMBEDDED]; 4951da177e4SLinus Torvalds u32 sg_indx = 0; 4961da177e4SLinus Torvalds u32 byte_count = 0; 497f2b1a06aSMark Haverkamp u32 actual_fibsize64, actual_fibsize = 0; 4981da177e4SLinus Torvalds int i; 499423400e6SRaghava Aditya Renukunta int is_native_device; 500423400e6SRaghava Aditya Renukunta u64 address; 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds 50333bb3b29SMark Haverkamp if (dev->in_reset) { 50433bb3b29SMark Haverkamp dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n")); 50533bb3b29SMark Haverkamp return -EBUSY; 50633bb3b29SMark Haverkamp } 5071da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)){ 5087c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 5091da177e4SLinus Torvalds return -EPERM; 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds /* 512f2b1a06aSMark Haverkamp * Allocate and initialize a Fib then setup a SRB command 5131da177e4SLinus Torvalds */ 514bfb35aa8SMark Haverkamp if (!(srbfib = aac_fib_alloc(dev))) { 5155d497cecSMark Haverkamp return -ENOMEM; 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds 5187c00ffa3SMark Haverkamp memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */ 5191da177e4SLinus Torvalds if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){ 5207c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); 5211da177e4SLinus Torvalds rcode = -EFAULT; 5221da177e4SLinus Torvalds goto cleanup; 5231da177e4SLinus Torvalds } 5241da177e4SLinus Torvalds 525b4789b8eSMahesh Rajashekhara if ((fibsize < (sizeof(struct user_aac_srb) - sizeof(struct user_sgentry))) || 526b4789b8eSMahesh Rajashekhara (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))) { 5271da177e4SLinus Torvalds rcode = -EINVAL; 5281da177e4SLinus Torvalds goto cleanup; 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds 5314645df10SDave Jones user_srbcmd = kmalloc(fibsize, GFP_KERNEL); 5327c00ffa3SMark Haverkamp if (!user_srbcmd) { 5337c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not make a copy of the srb\n")); 5347c00ffa3SMark Haverkamp rcode = -ENOMEM; 5357c00ffa3SMark Haverkamp goto cleanup; 5367c00ffa3SMark Haverkamp } 53756b58712SMark Haverkamp if(copy_from_user(user_srbcmd, user_srb,fibsize)){ 5387c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n")); 5391da177e4SLinus Torvalds rcode = -EFAULT; 5401da177e4SLinus Torvalds goto cleanup; 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds 54356b58712SMark Haverkamp flags = user_srbcmd->flags; /* from user in cpu order */ 54456b58712SMark Haverkamp switch (flags & (SRB_DataIn | SRB_DataOut)) { 5451da177e4SLinus Torvalds case SRB_DataOut: 5461da177e4SLinus Torvalds data_dir = DMA_TO_DEVICE; 5471da177e4SLinus Torvalds break; 5481da177e4SLinus Torvalds case (SRB_DataIn | SRB_DataOut): 5491da177e4SLinus Torvalds data_dir = DMA_BIDIRECTIONAL; 5501da177e4SLinus Torvalds break; 5511da177e4SLinus Torvalds case SRB_DataIn: 5521da177e4SLinus Torvalds data_dir = DMA_FROM_DEVICE; 5531da177e4SLinus Torvalds break; 5541da177e4SLinus Torvalds default: 5551da177e4SLinus Torvalds data_dir = DMA_NONE; 5561da177e4SLinus Torvalds } 5576391a113STobias Klauser if (user_srbcmd->sg.count > ARRAY_SIZE(sg_list)) { 5587c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: too many sg entries %d\n", 559423400e6SRaghava Aditya Renukunta user_srbcmd->sg.count)); 560423400e6SRaghava Aditya Renukunta rcode = -EINVAL; 561423400e6SRaghava Aditya Renukunta goto cleanup; 562423400e6SRaghava Aditya Renukunta } 563423400e6SRaghava Aditya Renukunta if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) { 564423400e6SRaghava Aditya Renukunta dprintk((KERN_DEBUG"aacraid:SG with no direction specified\n")); 5657c00ffa3SMark Haverkamp rcode = -EINVAL; 5667c00ffa3SMark Haverkamp goto cleanup; 5677c00ffa3SMark Haverkamp } 568f2b1a06aSMark Haverkamp actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + 569f2b1a06aSMark Haverkamp ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry)); 570f2b1a06aSMark Haverkamp actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) * 571f2b1a06aSMark Haverkamp (sizeof(struct sgentry64) - sizeof(struct sgentry)); 572f2b1a06aSMark Haverkamp /* User made a mistake - should not continue */ 573f2b1a06aSMark Haverkamp if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) { 574f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Bad Size specified in " 575f2b1a06aSMark Haverkamp "Raw SRB command calculated fibsize=%lu;%lu " 576f2b1a06aSMark Haverkamp "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu " 577f2b1a06aSMark Haverkamp "issued fibsize=%d\n", 578f2b1a06aSMark Haverkamp actual_fibsize, actual_fibsize64, user_srbcmd->sg.count, 579f2b1a06aSMark Haverkamp sizeof(struct aac_srb), sizeof(struct sgentry), 580f2b1a06aSMark Haverkamp sizeof(struct sgentry64), fibsize)); 581f2b1a06aSMark Haverkamp rcode = -EINVAL; 582f2b1a06aSMark Haverkamp goto cleanup; 583f2b1a06aSMark Haverkamp } 584423400e6SRaghava Aditya Renukunta 585f3ef4a74SRaghava Aditya Renukunta chn = user_srbcmd->channel; 586423400e6SRaghava Aditya Renukunta if (chn < AAC_MAX_BUSES && user_srbcmd->id < AAC_MAX_TARGETS && 587423400e6SRaghava Aditya Renukunta dev->hba_map[chn][user_srbcmd->id].devtype == 588423400e6SRaghava Aditya Renukunta AAC_DEVTYPE_NATIVE_RAW) { 589423400e6SRaghava Aditya Renukunta is_native_device = 1; 590423400e6SRaghava Aditya Renukunta hbacmd = (struct aac_hba_cmd_req *)srbfib->hw_fib_va; 591423400e6SRaghava Aditya Renukunta memset(hbacmd, 0, 96); /* sizeof(*hbacmd) is not necessary */ 592423400e6SRaghava Aditya Renukunta 593423400e6SRaghava Aditya Renukunta /* iu_type is a parameter of aac_hba_send */ 594423400e6SRaghava Aditya Renukunta switch (data_dir) { 595423400e6SRaghava Aditya Renukunta case DMA_TO_DEVICE: 596423400e6SRaghava Aditya Renukunta hbacmd->byte1 = 2; 597423400e6SRaghava Aditya Renukunta break; 598423400e6SRaghava Aditya Renukunta case DMA_FROM_DEVICE: 599423400e6SRaghava Aditya Renukunta case DMA_BIDIRECTIONAL: 600423400e6SRaghava Aditya Renukunta hbacmd->byte1 = 1; 601423400e6SRaghava Aditya Renukunta break; 602423400e6SRaghava Aditya Renukunta case DMA_NONE: 603423400e6SRaghava Aditya Renukunta default: 604423400e6SRaghava Aditya Renukunta break; 605423400e6SRaghava Aditya Renukunta } 606423400e6SRaghava Aditya Renukunta hbacmd->lun[1] = cpu_to_le32(user_srbcmd->lun); 607423400e6SRaghava Aditya Renukunta hbacmd->it_nexus = dev->hba_map[chn][user_srbcmd->id].rmw_nexus; 608423400e6SRaghava Aditya Renukunta 609423400e6SRaghava Aditya Renukunta /* 610423400e6SRaghava Aditya Renukunta * we fill in reply_qid later in aac_src_deliver_message 611423400e6SRaghava Aditya Renukunta * we fill in iu_type, request_id later in aac_hba_send 612423400e6SRaghava Aditya Renukunta * we fill in emb_data_desc_count, data_length later 613423400e6SRaghava Aditya Renukunta * in sg list build 614423400e6SRaghava Aditya Renukunta */ 615423400e6SRaghava Aditya Renukunta 616423400e6SRaghava Aditya Renukunta memcpy(hbacmd->cdb, user_srbcmd->cdb, sizeof(hbacmd->cdb)); 617423400e6SRaghava Aditya Renukunta 618423400e6SRaghava Aditya Renukunta address = (u64)srbfib->hw_error_pa; 619423400e6SRaghava Aditya Renukunta hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); 620423400e6SRaghava Aditya Renukunta hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff)); 621423400e6SRaghava Aditya Renukunta hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); 622423400e6SRaghava Aditya Renukunta hbacmd->emb_data_desc_count = 623423400e6SRaghava Aditya Renukunta cpu_to_le32(user_srbcmd->sg.count); 624423400e6SRaghava Aditya Renukunta srbfib->hbacmd_size = 64 + 625423400e6SRaghava Aditya Renukunta user_srbcmd->sg.count * sizeof(struct aac_hba_sgl); 626423400e6SRaghava Aditya Renukunta 627423400e6SRaghava Aditya Renukunta } else { 628423400e6SRaghava Aditya Renukunta is_native_device = 0; 629423400e6SRaghava Aditya Renukunta aac_fib_init(srbfib); 630423400e6SRaghava Aditya Renukunta 631423400e6SRaghava Aditya Renukunta /* raw_srb FIB is not FastResponseCapable */ 632423400e6SRaghava Aditya Renukunta srbfib->hw_fib_va->header.XferState &= 633423400e6SRaghava Aditya Renukunta ~cpu_to_le32(FastResponseCapable); 634423400e6SRaghava Aditya Renukunta 635423400e6SRaghava Aditya Renukunta srbcmd = (struct aac_srb *) fib_data(srbfib); 636423400e6SRaghava Aditya Renukunta 637423400e6SRaghava Aditya Renukunta // Fix up srb for endian and force some values 638423400e6SRaghava Aditya Renukunta 639423400e6SRaghava Aditya Renukunta srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this 640423400e6SRaghava Aditya Renukunta srbcmd->channel = cpu_to_le32(user_srbcmd->channel); 641423400e6SRaghava Aditya Renukunta srbcmd->id = cpu_to_le32(user_srbcmd->id); 642423400e6SRaghava Aditya Renukunta srbcmd->lun = cpu_to_le32(user_srbcmd->lun); 643423400e6SRaghava Aditya Renukunta srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); 644423400e6SRaghava Aditya Renukunta srbcmd->flags = cpu_to_le32(flags); 645423400e6SRaghava Aditya Renukunta srbcmd->retry_limit = 0; // Obsolete parameter 646423400e6SRaghava Aditya Renukunta srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); 647423400e6SRaghava Aditya Renukunta memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); 648423400e6SRaghava Aditya Renukunta } 649423400e6SRaghava Aditya Renukunta 650423400e6SRaghava Aditya Renukunta byte_count = 0; 651423400e6SRaghava Aditya Renukunta if (is_native_device) { 652423400e6SRaghava Aditya Renukunta struct user_sgmap *usg32 = &user_srbcmd->sg; 653423400e6SRaghava Aditya Renukunta struct user_sgmap64 *usg64 = 654423400e6SRaghava Aditya Renukunta (struct user_sgmap64 *)&user_srbcmd->sg; 655423400e6SRaghava Aditya Renukunta 656423400e6SRaghava Aditya Renukunta for (i = 0; i < usg32->count; i++) { 657423400e6SRaghava Aditya Renukunta void *p; 658423400e6SRaghava Aditya Renukunta u64 addr; 659423400e6SRaghava Aditya Renukunta 660423400e6SRaghava Aditya Renukunta sg_count[i] = (actual_fibsize64 == fibsize) ? 661423400e6SRaghava Aditya Renukunta usg64->sg[i].count : usg32->sg[i].count; 662423400e6SRaghava Aditya Renukunta if (sg_count[i] > 663423400e6SRaghava Aditya Renukunta (dev->scsi_host_ptr->max_sectors << 9)) { 664423400e6SRaghava Aditya Renukunta pr_err("aacraid: upsg->sg[%d].count=%u>%u\n", 665423400e6SRaghava Aditya Renukunta i, sg_count[i], 666423400e6SRaghava Aditya Renukunta dev->scsi_host_ptr->max_sectors << 9); 667f2b1a06aSMark Haverkamp rcode = -EINVAL; 668f2b1a06aSMark Haverkamp goto cleanup; 669f2b1a06aSMark Haverkamp } 670423400e6SRaghava Aditya Renukunta 671c831a4a0SRaghava Aditya Renukunta p = kmalloc(sg_count[i], GFP_KERNEL); 672423400e6SRaghava Aditya Renukunta if (!p) { 673423400e6SRaghava Aditya Renukunta rcode = -ENOMEM; 674423400e6SRaghava Aditya Renukunta goto cleanup; 675423400e6SRaghava Aditya Renukunta } 676423400e6SRaghava Aditya Renukunta 677423400e6SRaghava Aditya Renukunta if (actual_fibsize64 == fibsize) { 678423400e6SRaghava Aditya Renukunta addr = (u64)usg64->sg[i].addr[0]; 679423400e6SRaghava Aditya Renukunta addr += ((u64)usg64->sg[i].addr[1]) << 32; 680423400e6SRaghava Aditya Renukunta } else { 681423400e6SRaghava Aditya Renukunta addr = (u64)usg32->sg[i].addr; 682423400e6SRaghava Aditya Renukunta } 683423400e6SRaghava Aditya Renukunta 684423400e6SRaghava Aditya Renukunta sg_user[i] = (void __user *)(uintptr_t)addr; 685423400e6SRaghava Aditya Renukunta sg_list[i] = p; // save so we can clean up later 686423400e6SRaghava Aditya Renukunta sg_indx = i; 687423400e6SRaghava Aditya Renukunta 688423400e6SRaghava Aditya Renukunta if (flags & SRB_DataOut) { 689423400e6SRaghava Aditya Renukunta if (copy_from_user(p, sg_user[i], 690423400e6SRaghava Aditya Renukunta sg_count[i])) { 691423400e6SRaghava Aditya Renukunta rcode = -EFAULT; 692423400e6SRaghava Aditya Renukunta goto cleanup; 693423400e6SRaghava Aditya Renukunta } 694423400e6SRaghava Aditya Renukunta } 695423400e6SRaghava Aditya Renukunta addr = pci_map_single(dev->pdev, p, sg_count[i], 696423400e6SRaghava Aditya Renukunta data_dir); 697423400e6SRaghava Aditya Renukunta hbacmd->sge[i].addr_hi = cpu_to_le32((u32)(addr>>32)); 698423400e6SRaghava Aditya Renukunta hbacmd->sge[i].addr_lo = cpu_to_le32( 699423400e6SRaghava Aditya Renukunta (u32)(addr & 0xffffffff)); 700423400e6SRaghava Aditya Renukunta hbacmd->sge[i].len = cpu_to_le32(sg_count[i]); 701423400e6SRaghava Aditya Renukunta hbacmd->sge[i].flags = 0; 702423400e6SRaghava Aditya Renukunta byte_count += sg_count[i]; 703423400e6SRaghava Aditya Renukunta } 704423400e6SRaghava Aditya Renukunta 705423400e6SRaghava Aditya Renukunta if (usg32->count > 0) /* embedded sglist */ 706423400e6SRaghava Aditya Renukunta hbacmd->sge[usg32->count-1].flags = 707423400e6SRaghava Aditya Renukunta cpu_to_le32(0x40000000); 708423400e6SRaghava Aditya Renukunta hbacmd->data_length = cpu_to_le32(byte_count); 709423400e6SRaghava Aditya Renukunta 710423400e6SRaghava Aditya Renukunta status = aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, srbfib, 711423400e6SRaghava Aditya Renukunta NULL, NULL); 712423400e6SRaghava Aditya Renukunta 713423400e6SRaghava Aditya Renukunta } else if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) { 71456b58712SMark Haverkamp struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg; 71584e29308SMark Haverkamp struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds /* 7181da177e4SLinus Torvalds * This should also catch if user used the 32 bit sgmap 7191da177e4SLinus Torvalds */ 720f2b1a06aSMark Haverkamp if (actual_fibsize64 == fibsize) { 721f2b1a06aSMark Haverkamp actual_fibsize = actual_fibsize64; 722f2b1a06aSMark Haverkamp for (i = 0; i < upsg->count; i++) { 723f2b1a06aSMark Haverkamp u64 addr; 724f2b1a06aSMark Haverkamp void* p; 725423400e6SRaghava Aditya Renukunta 726423400e6SRaghava Aditya Renukunta sg_count[i] = upsg->sg[i].count; 727423400e6SRaghava Aditya Renukunta if (sg_count[i] > 728cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 72909050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 73009050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 731cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 73209050715SMark Salyzyn rcode = -EINVAL; 73309050715SMark Salyzyn goto cleanup; 73409050715SMark Salyzyn } 735c831a4a0SRaghava Aditya Renukunta 736c831a4a0SRaghava Aditya Renukunta p = kmalloc(sg_count[i], GFP_KERNEL); 7376dcd4a7fSSalyzyn, Mark if(!p) { 738f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 739423400e6SRaghava Aditya Renukunta sg_count[i], i, upsg->count)); 740f2b1a06aSMark Haverkamp rcode = -ENOMEM; 7411da177e4SLinus Torvalds goto cleanup; 7421da177e4SLinus Torvalds } 743f2b1a06aSMark Haverkamp addr = (u64)upsg->sg[i].addr[0]; 744f2b1a06aSMark Haverkamp addr += ((u64)upsg->sg[i].addr[1]) << 32; 745142956afSAl Viro sg_user[i] = (void __user *)(uintptr_t)addr; 746f2b1a06aSMark Haverkamp sg_list[i] = p; // save so we can clean up later 747f2b1a06aSMark Haverkamp sg_indx = i; 748f2b1a06aSMark Haverkamp 749f2b1a06aSMark Haverkamp if (flags & SRB_DataOut) { 750423400e6SRaghava Aditya Renukunta if (copy_from_user(p, sg_user[i], 751423400e6SRaghava Aditya Renukunta sg_count[i])){ 752f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 753f2b1a06aSMark Haverkamp rcode = -EFAULT; 754f2b1a06aSMark Haverkamp goto cleanup; 755f2b1a06aSMark Haverkamp } 756f2b1a06aSMark Haverkamp } 757423400e6SRaghava Aditya Renukunta addr = pci_map_single(dev->pdev, p, 758423400e6SRaghava Aditya Renukunta sg_count[i], data_dir); 759f2b1a06aSMark Haverkamp 760f2b1a06aSMark Haverkamp psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 761f2b1a06aSMark Haverkamp psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 762423400e6SRaghava Aditya Renukunta byte_count += sg_count[i]; 763423400e6SRaghava Aditya Renukunta psg->sg[i].count = cpu_to_le32(sg_count[i]); 764f2b1a06aSMark Haverkamp } 765f2b1a06aSMark Haverkamp } else { 766f2b1a06aSMark Haverkamp struct user_sgmap* usg; 76722e9f5a6SMuhammad Falak R Wani usg = kmemdup(upsg, 76822e9f5a6SMuhammad Falak R Wani actual_fibsize - sizeof(struct aac_srb) 7697c00ffa3SMark Haverkamp + sizeof(struct sgmap), GFP_KERNEL); 7707c00ffa3SMark Haverkamp if (!usg) { 7717c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); 7727c00ffa3SMark Haverkamp rcode = -ENOMEM; 7737c00ffa3SMark Haverkamp goto cleanup; 7747c00ffa3SMark Haverkamp } 775f2b1a06aSMark Haverkamp actual_fibsize = actual_fibsize64; 7761da177e4SLinus Torvalds 7777c00ffa3SMark Haverkamp for (i = 0; i < usg->count; i++) { 77856b58712SMark Haverkamp u64 addr; 7791da177e4SLinus Torvalds void* p; 780423400e6SRaghava Aditya Renukunta 781423400e6SRaghava Aditya Renukunta sg_count[i] = usg->sg[i].count; 782423400e6SRaghava Aditya Renukunta if (sg_count[i] > 783cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 78409050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 78509050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 786cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 7877dd72f51SJesper Juhl kfree(usg); 78809050715SMark Salyzyn rcode = -EINVAL; 78909050715SMark Salyzyn goto cleanup; 79009050715SMark Salyzyn } 791c831a4a0SRaghava Aditya Renukunta 792c831a4a0SRaghava Aditya Renukunta p = kmalloc(sg_count[i], GFP_KERNEL); 7936dcd4a7fSSalyzyn, Mark if(!p) { 7947c00ffa3SMark Haverkamp dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 795423400e6SRaghava Aditya Renukunta sg_count[i], i, usg->count)); 7968a52da63SJulia Lawall kfree(usg); 7971da177e4SLinus Torvalds rcode = -ENOMEM; 7981da177e4SLinus Torvalds goto cleanup; 7991da177e4SLinus Torvalds } 800142956afSAl Viro sg_user[i] = (void __user *)(uintptr_t)usg->sg[i].addr; 8011da177e4SLinus Torvalds sg_list[i] = p; // save so we can clean up later 8021da177e4SLinus Torvalds sg_indx = i; 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds if (flags & SRB_DataOut) { 805423400e6SRaghava Aditya Renukunta if (copy_from_user(p, sg_user[i], 806423400e6SRaghava Aditya Renukunta sg_count[i])) { 8077c00ffa3SMark Haverkamp kfree (usg); 8087c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 8091da177e4SLinus Torvalds rcode = -EFAULT; 8101da177e4SLinus Torvalds goto cleanup; 8111da177e4SLinus Torvalds } 8121da177e4SLinus Torvalds } 813423400e6SRaghava Aditya Renukunta addr = pci_map_single(dev->pdev, p, 814423400e6SRaghava Aditya Renukunta sg_count[i], data_dir); 8151da177e4SLinus Torvalds 81656b58712SMark Haverkamp psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 81756b58712SMark Haverkamp psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 818423400e6SRaghava Aditya Renukunta byte_count += sg_count[i]; 819423400e6SRaghava Aditya Renukunta psg->sg[i].count = cpu_to_le32(sg_count[i]); 8201da177e4SLinus Torvalds } 8217c00ffa3SMark Haverkamp kfree (usg); 822f2b1a06aSMark Haverkamp } 8231da177e4SLinus Torvalds srbcmd->count = cpu_to_le32(byte_count); 8242f5d1f79SMahesh Rajashekhara if (user_srbcmd->sg.count) 8257c00ffa3SMark Haverkamp psg->count = cpu_to_le32(sg_indx+1); 8262f5d1f79SMahesh Rajashekhara else 8272f5d1f79SMahesh Rajashekhara psg->count = 0; 828bfb35aa8SMark Haverkamp status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); 8291da177e4SLinus Torvalds } else { 83056b58712SMark Haverkamp struct user_sgmap* upsg = &user_srbcmd->sg; 8311da177e4SLinus Torvalds struct sgmap* psg = &srbcmd->sg; 8321da177e4SLinus Torvalds 833f2b1a06aSMark Haverkamp if (actual_fibsize64 == fibsize) { 834f2b1a06aSMark Haverkamp struct user_sgmap64* usg = (struct user_sgmap64 *)upsg; 835f2b1a06aSMark Haverkamp for (i = 0; i < upsg->count; i++) { 836142956afSAl Viro uintptr_t addr; 837f2b1a06aSMark Haverkamp void* p; 838423400e6SRaghava Aditya Renukunta 839423400e6SRaghava Aditya Renukunta sg_count[i] = usg->sg[i].count; 840423400e6SRaghava Aditya Renukunta if (sg_count[i] > 841cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 84209050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 84309050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 844cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 84509050715SMark Salyzyn rcode = -EINVAL; 84609050715SMark Salyzyn goto cleanup; 84709050715SMark Salyzyn } 848c831a4a0SRaghava Aditya Renukunta p = kmalloc(sg_count[i], GFP_KERNEL|GFP_DMA32); 8496dcd4a7fSSalyzyn, Mark if (!p) { 850f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 851423400e6SRaghava Aditya Renukunta sg_count[i], i, usg->count)); 852f2b1a06aSMark Haverkamp rcode = -ENOMEM; 8531da177e4SLinus Torvalds goto cleanup; 8541da177e4SLinus Torvalds } 855f2b1a06aSMark Haverkamp addr = (u64)usg->sg[i].addr[0]; 856f2b1a06aSMark Haverkamp addr += ((u64)usg->sg[i].addr[1]) << 32; 857142956afSAl Viro sg_user[i] = (void __user *)addr; 858f2b1a06aSMark Haverkamp sg_list[i] = p; // save so we can clean up later 859f2b1a06aSMark Haverkamp sg_indx = i; 860f2b1a06aSMark Haverkamp 861f2b1a06aSMark Haverkamp if (flags & SRB_DataOut) { 862423400e6SRaghava Aditya Renukunta if (copy_from_user(p, sg_user[i], 863423400e6SRaghava Aditya Renukunta sg_count[i])){ 864f2b1a06aSMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 865f2b1a06aSMark Haverkamp rcode = -EFAULT; 8661da177e4SLinus Torvalds goto cleanup; 8671da177e4SLinus Torvalds } 868f2b1a06aSMark Haverkamp } 869f2b1a06aSMark Haverkamp addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); 870f2b1a06aSMark Haverkamp 871f2b1a06aSMark Haverkamp psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff); 872f2b1a06aSMark Haverkamp byte_count += usg->sg[i].count; 873423400e6SRaghava Aditya Renukunta psg->sg[i].count = cpu_to_le32(sg_count[i]); 874f2b1a06aSMark Haverkamp } 875f2b1a06aSMark Haverkamp } else { 87656b58712SMark Haverkamp for (i = 0; i < upsg->count; i++) { 8771da177e4SLinus Torvalds dma_addr_t addr; 8781da177e4SLinus Torvalds void* p; 879423400e6SRaghava Aditya Renukunta 880423400e6SRaghava Aditya Renukunta sg_count[i] = upsg->sg[i].count; 881423400e6SRaghava Aditya Renukunta if (sg_count[i] > 882cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech ((dev->adapter_info.options & 88309050715SMark Salyzyn AAC_OPT_NEW_COMM) ? 88409050715SMark Salyzyn (dev->scsi_host_ptr->max_sectors << 9) : 885cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 65536)) { 88609050715SMark Salyzyn rcode = -EINVAL; 88709050715SMark Salyzyn goto cleanup; 88809050715SMark Salyzyn } 889c831a4a0SRaghava Aditya Renukunta p = kmalloc(sg_count[i], GFP_KERNEL|GFP_DMA32); 8906dcd4a7fSSalyzyn, Mark if (!p) { 8917c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 892423400e6SRaghava Aditya Renukunta sg_count[i], i, upsg->count)); 8931da177e4SLinus Torvalds rcode = -ENOMEM; 8941da177e4SLinus Torvalds goto cleanup; 8951da177e4SLinus Torvalds } 896142956afSAl Viro sg_user[i] = (void __user *)(uintptr_t)upsg->sg[i].addr; 8971da177e4SLinus Torvalds sg_list[i] = p; // save so we can clean up later 8981da177e4SLinus Torvalds sg_indx = i; 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds if (flags & SRB_DataOut) { 90156b58712SMark Haverkamp if (copy_from_user(p, sg_user[i], 902423400e6SRaghava Aditya Renukunta sg_count[i])) { 9037c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 9041da177e4SLinus Torvalds rcode = -EFAULT; 9051da177e4SLinus Torvalds goto cleanup; 9061da177e4SLinus Torvalds } 9071da177e4SLinus Torvalds } 90856b58712SMark Haverkamp addr = pci_map_single(dev->pdev, p, 909423400e6SRaghava Aditya Renukunta sg_count[i], data_dir); 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds psg->sg[i].addr = cpu_to_le32(addr); 912423400e6SRaghava Aditya Renukunta byte_count += sg_count[i]; 913423400e6SRaghava Aditya Renukunta psg->sg[i].count = cpu_to_le32(sg_count[i]); 914f2b1a06aSMark Haverkamp } 9151da177e4SLinus Torvalds } 9161da177e4SLinus Torvalds srbcmd->count = cpu_to_le32(byte_count); 9172f5d1f79SMahesh Rajashekhara if (user_srbcmd->sg.count) 9187c00ffa3SMark Haverkamp psg->count = cpu_to_le32(sg_indx+1); 9192f5d1f79SMahesh Rajashekhara else 9202f5d1f79SMahesh Rajashekhara psg->count = 0; 921bfb35aa8SMark Haverkamp status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL); 9221da177e4SLinus Torvalds } 923423400e6SRaghava Aditya Renukunta 924cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (status == -ERESTARTSYS) { 925cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech rcode = -ERESTARTSYS; 926c8f7b073SMark Haverkamp goto cleanup; 927c8f7b073SMark Haverkamp } 9281da177e4SLinus Torvalds 9291da177e4SLinus Torvalds if (status != 0) { 9307c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); 9315d497cecSMark Haverkamp rcode = -ENXIO; 9321da177e4SLinus Torvalds goto cleanup; 9331da177e4SLinus Torvalds } 9341da177e4SLinus Torvalds 9351da177e4SLinus Torvalds if (flags & SRB_DataIn) { 9361da177e4SLinus Torvalds for(i = 0 ; i <= sg_indx; i++){ 937423400e6SRaghava Aditya Renukunta if (copy_to_user(sg_user[i], sg_list[i], sg_count[i])) { 9387c00ffa3SMark Haverkamp dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); 9391da177e4SLinus Torvalds rcode = -EFAULT; 9401da177e4SLinus Torvalds goto cleanup; 9411da177e4SLinus Torvalds 9421da177e4SLinus Torvalds } 9431da177e4SLinus Torvalds } 9441da177e4SLinus Torvalds } 9451da177e4SLinus Torvalds 946423400e6SRaghava Aditya Renukunta user_reply = arg + fibsize; 947423400e6SRaghava Aditya Renukunta if (is_native_device) { 948423400e6SRaghava Aditya Renukunta struct aac_hba_resp *err = 949423400e6SRaghava Aditya Renukunta &((struct aac_native_hba *)srbfib->hw_fib_va)->resp.err; 950423400e6SRaghava Aditya Renukunta struct aac_srb_reply reply; 951423400e6SRaghava Aditya Renukunta 952423400e6SRaghava Aditya Renukunta reply.status = ST_OK; 953423400e6SRaghava Aditya Renukunta if (srbfib->flags & FIB_CONTEXT_FLAG_FASTRESP) { 954423400e6SRaghava Aditya Renukunta /* fast response */ 955423400e6SRaghava Aditya Renukunta reply.srb_status = SRB_STATUS_SUCCESS; 956423400e6SRaghava Aditya Renukunta reply.scsi_status = 0; 957423400e6SRaghava Aditya Renukunta reply.data_xfer_length = byte_count; 9585cc973f0SColin Ian King reply.sense_data_size = 0; 9595cc973f0SColin Ian King memset(reply.sense_data, 0, AAC_SENSE_BUFFERSIZE); 960423400e6SRaghava Aditya Renukunta } else { 961423400e6SRaghava Aditya Renukunta reply.srb_status = err->service_response; 962423400e6SRaghava Aditya Renukunta reply.scsi_status = err->status; 963423400e6SRaghava Aditya Renukunta reply.data_xfer_length = byte_count - 964423400e6SRaghava Aditya Renukunta le32_to_cpu(err->residual_count); 965423400e6SRaghava Aditya Renukunta reply.sense_data_size = err->sense_response_data_len; 966423400e6SRaghava Aditya Renukunta memcpy(reply.sense_data, err->sense_response_buf, 967423400e6SRaghava Aditya Renukunta AAC_SENSE_BUFFERSIZE); 968423400e6SRaghava Aditya Renukunta } 969423400e6SRaghava Aditya Renukunta if (copy_to_user(user_reply, &reply, 970423400e6SRaghava Aditya Renukunta sizeof(struct aac_srb_reply))) { 971423400e6SRaghava Aditya Renukunta dprintk((KERN_DEBUG"aacraid: Copy to user failed\n")); 9721da177e4SLinus Torvalds rcode = -EFAULT; 9731da177e4SLinus Torvalds goto cleanup; 9741da177e4SLinus Torvalds } 975423400e6SRaghava Aditya Renukunta } else { 976423400e6SRaghava Aditya Renukunta struct aac_srb_reply *reply; 977423400e6SRaghava Aditya Renukunta 978423400e6SRaghava Aditya Renukunta reply = (struct aac_srb_reply *) fib_data(srbfib); 979423400e6SRaghava Aditya Renukunta if (copy_to_user(user_reply, reply, 980423400e6SRaghava Aditya Renukunta sizeof(struct aac_srb_reply))) { 981423400e6SRaghava Aditya Renukunta dprintk((KERN_DEBUG"aacraid: Copy to user failed\n")); 982423400e6SRaghava Aditya Renukunta rcode = -EFAULT; 983423400e6SRaghava Aditya Renukunta goto cleanup; 984423400e6SRaghava Aditya Renukunta } 985423400e6SRaghava Aditya Renukunta } 9861da177e4SLinus Torvalds 9871da177e4SLinus Torvalds cleanup: 98856b58712SMark Haverkamp kfree(user_srbcmd); 989cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (rcode != -ERESTARTSYS) { 990423400e6SRaghava Aditya Renukunta for (i = 0; i <= sg_indx; i++) 991423400e6SRaghava Aditya Renukunta kfree(sg_list[i]); 992bfb35aa8SMark Haverkamp aac_fib_complete(srbfib); 993bfb35aa8SMark Haverkamp aac_fib_free(srbfib); 994c8f7b073SMark Haverkamp } 9951da177e4SLinus Torvalds 9961da177e4SLinus Torvalds return rcode; 9971da177e4SLinus Torvalds } 9981da177e4SLinus Torvalds 9991da177e4SLinus Torvalds struct aac_pci_info { 10001da177e4SLinus Torvalds u32 bus; 10011da177e4SLinus Torvalds u32 slot; 10021da177e4SLinus Torvalds }; 10031da177e4SLinus Torvalds 10041da177e4SLinus Torvalds 10054833869eSAdrian Bunk static int aac_get_pci_info(struct aac_dev* dev, void __user *arg) 10061da177e4SLinus Torvalds { 10071da177e4SLinus Torvalds struct aac_pci_info pci_info; 10081da177e4SLinus Torvalds 10091da177e4SLinus Torvalds pci_info.bus = dev->pdev->bus->number; 10101da177e4SLinus Torvalds pci_info.slot = PCI_SLOT(dev->pdev->devfn); 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { 10137c00ffa3SMark Haverkamp dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); 10141da177e4SLinus Torvalds return -EFAULT; 10151da177e4SLinus Torvalds } 10161da177e4SLinus Torvalds return 0; 10171da177e4SLinus Torvalds } 1018c799d519SRaghava Aditya Renukunta 1019c799d519SRaghava Aditya Renukunta static int aac_get_hba_info(struct aac_dev *dev, void __user *arg) 1020c799d519SRaghava Aditya Renukunta { 1021c799d519SRaghava Aditya Renukunta struct aac_hba_info hbainfo; 1022c799d519SRaghava Aditya Renukunta 1023c799d519SRaghava Aditya Renukunta hbainfo.adapter_number = (u8) dev->id; 1024c799d519SRaghava Aditya Renukunta hbainfo.system_io_bus_number = dev->pdev->bus->number; 1025c799d519SRaghava Aditya Renukunta hbainfo.device_number = (dev->pdev->devfn >> 3); 1026c799d519SRaghava Aditya Renukunta hbainfo.function_number = (dev->pdev->devfn & 0x0007); 1027c799d519SRaghava Aditya Renukunta 1028c799d519SRaghava Aditya Renukunta hbainfo.vendor_id = dev->pdev->vendor; 1029c799d519SRaghava Aditya Renukunta hbainfo.device_id = dev->pdev->device; 1030c799d519SRaghava Aditya Renukunta hbainfo.sub_vendor_id = dev->pdev->subsystem_vendor; 1031c799d519SRaghava Aditya Renukunta hbainfo.sub_system_id = dev->pdev->subsystem_device; 1032c799d519SRaghava Aditya Renukunta 1033c799d519SRaghava Aditya Renukunta if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { 1034c799d519SRaghava Aditya Renukunta dprintk((KERN_DEBUG "aacraid: Could not copy hba info\n")); 1035c799d519SRaghava Aditya Renukunta return -EFAULT; 1036c799d519SRaghava Aditya Renukunta } 1037c799d519SRaghava Aditya Renukunta 1038c799d519SRaghava Aditya Renukunta return 0; 1039c799d519SRaghava Aditya Renukunta } 1040c799d519SRaghava Aditya Renukunta 104109867a0eSRaghava Aditya Renukunta struct aac_reset_iop { 104209867a0eSRaghava Aditya Renukunta u8 reset_type; 104309867a0eSRaghava Aditya Renukunta }; 10441da177e4SLinus Torvalds 104509867a0eSRaghava Aditya Renukunta static int aac_send_reset_adapter(struct aac_dev *dev, void __user *arg) 104609867a0eSRaghava Aditya Renukunta { 104709867a0eSRaghava Aditya Renukunta struct aac_reset_iop reset; 104809867a0eSRaghava Aditya Renukunta int retval; 104909867a0eSRaghava Aditya Renukunta 105009867a0eSRaghava Aditya Renukunta if (copy_from_user((void *)&reset, arg, sizeof(struct aac_reset_iop))) 105109867a0eSRaghava Aditya Renukunta return -EFAULT; 105209867a0eSRaghava Aditya Renukunta 105309867a0eSRaghava Aditya Renukunta retval = aac_reset_adapter(dev, 0, reset.reset_type); 105409867a0eSRaghava Aditya Renukunta return retval; 105509867a0eSRaghava Aditya Renukunta 105609867a0eSRaghava Aditya Renukunta } 10571da177e4SLinus Torvalds 10581da177e4SLinus Torvalds int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg) 10591da177e4SLinus Torvalds { 10601da177e4SLinus Torvalds int status; 10611da177e4SLinus Torvalds 1062222a9fb3SRaghava Aditya Renukunta mutex_lock(&dev->ioctl_mutex); 1063222a9fb3SRaghava Aditya Renukunta 1064fbd18598SRaghava Aditya Renukunta if (dev->adapter_shutdown) { 1065fbd18598SRaghava Aditya Renukunta status = -EACCES; 1066fbd18598SRaghava Aditya Renukunta goto cleanup; 1067fbd18598SRaghava Aditya Renukunta } 1068fbd18598SRaghava Aditya Renukunta 10691da177e4SLinus Torvalds /* 10701da177e4SLinus Torvalds * HBA gets first crack 10711da177e4SLinus Torvalds */ 10721da177e4SLinus Torvalds 10731da177e4SLinus Torvalds status = aac_dev_ioctl(dev, cmd, arg); 10741da177e4SLinus Torvalds if (status != -ENOTTY) 1075222a9fb3SRaghava Aditya Renukunta goto cleanup; 10761da177e4SLinus Torvalds 10771da177e4SLinus Torvalds switch (cmd) { 10781da177e4SLinus Torvalds case FSACTL_MINIPORT_REV_CHECK: 10791da177e4SLinus Torvalds status = check_revision(dev, arg); 10801da177e4SLinus Torvalds break; 10817c00ffa3SMark Haverkamp case FSACTL_SEND_LARGE_FIB: 10821da177e4SLinus Torvalds case FSACTL_SENDFIB: 10831da177e4SLinus Torvalds status = ioctl_send_fib(dev, arg); 10841da177e4SLinus Torvalds break; 10851da177e4SLinus Torvalds case FSACTL_OPEN_GET_ADAPTER_FIB: 10861da177e4SLinus Torvalds status = open_getadapter_fib(dev, arg); 10871da177e4SLinus Torvalds break; 10881da177e4SLinus Torvalds case FSACTL_GET_NEXT_ADAPTER_FIB: 10891da177e4SLinus Torvalds status = next_getadapter_fib(dev, arg); 10901da177e4SLinus Torvalds break; 10911da177e4SLinus Torvalds case FSACTL_CLOSE_GET_ADAPTER_FIB: 10921da177e4SLinus Torvalds status = close_getadapter_fib(dev, arg); 10931da177e4SLinus Torvalds break; 10941da177e4SLinus Torvalds case FSACTL_SEND_RAW_SRB: 10951da177e4SLinus Torvalds status = aac_send_raw_srb(dev,arg); 10961da177e4SLinus Torvalds break; 10971da177e4SLinus Torvalds case FSACTL_GET_PCI_INFO: 10981da177e4SLinus Torvalds status = aac_get_pci_info(dev,arg); 10991da177e4SLinus Torvalds break; 1100c799d519SRaghava Aditya Renukunta case FSACTL_GET_HBA_INFO: 1101c799d519SRaghava Aditya Renukunta status = aac_get_hba_info(dev, arg); 1102c799d519SRaghava Aditya Renukunta break; 110309867a0eSRaghava Aditya Renukunta case FSACTL_RESET_IOP: 110409867a0eSRaghava Aditya Renukunta status = aac_send_reset_adapter(dev, arg); 110509867a0eSRaghava Aditya Renukunta break; 110609867a0eSRaghava Aditya Renukunta 11071da177e4SLinus Torvalds default: 11081da177e4SLinus Torvalds status = -ENOTTY; 11091da177e4SLinus Torvalds break; 11101da177e4SLinus Torvalds } 1111222a9fb3SRaghava Aditya Renukunta 1112222a9fb3SRaghava Aditya Renukunta cleanup: 1113222a9fb3SRaghava Aditya Renukunta mutex_unlock(&dev->ioctl_mutex); 1114222a9fb3SRaghava Aditya Renukunta 11151da177e4SLinus Torvalds return status; 11161da177e4SLinus Torvalds } 11171da177e4SLinus Torvalds 1118