18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Adaptec AAC series RAID controller driver 48c2ecf20Sopenharmony_ci * (c) Copyright 2001 Red Hat Inc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * based on the old aacraid driver that is.. 78c2ecf20Sopenharmony_ci * Adaptec aacraid device driver for Linux. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2000-2010 Adaptec, Inc. 108c2ecf20Sopenharmony_ci * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 118c2ecf20Sopenharmony_ci * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Module Name: 148c2ecf20Sopenharmony_ci * commctrl.c 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Abstract: Contains all routines for control of the AFA comm layer 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/types.h> 228c2ecf20Sopenharmony_ci#include <linux/pci.h> 238c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/completion.h> 268c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 278c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 288c2ecf20Sopenharmony_ci#include <linux/compat.h> 298c2ecf20Sopenharmony_ci#include <linux/delay.h> /* ssleep prototype */ 308c2ecf20Sopenharmony_ci#include <linux/kthread.h> 318c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 328c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include "aacraid.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci# define AAC_DEBUG_PREAMBLE KERN_INFO 378c2ecf20Sopenharmony_ci# define AAC_DEBUG_POSTAMBLE 388c2ecf20Sopenharmony_ci/** 398c2ecf20Sopenharmony_ci * ioctl_send_fib - send a FIB from userspace 408c2ecf20Sopenharmony_ci * @dev: adapter is being processed 418c2ecf20Sopenharmony_ci * @arg: arguments to the ioctl call 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * This routine sends a fib to the adapter on behalf of a user level 448c2ecf20Sopenharmony_ci * program. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cistatic int ioctl_send_fib(struct aac_dev * dev, void __user *arg) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct hw_fib * kfib; 498c2ecf20Sopenharmony_ci struct fib *fibptr; 508c2ecf20Sopenharmony_ci struct hw_fib * hw_fib = (struct hw_fib *)0; 518c2ecf20Sopenharmony_ci dma_addr_t hw_fib_pa = (dma_addr_t)0LL; 528c2ecf20Sopenharmony_ci unsigned int size, osize; 538c2ecf20Sopenharmony_ci int retval; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (dev->in_reset) { 568c2ecf20Sopenharmony_ci return -EBUSY; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci fibptr = aac_fib_alloc(dev); 598c2ecf20Sopenharmony_ci if(fibptr == NULL) { 608c2ecf20Sopenharmony_ci return -ENOMEM; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci kfib = fibptr->hw_fib_va; 648c2ecf20Sopenharmony_ci /* 658c2ecf20Sopenharmony_ci * First copy in the header so that we can check the size field. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) { 688c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 698c2ecf20Sopenharmony_ci return -EFAULT; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci /* 728c2ecf20Sopenharmony_ci * Since we copy based on the fib header size, make sure that we 738c2ecf20Sopenharmony_ci * will not overrun the buffer when we copy the memory. Return 748c2ecf20Sopenharmony_ci * an error if we would. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci osize = size = le16_to_cpu(kfib->header.Size) + 778c2ecf20Sopenharmony_ci sizeof(struct aac_fibhdr); 788c2ecf20Sopenharmony_ci if (size < le16_to_cpu(kfib->header.SenderSize)) 798c2ecf20Sopenharmony_ci size = le16_to_cpu(kfib->header.SenderSize); 808c2ecf20Sopenharmony_ci if (size > dev->max_fib_size) { 818c2ecf20Sopenharmony_ci dma_addr_t daddr; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (size > 2048) { 848c2ecf20Sopenharmony_ci retval = -EINVAL; 858c2ecf20Sopenharmony_ci goto cleanup; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci kfib = dma_alloc_coherent(&dev->pdev->dev, size, &daddr, 898c2ecf20Sopenharmony_ci GFP_KERNEL); 908c2ecf20Sopenharmony_ci if (!kfib) { 918c2ecf20Sopenharmony_ci retval = -ENOMEM; 928c2ecf20Sopenharmony_ci goto cleanup; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Highjack the hw_fib */ 968c2ecf20Sopenharmony_ci hw_fib = fibptr->hw_fib_va; 978c2ecf20Sopenharmony_ci hw_fib_pa = fibptr->hw_fib_pa; 988c2ecf20Sopenharmony_ci fibptr->hw_fib_va = kfib; 998c2ecf20Sopenharmony_ci fibptr->hw_fib_pa = daddr; 1008c2ecf20Sopenharmony_ci memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size); 1018c2ecf20Sopenharmony_ci memcpy(kfib, hw_fib, dev->max_fib_size); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (copy_from_user(kfib, arg, size)) { 1058c2ecf20Sopenharmony_ci retval = -EFAULT; 1068c2ecf20Sopenharmony_ci goto cleanup; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Sanity check the second copy */ 1108c2ecf20Sopenharmony_ci if ((osize != le16_to_cpu(kfib->header.Size) + 1118c2ecf20Sopenharmony_ci sizeof(struct aac_fibhdr)) 1128c2ecf20Sopenharmony_ci || (size < le16_to_cpu(kfib->header.SenderSize))) { 1138c2ecf20Sopenharmony_ci retval = -EINVAL; 1148c2ecf20Sopenharmony_ci goto cleanup; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) { 1188c2ecf20Sopenharmony_ci aac_adapter_interrupt(dev); 1198c2ecf20Sopenharmony_ci /* 1208c2ecf20Sopenharmony_ci * Since we didn't really send a fib, zero out the state to allow 1218c2ecf20Sopenharmony_ci * cleanup code not to assert. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci kfib->header.XferState = 0; 1248c2ecf20Sopenharmony_ci } else { 1258c2ecf20Sopenharmony_ci retval = aac_fib_send(le16_to_cpu(kfib->header.Command), fibptr, 1268c2ecf20Sopenharmony_ci le16_to_cpu(kfib->header.Size) , FsaNormal, 1278c2ecf20Sopenharmony_ci 1, 1, NULL, NULL); 1288c2ecf20Sopenharmony_ci if (retval) { 1298c2ecf20Sopenharmony_ci goto cleanup; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci if (aac_fib_complete(fibptr) != 0) { 1328c2ecf20Sopenharmony_ci retval = -EINVAL; 1338c2ecf20Sopenharmony_ci goto cleanup; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * Make sure that the size returned by the adapter (which includes 1388c2ecf20Sopenharmony_ci * the header) is less than or equal to the size of a fib, so we 1398c2ecf20Sopenharmony_ci * don't corrupt application data. Then copy that size to the user 1408c2ecf20Sopenharmony_ci * buffer. (Don't try to add the header information again, since it 1418c2ecf20Sopenharmony_ci * was already included by the adapter.) 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci retval = 0; 1458c2ecf20Sopenharmony_ci if (copy_to_user(arg, (void *)kfib, size)) 1468c2ecf20Sopenharmony_ci retval = -EFAULT; 1478c2ecf20Sopenharmony_cicleanup: 1488c2ecf20Sopenharmony_ci if (hw_fib) { 1498c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, size, kfib, 1508c2ecf20Sopenharmony_ci fibptr->hw_fib_pa); 1518c2ecf20Sopenharmony_ci fibptr->hw_fib_pa = hw_fib_pa; 1528c2ecf20Sopenharmony_ci fibptr->hw_fib_va = hw_fib; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci if (retval != -ERESTARTSYS) 1558c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 1568c2ecf20Sopenharmony_ci return retval; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/** 1608c2ecf20Sopenharmony_ci * open_getadapter_fib - Get the next fib 1618c2ecf20Sopenharmony_ci * @dev: adapter is being processed 1628c2ecf20Sopenharmony_ci * @arg: arguments to the open call 1638c2ecf20Sopenharmony_ci * 1648c2ecf20Sopenharmony_ci * This routine will get the next Fib, if available, from the AdapterFibContext 1658c2ecf20Sopenharmony_ci * passed in from the user. 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_cistatic int open_getadapter_fib(struct aac_dev * dev, void __user *arg) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct aac_fib_context * fibctx; 1708c2ecf20Sopenharmony_ci int status; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); 1738c2ecf20Sopenharmony_ci if (fibctx == NULL) { 1748c2ecf20Sopenharmony_ci status = -ENOMEM; 1758c2ecf20Sopenharmony_ci } else { 1768c2ecf20Sopenharmony_ci unsigned long flags; 1778c2ecf20Sopenharmony_ci struct list_head * entry; 1788c2ecf20Sopenharmony_ci struct aac_fib_context * context; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; 1818c2ecf20Sopenharmony_ci fibctx->size = sizeof(struct aac_fib_context); 1828c2ecf20Sopenharmony_ci /* 1838c2ecf20Sopenharmony_ci * Yes yes, I know this could be an index, but we have a 1848c2ecf20Sopenharmony_ci * better guarantee of uniqueness for the locked loop below. 1858c2ecf20Sopenharmony_ci * Without the aid of a persistent history, this also helps 1868c2ecf20Sopenharmony_ci * reduce the chance that the opaque context would be reused. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF); 1898c2ecf20Sopenharmony_ci /* 1908c2ecf20Sopenharmony_ci * Initialize the mutex used to wait for the next AIF. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci init_completion(&fibctx->completion); 1938c2ecf20Sopenharmony_ci fibctx->wait = 0; 1948c2ecf20Sopenharmony_ci /* 1958c2ecf20Sopenharmony_ci * Initialize the fibs and set the count of fibs on 1968c2ecf20Sopenharmony_ci * the list to 0. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci fibctx->count = 0; 1998c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fibctx->fib_list); 2008c2ecf20Sopenharmony_ci fibctx->jiffies = jiffies/HZ; 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * Now add this context onto the adapter's 2038c2ecf20Sopenharmony_ci * AdapterFibContext list. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flags); 2068c2ecf20Sopenharmony_ci /* Ensure that we have a unique identifier */ 2078c2ecf20Sopenharmony_ci entry = dev->fib_list.next; 2088c2ecf20Sopenharmony_ci while (entry != &dev->fib_list) { 2098c2ecf20Sopenharmony_ci context = list_entry(entry, struct aac_fib_context, next); 2108c2ecf20Sopenharmony_ci if (context->unique == fibctx->unique) { 2118c2ecf20Sopenharmony_ci /* Not unique (32 bits) */ 2128c2ecf20Sopenharmony_ci fibctx->unique++; 2138c2ecf20Sopenharmony_ci entry = dev->fib_list.next; 2148c2ecf20Sopenharmony_ci } else { 2158c2ecf20Sopenharmony_ci entry = entry->next; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci list_add_tail(&fibctx->next, &dev->fib_list); 2198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 2208c2ecf20Sopenharmony_ci if (copy_to_user(arg, &fibctx->unique, 2218c2ecf20Sopenharmony_ci sizeof(fibctx->unique))) { 2228c2ecf20Sopenharmony_ci status = -EFAULT; 2238c2ecf20Sopenharmony_ci } else { 2248c2ecf20Sopenharmony_ci status = 0; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci return status; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistruct compat_fib_ioctl { 2318c2ecf20Sopenharmony_ci u32 fibctx; 2328c2ecf20Sopenharmony_ci s32 wait; 2338c2ecf20Sopenharmony_ci compat_uptr_t fib; 2348c2ecf20Sopenharmony_ci}; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/** 2378c2ecf20Sopenharmony_ci * next_getadapter_fib - get the next fib 2388c2ecf20Sopenharmony_ci * @dev: adapter to use 2398c2ecf20Sopenharmony_ci * @arg: ioctl argument 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * This routine will get the next Fib, if available, from the AdapterFibContext 2428c2ecf20Sopenharmony_ci * passed in from the user. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic int next_getadapter_fib(struct aac_dev * dev, void __user *arg) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct fib_ioctl f; 2478c2ecf20Sopenharmony_ci struct fib *fib; 2488c2ecf20Sopenharmony_ci struct aac_fib_context *fibctx; 2498c2ecf20Sopenharmony_ci int status; 2508c2ecf20Sopenharmony_ci struct list_head * entry; 2518c2ecf20Sopenharmony_ci unsigned long flags; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (in_compat_syscall()) { 2548c2ecf20Sopenharmony_ci struct compat_fib_ioctl cf; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (copy_from_user(&cf, arg, sizeof(struct compat_fib_ioctl))) 2578c2ecf20Sopenharmony_ci return -EFAULT; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci f.fibctx = cf.fibctx; 2608c2ecf20Sopenharmony_ci f.wait = cf.wait; 2618c2ecf20Sopenharmony_ci f.fib = compat_ptr(cf.fib); 2628c2ecf20Sopenharmony_ci } else { 2638c2ecf20Sopenharmony_ci if (copy_from_user(&f, arg, sizeof(struct fib_ioctl))) 2648c2ecf20Sopenharmony_ci return -EFAULT; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci /* 2678c2ecf20Sopenharmony_ci * Verify that the HANDLE passed in was a valid AdapterFibContext 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * Search the list of AdapterFibContext addresses on the adapter 2708c2ecf20Sopenharmony_ci * to be sure this is a valid address 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flags); 2738c2ecf20Sopenharmony_ci entry = dev->fib_list.next; 2748c2ecf20Sopenharmony_ci fibctx = NULL; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci while (entry != &dev->fib_list) { 2778c2ecf20Sopenharmony_ci fibctx = list_entry(entry, struct aac_fib_context, next); 2788c2ecf20Sopenharmony_ci /* 2798c2ecf20Sopenharmony_ci * Extract the AdapterFibContext from the Input parameters. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci if (fibctx->unique == f.fibctx) { /* We found a winner */ 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci entry = entry->next; 2858c2ecf20Sopenharmony_ci fibctx = NULL; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci if (!fibctx) { 2888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 2898c2ecf20Sopenharmony_ci dprintk ((KERN_INFO "Fib Context not found\n")); 2908c2ecf20Sopenharmony_ci return -EINVAL; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || 2948c2ecf20Sopenharmony_ci (fibctx->size != sizeof(struct aac_fib_context))) { 2958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 2968c2ecf20Sopenharmony_ci dprintk ((KERN_INFO "Fib Context corrupt?\n")); 2978c2ecf20Sopenharmony_ci return -EINVAL; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci status = 0; 3008c2ecf20Sopenharmony_ci /* 3018c2ecf20Sopenharmony_ci * If there are no fibs to send back, then either wait or return 3028c2ecf20Sopenharmony_ci * -EAGAIN 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_cireturn_fib: 3058c2ecf20Sopenharmony_ci if (!list_empty(&fibctx->fib_list)) { 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * Pull the next fib from the fibs 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci entry = fibctx->fib_list.next; 3108c2ecf20Sopenharmony_ci list_del(entry); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci fib = list_entry(entry, struct fib, fiblink); 3138c2ecf20Sopenharmony_ci fibctx->count--; 3148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 3158c2ecf20Sopenharmony_ci if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) { 3168c2ecf20Sopenharmony_ci kfree(fib->hw_fib_va); 3178c2ecf20Sopenharmony_ci kfree(fib); 3188c2ecf20Sopenharmony_ci return -EFAULT; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci /* 3218c2ecf20Sopenharmony_ci * Free the space occupied by this copy of the fib. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci kfree(fib->hw_fib_va); 3248c2ecf20Sopenharmony_ci kfree(fib); 3258c2ecf20Sopenharmony_ci status = 0; 3268c2ecf20Sopenharmony_ci } else { 3278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 3288c2ecf20Sopenharmony_ci /* If someone killed the AIF aacraid thread, restart it */ 3298c2ecf20Sopenharmony_ci status = !dev->aif_thread; 3308c2ecf20Sopenharmony_ci if (status && !dev->in_reset && dev->queues && dev->fsa_dev) { 3318c2ecf20Sopenharmony_ci /* Be paranoid, be very paranoid! */ 3328c2ecf20Sopenharmony_ci kthread_stop(dev->thread); 3338c2ecf20Sopenharmony_ci ssleep(1); 3348c2ecf20Sopenharmony_ci dev->aif_thread = 0; 3358c2ecf20Sopenharmony_ci dev->thread = kthread_run(aac_command_thread, dev, 3368c2ecf20Sopenharmony_ci "%s", dev->name); 3378c2ecf20Sopenharmony_ci ssleep(1); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci if (f.wait) { 3408c2ecf20Sopenharmony_ci if (wait_for_completion_interruptible(&fibctx->completion) < 0) { 3418c2ecf20Sopenharmony_ci status = -ERESTARTSYS; 3428c2ecf20Sopenharmony_ci } else { 3438c2ecf20Sopenharmony_ci /* Lock again and retry */ 3448c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flags); 3458c2ecf20Sopenharmony_ci goto return_fib; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci } else { 3488c2ecf20Sopenharmony_ci status = -EAGAIN; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci fibctx->jiffies = jiffies/HZ; 3528c2ecf20Sopenharmony_ci return status; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ciint aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct fib *fib; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* 3608c2ecf20Sopenharmony_ci * First free any FIBs that have not been consumed. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci while (!list_empty(&fibctx->fib_list)) { 3638c2ecf20Sopenharmony_ci struct list_head * entry; 3648c2ecf20Sopenharmony_ci /* 3658c2ecf20Sopenharmony_ci * Pull the next fib from the fibs 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci entry = fibctx->fib_list.next; 3688c2ecf20Sopenharmony_ci list_del(entry); 3698c2ecf20Sopenharmony_ci fib = list_entry(entry, struct fib, fiblink); 3708c2ecf20Sopenharmony_ci fibctx->count--; 3718c2ecf20Sopenharmony_ci /* 3728c2ecf20Sopenharmony_ci * Free the space occupied by this copy of the fib. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci kfree(fib->hw_fib_va); 3758c2ecf20Sopenharmony_ci kfree(fib); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * Remove the Context from the AdapterFibContext List 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_ci list_del(&fibctx->next); 3818c2ecf20Sopenharmony_ci /* 3828c2ecf20Sopenharmony_ci * Invalidate context 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci fibctx->type = 0; 3858c2ecf20Sopenharmony_ci /* 3868c2ecf20Sopenharmony_ci * Free the space occupied by the Context 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci kfree(fibctx); 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/** 3938c2ecf20Sopenharmony_ci * close_getadapter_fib - close down user fib context 3948c2ecf20Sopenharmony_ci * @dev: adapter 3958c2ecf20Sopenharmony_ci * @arg: ioctl arguments 3968c2ecf20Sopenharmony_ci * 3978c2ecf20Sopenharmony_ci * This routine will close down the fibctx passed in from the user. 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int close_getadapter_fib(struct aac_dev * dev, void __user *arg) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct aac_fib_context *fibctx; 4038c2ecf20Sopenharmony_ci int status; 4048c2ecf20Sopenharmony_ci unsigned long flags; 4058c2ecf20Sopenharmony_ci struct list_head * entry; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* 4088c2ecf20Sopenharmony_ci * Verify that the HANDLE passed in was a valid AdapterFibContext 4098c2ecf20Sopenharmony_ci * 4108c2ecf20Sopenharmony_ci * Search the list of AdapterFibContext addresses on the adapter 4118c2ecf20Sopenharmony_ci * to be sure this is a valid address 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci entry = dev->fib_list.next; 4158c2ecf20Sopenharmony_ci fibctx = NULL; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci while(entry != &dev->fib_list) { 4188c2ecf20Sopenharmony_ci fibctx = list_entry(entry, struct aac_fib_context, next); 4198c2ecf20Sopenharmony_ci /* 4208c2ecf20Sopenharmony_ci * Extract the fibctx from the input parameters 4218c2ecf20Sopenharmony_ci */ 4228c2ecf20Sopenharmony_ci if (fibctx->unique == (u32)(uintptr_t)arg) /* We found a winner */ 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci entry = entry->next; 4258c2ecf20Sopenharmony_ci fibctx = NULL; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (!fibctx) 4298c2ecf20Sopenharmony_ci return 0; /* Already gone */ 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || 4328c2ecf20Sopenharmony_ci (fibctx->size != sizeof(struct aac_fib_context))) 4338c2ecf20Sopenharmony_ci return -EINVAL; 4348c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flags); 4358c2ecf20Sopenharmony_ci status = aac_close_fib_context(dev, fibctx); 4368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 4378c2ecf20Sopenharmony_ci return status; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci/** 4418c2ecf20Sopenharmony_ci * check_revision - close down user fib context 4428c2ecf20Sopenharmony_ci * @dev: adapter 4438c2ecf20Sopenharmony_ci * @arg: ioctl arguments 4448c2ecf20Sopenharmony_ci * 4458c2ecf20Sopenharmony_ci * This routine returns the driver version. 4468c2ecf20Sopenharmony_ci * Under Linux, there have been no version incompatibilities, so this is 4478c2ecf20Sopenharmony_ci * simple! 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int check_revision(struct aac_dev *dev, void __user *arg) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct revision response; 4538c2ecf20Sopenharmony_ci char *driver_version = aac_driver_version; 4548c2ecf20Sopenharmony_ci u32 version; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci response.compat = 1; 4578c2ecf20Sopenharmony_ci version = (simple_strtol(driver_version, 4588c2ecf20Sopenharmony_ci &driver_version, 10) << 24) | 0x00000400; 4598c2ecf20Sopenharmony_ci version += simple_strtol(driver_version + 1, &driver_version, 10) << 16; 4608c2ecf20Sopenharmony_ci version += simple_strtol(driver_version + 1, NULL, 10); 4618c2ecf20Sopenharmony_ci response.version = cpu_to_le32(version); 4628c2ecf20Sopenharmony_ci# ifdef AAC_DRIVER_BUILD 4638c2ecf20Sopenharmony_ci response.build = cpu_to_le32(AAC_DRIVER_BUILD); 4648c2ecf20Sopenharmony_ci# else 4658c2ecf20Sopenharmony_ci response.build = cpu_to_le32(9999); 4668c2ecf20Sopenharmony_ci# endif 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (copy_to_user(arg, &response, sizeof(response))) 4698c2ecf20Sopenharmony_ci return -EFAULT; 4708c2ecf20Sopenharmony_ci return 0; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci/** 4758c2ecf20Sopenharmony_ci * aac_send_raw_scb 4768c2ecf20Sopenharmony_ci * @dev: adapter is being processed 4778c2ecf20Sopenharmony_ci * @arg: arguments to the send call 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_cistatic int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct fib* srbfib; 4828c2ecf20Sopenharmony_ci int status; 4838c2ecf20Sopenharmony_ci struct aac_srb *srbcmd = NULL; 4848c2ecf20Sopenharmony_ci struct aac_hba_cmd_req *hbacmd = NULL; 4858c2ecf20Sopenharmony_ci struct user_aac_srb *user_srbcmd = NULL; 4868c2ecf20Sopenharmony_ci struct user_aac_srb __user *user_srb = arg; 4878c2ecf20Sopenharmony_ci struct aac_srb_reply __user *user_reply; 4888c2ecf20Sopenharmony_ci u32 chn; 4898c2ecf20Sopenharmony_ci u32 fibsize = 0; 4908c2ecf20Sopenharmony_ci u32 flags = 0; 4918c2ecf20Sopenharmony_ci s32 rcode = 0; 4928c2ecf20Sopenharmony_ci u32 data_dir; 4938c2ecf20Sopenharmony_ci void __user *sg_user[HBA_MAX_SG_EMBEDDED]; 4948c2ecf20Sopenharmony_ci void *sg_list[HBA_MAX_SG_EMBEDDED]; 4958c2ecf20Sopenharmony_ci u32 sg_count[HBA_MAX_SG_EMBEDDED]; 4968c2ecf20Sopenharmony_ci u32 sg_indx = 0; 4978c2ecf20Sopenharmony_ci u32 byte_count = 0; 4988c2ecf20Sopenharmony_ci u32 actual_fibsize64, actual_fibsize = 0; 4998c2ecf20Sopenharmony_ci int i; 5008c2ecf20Sopenharmony_ci int is_native_device; 5018c2ecf20Sopenharmony_ci u64 address; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (dev->in_reset) { 5058c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n")); 5068c2ecf20Sopenharmony_ci return -EBUSY; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)){ 5098c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 5108c2ecf20Sopenharmony_ci return -EPERM; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci /* 5138c2ecf20Sopenharmony_ci * Allocate and initialize a Fib then setup a SRB command 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ci if (!(srbfib = aac_fib_alloc(dev))) { 5168c2ecf20Sopenharmony_ci return -ENOMEM; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */ 5208c2ecf20Sopenharmony_ci if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){ 5218c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); 5228c2ecf20Sopenharmony_ci rcode = -EFAULT; 5238c2ecf20Sopenharmony_ci goto cleanup; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if ((fibsize < (sizeof(struct user_aac_srb) - sizeof(struct user_sgentry))) || 5278c2ecf20Sopenharmony_ci (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))) { 5288c2ecf20Sopenharmony_ci rcode = -EINVAL; 5298c2ecf20Sopenharmony_ci goto cleanup; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci user_srbcmd = memdup_user(user_srb, fibsize); 5338c2ecf20Sopenharmony_ci if (IS_ERR(user_srbcmd)) { 5348c2ecf20Sopenharmony_ci rcode = PTR_ERR(user_srbcmd); 5358c2ecf20Sopenharmony_ci user_srbcmd = NULL; 5368c2ecf20Sopenharmony_ci goto cleanup; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci flags = user_srbcmd->flags; /* from user in cpu order */ 5408c2ecf20Sopenharmony_ci switch (flags & (SRB_DataIn | SRB_DataOut)) { 5418c2ecf20Sopenharmony_ci case SRB_DataOut: 5428c2ecf20Sopenharmony_ci data_dir = DMA_TO_DEVICE; 5438c2ecf20Sopenharmony_ci break; 5448c2ecf20Sopenharmony_ci case (SRB_DataIn | SRB_DataOut): 5458c2ecf20Sopenharmony_ci data_dir = DMA_BIDIRECTIONAL; 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci case SRB_DataIn: 5488c2ecf20Sopenharmony_ci data_dir = DMA_FROM_DEVICE; 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci default: 5518c2ecf20Sopenharmony_ci data_dir = DMA_NONE; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci if (user_srbcmd->sg.count > ARRAY_SIZE(sg_list)) { 5548c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: too many sg entries %d\n", 5558c2ecf20Sopenharmony_ci user_srbcmd->sg.count)); 5568c2ecf20Sopenharmony_ci rcode = -EINVAL; 5578c2ecf20Sopenharmony_ci goto cleanup; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) { 5608c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid:SG with no direction specified\n")); 5618c2ecf20Sopenharmony_ci rcode = -EINVAL; 5628c2ecf20Sopenharmony_ci goto cleanup; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + 5658c2ecf20Sopenharmony_ci ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry)); 5668c2ecf20Sopenharmony_ci actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) * 5678c2ecf20Sopenharmony_ci (sizeof(struct sgentry64) - sizeof(struct sgentry)); 5688c2ecf20Sopenharmony_ci /* User made a mistake - should not continue */ 5698c2ecf20Sopenharmony_ci if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) { 5708c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Bad Size specified in " 5718c2ecf20Sopenharmony_ci "Raw SRB command calculated fibsize=%lu;%lu " 5728c2ecf20Sopenharmony_ci "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu " 5738c2ecf20Sopenharmony_ci "issued fibsize=%d\n", 5748c2ecf20Sopenharmony_ci actual_fibsize, actual_fibsize64, user_srbcmd->sg.count, 5758c2ecf20Sopenharmony_ci sizeof(struct aac_srb), sizeof(struct sgentry), 5768c2ecf20Sopenharmony_ci sizeof(struct sgentry64), fibsize)); 5778c2ecf20Sopenharmony_ci rcode = -EINVAL; 5788c2ecf20Sopenharmony_ci goto cleanup; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci chn = user_srbcmd->channel; 5828c2ecf20Sopenharmony_ci if (chn < AAC_MAX_BUSES && user_srbcmd->id < AAC_MAX_TARGETS && 5838c2ecf20Sopenharmony_ci dev->hba_map[chn][user_srbcmd->id].devtype == 5848c2ecf20Sopenharmony_ci AAC_DEVTYPE_NATIVE_RAW) { 5858c2ecf20Sopenharmony_ci is_native_device = 1; 5868c2ecf20Sopenharmony_ci hbacmd = (struct aac_hba_cmd_req *)srbfib->hw_fib_va; 5878c2ecf20Sopenharmony_ci memset(hbacmd, 0, 96); /* sizeof(*hbacmd) is not necessary */ 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* iu_type is a parameter of aac_hba_send */ 5908c2ecf20Sopenharmony_ci switch (data_dir) { 5918c2ecf20Sopenharmony_ci case DMA_TO_DEVICE: 5928c2ecf20Sopenharmony_ci hbacmd->byte1 = 2; 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci case DMA_FROM_DEVICE: 5958c2ecf20Sopenharmony_ci case DMA_BIDIRECTIONAL: 5968c2ecf20Sopenharmony_ci hbacmd->byte1 = 1; 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci case DMA_NONE: 5998c2ecf20Sopenharmony_ci default: 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci hbacmd->lun[1] = cpu_to_le32(user_srbcmd->lun); 6038c2ecf20Sopenharmony_ci hbacmd->it_nexus = dev->hba_map[chn][user_srbcmd->id].rmw_nexus; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* 6068c2ecf20Sopenharmony_ci * we fill in reply_qid later in aac_src_deliver_message 6078c2ecf20Sopenharmony_ci * we fill in iu_type, request_id later in aac_hba_send 6088c2ecf20Sopenharmony_ci * we fill in emb_data_desc_count, data_length later 6098c2ecf20Sopenharmony_ci * in sg list build 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci memcpy(hbacmd->cdb, user_srbcmd->cdb, sizeof(hbacmd->cdb)); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci address = (u64)srbfib->hw_error_pa; 6158c2ecf20Sopenharmony_ci hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); 6168c2ecf20Sopenharmony_ci hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff)); 6178c2ecf20Sopenharmony_ci hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); 6188c2ecf20Sopenharmony_ci hbacmd->emb_data_desc_count = 6198c2ecf20Sopenharmony_ci cpu_to_le32(user_srbcmd->sg.count); 6208c2ecf20Sopenharmony_ci srbfib->hbacmd_size = 64 + 6218c2ecf20Sopenharmony_ci user_srbcmd->sg.count * sizeof(struct aac_hba_sgl); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci } else { 6248c2ecf20Sopenharmony_ci is_native_device = 0; 6258c2ecf20Sopenharmony_ci aac_fib_init(srbfib); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* raw_srb FIB is not FastResponseCapable */ 6288c2ecf20Sopenharmony_ci srbfib->hw_fib_va->header.XferState &= 6298c2ecf20Sopenharmony_ci ~cpu_to_le32(FastResponseCapable); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci srbcmd = (struct aac_srb *) fib_data(srbfib); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci // Fix up srb for endian and force some values 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this 6368c2ecf20Sopenharmony_ci srbcmd->channel = cpu_to_le32(user_srbcmd->channel); 6378c2ecf20Sopenharmony_ci srbcmd->id = cpu_to_le32(user_srbcmd->id); 6388c2ecf20Sopenharmony_ci srbcmd->lun = cpu_to_le32(user_srbcmd->lun); 6398c2ecf20Sopenharmony_ci srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); 6408c2ecf20Sopenharmony_ci srbcmd->flags = cpu_to_le32(flags); 6418c2ecf20Sopenharmony_ci srbcmd->retry_limit = 0; // Obsolete parameter 6428c2ecf20Sopenharmony_ci srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); 6438c2ecf20Sopenharmony_ci memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci byte_count = 0; 6478c2ecf20Sopenharmony_ci if (is_native_device) { 6488c2ecf20Sopenharmony_ci struct user_sgmap *usg32 = &user_srbcmd->sg; 6498c2ecf20Sopenharmony_ci struct user_sgmap64 *usg64 = 6508c2ecf20Sopenharmony_ci (struct user_sgmap64 *)&user_srbcmd->sg; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci for (i = 0; i < usg32->count; i++) { 6538c2ecf20Sopenharmony_ci void *p; 6548c2ecf20Sopenharmony_ci u64 addr; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci sg_count[i] = (actual_fibsize64 == fibsize) ? 6578c2ecf20Sopenharmony_ci usg64->sg[i].count : usg32->sg[i].count; 6588c2ecf20Sopenharmony_ci if (sg_count[i] > 6598c2ecf20Sopenharmony_ci (dev->scsi_host_ptr->max_sectors << 9)) { 6608c2ecf20Sopenharmony_ci pr_err("aacraid: upsg->sg[%d].count=%u>%u\n", 6618c2ecf20Sopenharmony_ci i, sg_count[i], 6628c2ecf20Sopenharmony_ci dev->scsi_host_ptr->max_sectors << 9); 6638c2ecf20Sopenharmony_ci rcode = -EINVAL; 6648c2ecf20Sopenharmony_ci goto cleanup; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci p = kmalloc(sg_count[i], GFP_KERNEL); 6688c2ecf20Sopenharmony_ci if (!p) { 6698c2ecf20Sopenharmony_ci rcode = -ENOMEM; 6708c2ecf20Sopenharmony_ci goto cleanup; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (actual_fibsize64 == fibsize) { 6748c2ecf20Sopenharmony_ci addr = (u64)usg64->sg[i].addr[0]; 6758c2ecf20Sopenharmony_ci addr += ((u64)usg64->sg[i].addr[1]) << 32; 6768c2ecf20Sopenharmony_ci } else { 6778c2ecf20Sopenharmony_ci addr = (u64)usg32->sg[i].addr; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci sg_user[i] = (void __user *)(uintptr_t)addr; 6818c2ecf20Sopenharmony_ci sg_list[i] = p; // save so we can clean up later 6828c2ecf20Sopenharmony_ci sg_indx = i; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (flags & SRB_DataOut) { 6858c2ecf20Sopenharmony_ci if (copy_from_user(p, sg_user[i], 6868c2ecf20Sopenharmony_ci sg_count[i])) { 6878c2ecf20Sopenharmony_ci rcode = -EFAULT; 6888c2ecf20Sopenharmony_ci goto cleanup; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, p, sg_count[i], 6928c2ecf20Sopenharmony_ci data_dir); 6938c2ecf20Sopenharmony_ci hbacmd->sge[i].addr_hi = cpu_to_le32((u32)(addr>>32)); 6948c2ecf20Sopenharmony_ci hbacmd->sge[i].addr_lo = cpu_to_le32( 6958c2ecf20Sopenharmony_ci (u32)(addr & 0xffffffff)); 6968c2ecf20Sopenharmony_ci hbacmd->sge[i].len = cpu_to_le32(sg_count[i]); 6978c2ecf20Sopenharmony_ci hbacmd->sge[i].flags = 0; 6988c2ecf20Sopenharmony_ci byte_count += sg_count[i]; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (usg32->count > 0) /* embedded sglist */ 7028c2ecf20Sopenharmony_ci hbacmd->sge[usg32->count-1].flags = 7038c2ecf20Sopenharmony_ci cpu_to_le32(0x40000000); 7048c2ecf20Sopenharmony_ci hbacmd->data_length = cpu_to_le32(byte_count); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci status = aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, srbfib, 7078c2ecf20Sopenharmony_ci NULL, NULL); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci } else if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) { 7108c2ecf20Sopenharmony_ci struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg; 7118c2ecf20Sopenharmony_ci struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* 7148c2ecf20Sopenharmony_ci * This should also catch if user used the 32 bit sgmap 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_ci if (actual_fibsize64 == fibsize) { 7178c2ecf20Sopenharmony_ci actual_fibsize = actual_fibsize64; 7188c2ecf20Sopenharmony_ci for (i = 0; i < upsg->count; i++) { 7198c2ecf20Sopenharmony_ci u64 addr; 7208c2ecf20Sopenharmony_ci void* p; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci sg_count[i] = upsg->sg[i].count; 7238c2ecf20Sopenharmony_ci if (sg_count[i] > 7248c2ecf20Sopenharmony_ci ((dev->adapter_info.options & 7258c2ecf20Sopenharmony_ci AAC_OPT_NEW_COMM) ? 7268c2ecf20Sopenharmony_ci (dev->scsi_host_ptr->max_sectors << 9) : 7278c2ecf20Sopenharmony_ci 65536)) { 7288c2ecf20Sopenharmony_ci rcode = -EINVAL; 7298c2ecf20Sopenharmony_ci goto cleanup; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci p = kmalloc(sg_count[i], GFP_KERNEL); 7338c2ecf20Sopenharmony_ci if(!p) { 7348c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 7358c2ecf20Sopenharmony_ci sg_count[i], i, upsg->count)); 7368c2ecf20Sopenharmony_ci rcode = -ENOMEM; 7378c2ecf20Sopenharmony_ci goto cleanup; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci addr = (u64)upsg->sg[i].addr[0]; 7408c2ecf20Sopenharmony_ci addr += ((u64)upsg->sg[i].addr[1]) << 32; 7418c2ecf20Sopenharmony_ci sg_user[i] = (void __user *)(uintptr_t)addr; 7428c2ecf20Sopenharmony_ci sg_list[i] = p; // save so we can clean up later 7438c2ecf20Sopenharmony_ci sg_indx = i; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (flags & SRB_DataOut) { 7468c2ecf20Sopenharmony_ci if (copy_from_user(p, sg_user[i], 7478c2ecf20Sopenharmony_ci sg_count[i])){ 7488c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 7498c2ecf20Sopenharmony_ci rcode = -EFAULT; 7508c2ecf20Sopenharmony_ci goto cleanup; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, p, 7548c2ecf20Sopenharmony_ci sg_count[i], data_dir); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 7578c2ecf20Sopenharmony_ci psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 7588c2ecf20Sopenharmony_ci byte_count += sg_count[i]; 7598c2ecf20Sopenharmony_ci psg->sg[i].count = cpu_to_le32(sg_count[i]); 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci } else { 7628c2ecf20Sopenharmony_ci struct user_sgmap* usg; 7638c2ecf20Sopenharmony_ci usg = kmemdup(upsg, 7648c2ecf20Sopenharmony_ci actual_fibsize - sizeof(struct aac_srb) 7658c2ecf20Sopenharmony_ci + sizeof(struct sgmap), GFP_KERNEL); 7668c2ecf20Sopenharmony_ci if (!usg) { 7678c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); 7688c2ecf20Sopenharmony_ci rcode = -ENOMEM; 7698c2ecf20Sopenharmony_ci goto cleanup; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci actual_fibsize = actual_fibsize64; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci for (i = 0; i < usg->count; i++) { 7748c2ecf20Sopenharmony_ci u64 addr; 7758c2ecf20Sopenharmony_ci void* p; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci sg_count[i] = usg->sg[i].count; 7788c2ecf20Sopenharmony_ci if (sg_count[i] > 7798c2ecf20Sopenharmony_ci ((dev->adapter_info.options & 7808c2ecf20Sopenharmony_ci AAC_OPT_NEW_COMM) ? 7818c2ecf20Sopenharmony_ci (dev->scsi_host_ptr->max_sectors << 9) : 7828c2ecf20Sopenharmony_ci 65536)) { 7838c2ecf20Sopenharmony_ci kfree(usg); 7848c2ecf20Sopenharmony_ci rcode = -EINVAL; 7858c2ecf20Sopenharmony_ci goto cleanup; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci p = kmalloc(sg_count[i], GFP_KERNEL); 7898c2ecf20Sopenharmony_ci if(!p) { 7908c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 7918c2ecf20Sopenharmony_ci sg_count[i], i, usg->count)); 7928c2ecf20Sopenharmony_ci kfree(usg); 7938c2ecf20Sopenharmony_ci rcode = -ENOMEM; 7948c2ecf20Sopenharmony_ci goto cleanup; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci sg_user[i] = (void __user *)(uintptr_t)usg->sg[i].addr; 7978c2ecf20Sopenharmony_ci sg_list[i] = p; // save so we can clean up later 7988c2ecf20Sopenharmony_ci sg_indx = i; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (flags & SRB_DataOut) { 8018c2ecf20Sopenharmony_ci if (copy_from_user(p, sg_user[i], 8028c2ecf20Sopenharmony_ci sg_count[i])) { 8038c2ecf20Sopenharmony_ci kfree (usg); 8048c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 8058c2ecf20Sopenharmony_ci rcode = -EFAULT; 8068c2ecf20Sopenharmony_ci goto cleanup; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, p, 8108c2ecf20Sopenharmony_ci sg_count[i], data_dir); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 8138c2ecf20Sopenharmony_ci psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 8148c2ecf20Sopenharmony_ci byte_count += sg_count[i]; 8158c2ecf20Sopenharmony_ci psg->sg[i].count = cpu_to_le32(sg_count[i]); 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci kfree (usg); 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci srbcmd->count = cpu_to_le32(byte_count); 8208c2ecf20Sopenharmony_ci if (user_srbcmd->sg.count) 8218c2ecf20Sopenharmony_ci psg->count = cpu_to_le32(sg_indx+1); 8228c2ecf20Sopenharmony_ci else 8238c2ecf20Sopenharmony_ci psg->count = 0; 8248c2ecf20Sopenharmony_ci status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); 8258c2ecf20Sopenharmony_ci } else { 8268c2ecf20Sopenharmony_ci struct user_sgmap* upsg = &user_srbcmd->sg; 8278c2ecf20Sopenharmony_ci struct sgmap* psg = &srbcmd->sg; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (actual_fibsize64 == fibsize) { 8308c2ecf20Sopenharmony_ci struct user_sgmap64* usg = (struct user_sgmap64 *)upsg; 8318c2ecf20Sopenharmony_ci for (i = 0; i < upsg->count; i++) { 8328c2ecf20Sopenharmony_ci uintptr_t addr; 8338c2ecf20Sopenharmony_ci void* p; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci sg_count[i] = usg->sg[i].count; 8368c2ecf20Sopenharmony_ci if (sg_count[i] > 8378c2ecf20Sopenharmony_ci ((dev->adapter_info.options & 8388c2ecf20Sopenharmony_ci AAC_OPT_NEW_COMM) ? 8398c2ecf20Sopenharmony_ci (dev->scsi_host_ptr->max_sectors << 9) : 8408c2ecf20Sopenharmony_ci 65536)) { 8418c2ecf20Sopenharmony_ci rcode = -EINVAL; 8428c2ecf20Sopenharmony_ci goto cleanup; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci p = kmalloc(sg_count[i], GFP_KERNEL); 8458c2ecf20Sopenharmony_ci if (!p) { 8468c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 8478c2ecf20Sopenharmony_ci sg_count[i], i, usg->count)); 8488c2ecf20Sopenharmony_ci rcode = -ENOMEM; 8498c2ecf20Sopenharmony_ci goto cleanup; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci addr = (u64)usg->sg[i].addr[0]; 8528c2ecf20Sopenharmony_ci addr += ((u64)usg->sg[i].addr[1]) << 32; 8538c2ecf20Sopenharmony_ci sg_user[i] = (void __user *)addr; 8548c2ecf20Sopenharmony_ci sg_list[i] = p; // save so we can clean up later 8558c2ecf20Sopenharmony_ci sg_indx = i; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (flags & SRB_DataOut) { 8588c2ecf20Sopenharmony_ci if (copy_from_user(p, sg_user[i], 8598c2ecf20Sopenharmony_ci sg_count[i])){ 8608c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 8618c2ecf20Sopenharmony_ci rcode = -EFAULT; 8628c2ecf20Sopenharmony_ci goto cleanup; 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, p, 8668c2ecf20Sopenharmony_ci usg->sg[i].count, 8678c2ecf20Sopenharmony_ci data_dir); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff); 8708c2ecf20Sopenharmony_ci byte_count += usg->sg[i].count; 8718c2ecf20Sopenharmony_ci psg->sg[i].count = cpu_to_le32(sg_count[i]); 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci } else { 8748c2ecf20Sopenharmony_ci for (i = 0; i < upsg->count; i++) { 8758c2ecf20Sopenharmony_ci dma_addr_t addr; 8768c2ecf20Sopenharmony_ci void* p; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci sg_count[i] = upsg->sg[i].count; 8798c2ecf20Sopenharmony_ci if (sg_count[i] > 8808c2ecf20Sopenharmony_ci ((dev->adapter_info.options & 8818c2ecf20Sopenharmony_ci AAC_OPT_NEW_COMM) ? 8828c2ecf20Sopenharmony_ci (dev->scsi_host_ptr->max_sectors << 9) : 8838c2ecf20Sopenharmony_ci 65536)) { 8848c2ecf20Sopenharmony_ci rcode = -EINVAL; 8858c2ecf20Sopenharmony_ci goto cleanup; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci p = kmalloc(sg_count[i], GFP_KERNEL); 8888c2ecf20Sopenharmony_ci if (!p) { 8898c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 8908c2ecf20Sopenharmony_ci sg_count[i], i, upsg->count)); 8918c2ecf20Sopenharmony_ci rcode = -ENOMEM; 8928c2ecf20Sopenharmony_ci goto cleanup; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci sg_user[i] = (void __user *)(uintptr_t)upsg->sg[i].addr; 8958c2ecf20Sopenharmony_ci sg_list[i] = p; // save so we can clean up later 8968c2ecf20Sopenharmony_ci sg_indx = i; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (flags & SRB_DataOut) { 8998c2ecf20Sopenharmony_ci if (copy_from_user(p, sg_user[i], 9008c2ecf20Sopenharmony_ci sg_count[i])) { 9018c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 9028c2ecf20Sopenharmony_ci rcode = -EFAULT; 9038c2ecf20Sopenharmony_ci goto cleanup; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, p, 9078c2ecf20Sopenharmony_ci sg_count[i], data_dir); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci psg->sg[i].addr = cpu_to_le32(addr); 9108c2ecf20Sopenharmony_ci byte_count += sg_count[i]; 9118c2ecf20Sopenharmony_ci psg->sg[i].count = cpu_to_le32(sg_count[i]); 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci srbcmd->count = cpu_to_le32(byte_count); 9158c2ecf20Sopenharmony_ci if (user_srbcmd->sg.count) 9168c2ecf20Sopenharmony_ci psg->count = cpu_to_le32(sg_indx+1); 9178c2ecf20Sopenharmony_ci else 9188c2ecf20Sopenharmony_ci psg->count = 0; 9198c2ecf20Sopenharmony_ci status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL); 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (status == -ERESTARTSYS) { 9238c2ecf20Sopenharmony_ci rcode = -ERESTARTSYS; 9248c2ecf20Sopenharmony_ci goto cleanup; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (status != 0) { 9288c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); 9298c2ecf20Sopenharmony_ci rcode = -ENXIO; 9308c2ecf20Sopenharmony_ci goto cleanup; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (flags & SRB_DataIn) { 9348c2ecf20Sopenharmony_ci for(i = 0 ; i <= sg_indx; i++){ 9358c2ecf20Sopenharmony_ci if (copy_to_user(sg_user[i], sg_list[i], sg_count[i])) { 9368c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); 9378c2ecf20Sopenharmony_ci rcode = -EFAULT; 9388c2ecf20Sopenharmony_ci goto cleanup; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci user_reply = arg + fibsize; 9458c2ecf20Sopenharmony_ci if (is_native_device) { 9468c2ecf20Sopenharmony_ci struct aac_hba_resp *err = 9478c2ecf20Sopenharmony_ci &((struct aac_native_hba *)srbfib->hw_fib_va)->resp.err; 9488c2ecf20Sopenharmony_ci struct aac_srb_reply reply; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci memset(&reply, 0, sizeof(reply)); 9518c2ecf20Sopenharmony_ci reply.status = ST_OK; 9528c2ecf20Sopenharmony_ci if (srbfib->flags & FIB_CONTEXT_FLAG_FASTRESP) { 9538c2ecf20Sopenharmony_ci /* fast response */ 9548c2ecf20Sopenharmony_ci reply.srb_status = SRB_STATUS_SUCCESS; 9558c2ecf20Sopenharmony_ci reply.scsi_status = 0; 9568c2ecf20Sopenharmony_ci reply.data_xfer_length = byte_count; 9578c2ecf20Sopenharmony_ci reply.sense_data_size = 0; 9588c2ecf20Sopenharmony_ci memset(reply.sense_data, 0, AAC_SENSE_BUFFERSIZE); 9598c2ecf20Sopenharmony_ci } else { 9608c2ecf20Sopenharmony_ci reply.srb_status = err->service_response; 9618c2ecf20Sopenharmony_ci reply.scsi_status = err->status; 9628c2ecf20Sopenharmony_ci reply.data_xfer_length = byte_count - 9638c2ecf20Sopenharmony_ci le32_to_cpu(err->residual_count); 9648c2ecf20Sopenharmony_ci reply.sense_data_size = err->sense_response_data_len; 9658c2ecf20Sopenharmony_ci memcpy(reply.sense_data, err->sense_response_buf, 9668c2ecf20Sopenharmony_ci AAC_SENSE_BUFFERSIZE); 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci if (copy_to_user(user_reply, &reply, 9698c2ecf20Sopenharmony_ci sizeof(struct aac_srb_reply))) { 9708c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Copy to user failed\n")); 9718c2ecf20Sopenharmony_ci rcode = -EFAULT; 9728c2ecf20Sopenharmony_ci goto cleanup; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci } else { 9758c2ecf20Sopenharmony_ci struct aac_srb_reply *reply; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci reply = (struct aac_srb_reply *) fib_data(srbfib); 9788c2ecf20Sopenharmony_ci if (copy_to_user(user_reply, reply, 9798c2ecf20Sopenharmony_ci sizeof(struct aac_srb_reply))) { 9808c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Copy to user failed\n")); 9818c2ecf20Sopenharmony_ci rcode = -EFAULT; 9828c2ecf20Sopenharmony_ci goto cleanup; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cicleanup: 9878c2ecf20Sopenharmony_ci kfree(user_srbcmd); 9888c2ecf20Sopenharmony_ci if (rcode != -ERESTARTSYS) { 9898c2ecf20Sopenharmony_ci for (i = 0; i <= sg_indx; i++) 9908c2ecf20Sopenharmony_ci kfree(sg_list[i]); 9918c2ecf20Sopenharmony_ci aac_fib_complete(srbfib); 9928c2ecf20Sopenharmony_ci aac_fib_free(srbfib); 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci return rcode; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistruct aac_pci_info { 9998c2ecf20Sopenharmony_ci u32 bus; 10008c2ecf20Sopenharmony_ci u32 slot; 10018c2ecf20Sopenharmony_ci}; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic int aac_get_pci_info(struct aac_dev* dev, void __user *arg) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct aac_pci_info pci_info; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci pci_info.bus = dev->pdev->bus->number; 10098c2ecf20Sopenharmony_ci pci_info.slot = PCI_SLOT(dev->pdev->devfn); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { 10128c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); 10138c2ecf20Sopenharmony_ci return -EFAULT; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci return 0; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic int aac_get_hba_info(struct aac_dev *dev, void __user *arg) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci struct aac_hba_info hbainfo; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci memset(&hbainfo, 0, sizeof(hbainfo)); 10238c2ecf20Sopenharmony_ci hbainfo.adapter_number = (u8) dev->id; 10248c2ecf20Sopenharmony_ci hbainfo.system_io_bus_number = dev->pdev->bus->number; 10258c2ecf20Sopenharmony_ci hbainfo.device_number = (dev->pdev->devfn >> 3); 10268c2ecf20Sopenharmony_ci hbainfo.function_number = (dev->pdev->devfn & 0x0007); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci hbainfo.vendor_id = dev->pdev->vendor; 10298c2ecf20Sopenharmony_ci hbainfo.device_id = dev->pdev->device; 10308c2ecf20Sopenharmony_ci hbainfo.sub_vendor_id = dev->pdev->subsystem_vendor; 10318c2ecf20Sopenharmony_ci hbainfo.sub_system_id = dev->pdev->subsystem_device; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { 10348c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aacraid: Could not copy hba info\n")); 10358c2ecf20Sopenharmony_ci return -EFAULT; 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci return 0; 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistruct aac_reset_iop { 10428c2ecf20Sopenharmony_ci u8 reset_type; 10438c2ecf20Sopenharmony_ci}; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic int aac_send_reset_adapter(struct aac_dev *dev, void __user *arg) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct aac_reset_iop reset; 10488c2ecf20Sopenharmony_ci int retval; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (copy_from_user((void *)&reset, arg, sizeof(struct aac_reset_iop))) 10518c2ecf20Sopenharmony_ci return -EFAULT; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci dev->adapter_shutdown = 1; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci mutex_unlock(&dev->ioctl_mutex); 10568c2ecf20Sopenharmony_ci retval = aac_reset_adapter(dev, 0, reset.reset_type); 10578c2ecf20Sopenharmony_ci mutex_lock(&dev->ioctl_mutex); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci return retval; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ciint aac_do_ioctl(struct aac_dev *dev, unsigned int cmd, void __user *arg) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci int status; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci mutex_lock(&dev->ioctl_mutex); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (dev->adapter_shutdown) { 10698c2ecf20Sopenharmony_ci status = -EACCES; 10708c2ecf20Sopenharmony_ci goto cleanup; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* 10748c2ecf20Sopenharmony_ci * HBA gets first crack 10758c2ecf20Sopenharmony_ci */ 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci status = aac_dev_ioctl(dev, cmd, arg); 10788c2ecf20Sopenharmony_ci if (status != -ENOTTY) 10798c2ecf20Sopenharmony_ci goto cleanup; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci switch (cmd) { 10828c2ecf20Sopenharmony_ci case FSACTL_MINIPORT_REV_CHECK: 10838c2ecf20Sopenharmony_ci status = check_revision(dev, arg); 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci case FSACTL_SEND_LARGE_FIB: 10868c2ecf20Sopenharmony_ci case FSACTL_SENDFIB: 10878c2ecf20Sopenharmony_ci status = ioctl_send_fib(dev, arg); 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci case FSACTL_OPEN_GET_ADAPTER_FIB: 10908c2ecf20Sopenharmony_ci status = open_getadapter_fib(dev, arg); 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci case FSACTL_GET_NEXT_ADAPTER_FIB: 10938c2ecf20Sopenharmony_ci status = next_getadapter_fib(dev, arg); 10948c2ecf20Sopenharmony_ci break; 10958c2ecf20Sopenharmony_ci case FSACTL_CLOSE_GET_ADAPTER_FIB: 10968c2ecf20Sopenharmony_ci status = close_getadapter_fib(dev, arg); 10978c2ecf20Sopenharmony_ci break; 10988c2ecf20Sopenharmony_ci case FSACTL_SEND_RAW_SRB: 10998c2ecf20Sopenharmony_ci status = aac_send_raw_srb(dev,arg); 11008c2ecf20Sopenharmony_ci break; 11018c2ecf20Sopenharmony_ci case FSACTL_GET_PCI_INFO: 11028c2ecf20Sopenharmony_ci status = aac_get_pci_info(dev,arg); 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci case FSACTL_GET_HBA_INFO: 11058c2ecf20Sopenharmony_ci status = aac_get_hba_info(dev, arg); 11068c2ecf20Sopenharmony_ci break; 11078c2ecf20Sopenharmony_ci case FSACTL_RESET_IOP: 11088c2ecf20Sopenharmony_ci status = aac_send_reset_adapter(dev, arg); 11098c2ecf20Sopenharmony_ci break; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci default: 11128c2ecf20Sopenharmony_ci status = -ENOTTY; 11138c2ecf20Sopenharmony_ci break; 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cicleanup: 11178c2ecf20Sopenharmony_ci mutex_unlock(&dev->ioctl_mutex); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci return status; 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ci 1122