162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Adaptec AAC series RAID controller driver 462306a36Sopenharmony_ci * (c) Copyright 2001 Red Hat Inc. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * based on the old aacraid driver that is.. 762306a36Sopenharmony_ci * Adaptec aacraid device driver for Linux. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (c) 2000-2010 Adaptec, Inc. 1062306a36Sopenharmony_ci * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 1162306a36Sopenharmony_ci * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Module Name: 1462306a36Sopenharmony_ci * commctrl.c 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Abstract: Contains all routines for control of the AFA comm layer 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/types.h> 2262306a36Sopenharmony_ci#include <linux/pci.h> 2362306a36Sopenharmony_ci#include <linux/spinlock.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/completion.h> 2662306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2762306a36Sopenharmony_ci#include <linux/blkdev.h> 2862306a36Sopenharmony_ci#include <linux/compat.h> 2962306a36Sopenharmony_ci#include <linux/delay.h> /* ssleep prototype */ 3062306a36Sopenharmony_ci#include <linux/kthread.h> 3162306a36Sopenharmony_ci#include <linux/uaccess.h> 3262306a36Sopenharmony_ci#include <scsi/scsi_host.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "aacraid.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci# define AAC_DEBUG_PREAMBLE KERN_INFO 3762306a36Sopenharmony_ci# define AAC_DEBUG_POSTAMBLE 3862306a36Sopenharmony_ci/** 3962306a36Sopenharmony_ci * ioctl_send_fib - send a FIB from userspace 4062306a36Sopenharmony_ci * @dev: adapter is being processed 4162306a36Sopenharmony_ci * @arg: arguments to the ioctl call 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * This routine sends a fib to the adapter on behalf of a user level 4462306a36Sopenharmony_ci * program. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_cistatic int ioctl_send_fib(struct aac_dev * dev, void __user *arg) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct hw_fib * kfib; 4962306a36Sopenharmony_ci struct fib *fibptr; 5062306a36Sopenharmony_ci struct hw_fib * hw_fib = (struct hw_fib *)0; 5162306a36Sopenharmony_ci dma_addr_t hw_fib_pa = (dma_addr_t)0LL; 5262306a36Sopenharmony_ci unsigned int size, osize; 5362306a36Sopenharmony_ci int retval; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (dev->in_reset) { 5662306a36Sopenharmony_ci return -EBUSY; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci fibptr = aac_fib_alloc(dev); 5962306a36Sopenharmony_ci if(fibptr == NULL) { 6062306a36Sopenharmony_ci return -ENOMEM; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci kfib = fibptr->hw_fib_va; 6462306a36Sopenharmony_ci /* 6562306a36Sopenharmony_ci * First copy in the header so that we can check the size field. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) { 6862306a36Sopenharmony_ci aac_fib_free(fibptr); 6962306a36Sopenharmony_ci return -EFAULT; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci /* 7262306a36Sopenharmony_ci * Since we copy based on the fib header size, make sure that we 7362306a36Sopenharmony_ci * will not overrun the buffer when we copy the memory. Return 7462306a36Sopenharmony_ci * an error if we would. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci osize = size = le16_to_cpu(kfib->header.Size) + 7762306a36Sopenharmony_ci sizeof(struct aac_fibhdr); 7862306a36Sopenharmony_ci if (size < le16_to_cpu(kfib->header.SenderSize)) 7962306a36Sopenharmony_ci size = le16_to_cpu(kfib->header.SenderSize); 8062306a36Sopenharmony_ci if (size > dev->max_fib_size) { 8162306a36Sopenharmony_ci dma_addr_t daddr; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (size > 2048) { 8462306a36Sopenharmony_ci retval = -EINVAL; 8562306a36Sopenharmony_ci goto cleanup; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci kfib = dma_alloc_coherent(&dev->pdev->dev, size, &daddr, 8962306a36Sopenharmony_ci GFP_KERNEL); 9062306a36Sopenharmony_ci if (!kfib) { 9162306a36Sopenharmony_ci retval = -ENOMEM; 9262306a36Sopenharmony_ci goto cleanup; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* Highjack the hw_fib */ 9662306a36Sopenharmony_ci hw_fib = fibptr->hw_fib_va; 9762306a36Sopenharmony_ci hw_fib_pa = fibptr->hw_fib_pa; 9862306a36Sopenharmony_ci fibptr->hw_fib_va = kfib; 9962306a36Sopenharmony_ci fibptr->hw_fib_pa = daddr; 10062306a36Sopenharmony_ci memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size); 10162306a36Sopenharmony_ci memcpy(kfib, hw_fib, dev->max_fib_size); 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (copy_from_user(kfib, arg, size)) { 10562306a36Sopenharmony_ci retval = -EFAULT; 10662306a36Sopenharmony_ci goto cleanup; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Sanity check the second copy */ 11062306a36Sopenharmony_ci if ((osize != le16_to_cpu(kfib->header.Size) + 11162306a36Sopenharmony_ci sizeof(struct aac_fibhdr)) 11262306a36Sopenharmony_ci || (size < le16_to_cpu(kfib->header.SenderSize))) { 11362306a36Sopenharmony_ci retval = -EINVAL; 11462306a36Sopenharmony_ci goto cleanup; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) { 11862306a36Sopenharmony_ci aac_adapter_interrupt(dev); 11962306a36Sopenharmony_ci /* 12062306a36Sopenharmony_ci * Since we didn't really send a fib, zero out the state to allow 12162306a36Sopenharmony_ci * cleanup code not to assert. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci kfib->header.XferState = 0; 12462306a36Sopenharmony_ci } else { 12562306a36Sopenharmony_ci retval = aac_fib_send(le16_to_cpu(kfib->header.Command), fibptr, 12662306a36Sopenharmony_ci le16_to_cpu(kfib->header.Size) , FsaNormal, 12762306a36Sopenharmony_ci 1, 1, NULL, NULL); 12862306a36Sopenharmony_ci if (retval) { 12962306a36Sopenharmony_ci goto cleanup; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci if (aac_fib_complete(fibptr) != 0) { 13262306a36Sopenharmony_ci retval = -EINVAL; 13362306a36Sopenharmony_ci goto cleanup; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * Make sure that the size returned by the adapter (which includes 13862306a36Sopenharmony_ci * the header) is less than or equal to the size of a fib, so we 13962306a36Sopenharmony_ci * don't corrupt application data. Then copy that size to the user 14062306a36Sopenharmony_ci * buffer. (Don't try to add the header information again, since it 14162306a36Sopenharmony_ci * was already included by the adapter.) 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci retval = 0; 14562306a36Sopenharmony_ci if (copy_to_user(arg, (void *)kfib, size)) 14662306a36Sopenharmony_ci retval = -EFAULT; 14762306a36Sopenharmony_cicleanup: 14862306a36Sopenharmony_ci if (hw_fib) { 14962306a36Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, size, kfib, 15062306a36Sopenharmony_ci fibptr->hw_fib_pa); 15162306a36Sopenharmony_ci fibptr->hw_fib_pa = hw_fib_pa; 15262306a36Sopenharmony_ci fibptr->hw_fib_va = hw_fib; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci if (retval != -ERESTARTSYS) 15562306a36Sopenharmony_ci aac_fib_free(fibptr); 15662306a36Sopenharmony_ci return retval; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/** 16062306a36Sopenharmony_ci * open_getadapter_fib - Get the next fib 16162306a36Sopenharmony_ci * @dev: adapter is being processed 16262306a36Sopenharmony_ci * @arg: arguments to the open call 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * This routine will get the next Fib, if available, from the AdapterFibContext 16562306a36Sopenharmony_ci * passed in from the user. 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_cistatic int open_getadapter_fib(struct aac_dev * dev, void __user *arg) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct aac_fib_context * fibctx; 17062306a36Sopenharmony_ci int status; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); 17362306a36Sopenharmony_ci if (fibctx == NULL) { 17462306a36Sopenharmony_ci status = -ENOMEM; 17562306a36Sopenharmony_ci } else { 17662306a36Sopenharmony_ci unsigned long flags; 17762306a36Sopenharmony_ci struct list_head * entry; 17862306a36Sopenharmony_ci struct aac_fib_context * context; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; 18162306a36Sopenharmony_ci fibctx->size = sizeof(struct aac_fib_context); 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * Yes yes, I know this could be an index, but we have a 18462306a36Sopenharmony_ci * better guarantee of uniqueness for the locked loop below. 18562306a36Sopenharmony_ci * Without the aid of a persistent history, this also helps 18662306a36Sopenharmony_ci * reduce the chance that the opaque context would be reused. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF); 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * Initialize the mutex used to wait for the next AIF. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci init_completion(&fibctx->completion); 19362306a36Sopenharmony_ci fibctx->wait = 0; 19462306a36Sopenharmony_ci /* 19562306a36Sopenharmony_ci * Initialize the fibs and set the count of fibs on 19662306a36Sopenharmony_ci * the list to 0. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci fibctx->count = 0; 19962306a36Sopenharmony_ci INIT_LIST_HEAD(&fibctx->fib_list); 20062306a36Sopenharmony_ci fibctx->jiffies = jiffies/HZ; 20162306a36Sopenharmony_ci /* 20262306a36Sopenharmony_ci * Now add this context onto the adapter's 20362306a36Sopenharmony_ci * AdapterFibContext list. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flags); 20662306a36Sopenharmony_ci /* Ensure that we have a unique identifier */ 20762306a36Sopenharmony_ci entry = dev->fib_list.next; 20862306a36Sopenharmony_ci while (entry != &dev->fib_list) { 20962306a36Sopenharmony_ci context = list_entry(entry, struct aac_fib_context, next); 21062306a36Sopenharmony_ci if (context->unique == fibctx->unique) { 21162306a36Sopenharmony_ci /* Not unique (32 bits) */ 21262306a36Sopenharmony_ci fibctx->unique++; 21362306a36Sopenharmony_ci entry = dev->fib_list.next; 21462306a36Sopenharmony_ci } else { 21562306a36Sopenharmony_ci entry = entry->next; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci list_add_tail(&fibctx->next, &dev->fib_list); 21962306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 22062306a36Sopenharmony_ci if (copy_to_user(arg, &fibctx->unique, 22162306a36Sopenharmony_ci sizeof(fibctx->unique))) { 22262306a36Sopenharmony_ci status = -EFAULT; 22362306a36Sopenharmony_ci } else { 22462306a36Sopenharmony_ci status = 0; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci return status; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistruct compat_fib_ioctl { 23162306a36Sopenharmony_ci u32 fibctx; 23262306a36Sopenharmony_ci s32 wait; 23362306a36Sopenharmony_ci compat_uptr_t fib; 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/** 23762306a36Sopenharmony_ci * next_getadapter_fib - get the next fib 23862306a36Sopenharmony_ci * @dev: adapter to use 23962306a36Sopenharmony_ci * @arg: ioctl argument 24062306a36Sopenharmony_ci * 24162306a36Sopenharmony_ci * This routine will get the next Fib, if available, from the AdapterFibContext 24262306a36Sopenharmony_ci * passed in from the user. 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_cistatic int next_getadapter_fib(struct aac_dev * dev, void __user *arg) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct fib_ioctl f; 24762306a36Sopenharmony_ci struct fib *fib; 24862306a36Sopenharmony_ci struct aac_fib_context *fibctx; 24962306a36Sopenharmony_ci int status; 25062306a36Sopenharmony_ci struct list_head * entry; 25162306a36Sopenharmony_ci unsigned long flags; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (in_compat_syscall()) { 25462306a36Sopenharmony_ci struct compat_fib_ioctl cf; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (copy_from_user(&cf, arg, sizeof(struct compat_fib_ioctl))) 25762306a36Sopenharmony_ci return -EFAULT; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci f.fibctx = cf.fibctx; 26062306a36Sopenharmony_ci f.wait = cf.wait; 26162306a36Sopenharmony_ci f.fib = compat_ptr(cf.fib); 26262306a36Sopenharmony_ci } else { 26362306a36Sopenharmony_ci if (copy_from_user(&f, arg, sizeof(struct fib_ioctl))) 26462306a36Sopenharmony_ci return -EFAULT; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci /* 26762306a36Sopenharmony_ci * Verify that the HANDLE passed in was a valid AdapterFibContext 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * Search the list of AdapterFibContext addresses on the adapter 27062306a36Sopenharmony_ci * to be sure this is a valid address 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flags); 27362306a36Sopenharmony_ci entry = dev->fib_list.next; 27462306a36Sopenharmony_ci fibctx = NULL; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci while (entry != &dev->fib_list) { 27762306a36Sopenharmony_ci fibctx = list_entry(entry, struct aac_fib_context, next); 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * Extract the AdapterFibContext from the Input parameters. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_ci if (fibctx->unique == f.fibctx) { /* We found a winner */ 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci entry = entry->next; 28562306a36Sopenharmony_ci fibctx = NULL; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci if (!fibctx) { 28862306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 28962306a36Sopenharmony_ci dprintk ((KERN_INFO "Fib Context not found\n")); 29062306a36Sopenharmony_ci return -EINVAL; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || 29462306a36Sopenharmony_ci (fibctx->size != sizeof(struct aac_fib_context))) { 29562306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 29662306a36Sopenharmony_ci dprintk ((KERN_INFO "Fib Context corrupt?\n")); 29762306a36Sopenharmony_ci return -EINVAL; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci status = 0; 30062306a36Sopenharmony_ci /* 30162306a36Sopenharmony_ci * If there are no fibs to send back, then either wait or return 30262306a36Sopenharmony_ci * -EAGAIN 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_cireturn_fib: 30562306a36Sopenharmony_ci if (!list_empty(&fibctx->fib_list)) { 30662306a36Sopenharmony_ci /* 30762306a36Sopenharmony_ci * Pull the next fib from the fibs 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci entry = fibctx->fib_list.next; 31062306a36Sopenharmony_ci list_del(entry); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci fib = list_entry(entry, struct fib, fiblink); 31362306a36Sopenharmony_ci fibctx->count--; 31462306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 31562306a36Sopenharmony_ci if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) { 31662306a36Sopenharmony_ci kfree(fib->hw_fib_va); 31762306a36Sopenharmony_ci kfree(fib); 31862306a36Sopenharmony_ci return -EFAULT; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci /* 32162306a36Sopenharmony_ci * Free the space occupied by this copy of the fib. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci kfree(fib->hw_fib_va); 32462306a36Sopenharmony_ci kfree(fib); 32562306a36Sopenharmony_ci status = 0; 32662306a36Sopenharmony_ci } else { 32762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 32862306a36Sopenharmony_ci /* If someone killed the AIF aacraid thread, restart it */ 32962306a36Sopenharmony_ci status = !dev->aif_thread; 33062306a36Sopenharmony_ci if (status && !dev->in_reset && dev->queues && dev->fsa_dev) { 33162306a36Sopenharmony_ci /* Be paranoid, be very paranoid! */ 33262306a36Sopenharmony_ci kthread_stop(dev->thread); 33362306a36Sopenharmony_ci ssleep(1); 33462306a36Sopenharmony_ci dev->aif_thread = 0; 33562306a36Sopenharmony_ci dev->thread = kthread_run(aac_command_thread, dev, 33662306a36Sopenharmony_ci "%s", dev->name); 33762306a36Sopenharmony_ci ssleep(1); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci if (f.wait) { 34062306a36Sopenharmony_ci if (wait_for_completion_interruptible(&fibctx->completion) < 0) { 34162306a36Sopenharmony_ci status = -ERESTARTSYS; 34262306a36Sopenharmony_ci } else { 34362306a36Sopenharmony_ci /* Lock again and retry */ 34462306a36Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flags); 34562306a36Sopenharmony_ci goto return_fib; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci } else { 34862306a36Sopenharmony_ci status = -EAGAIN; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci fibctx->jiffies = jiffies/HZ; 35262306a36Sopenharmony_ci return status; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ciint aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct fib *fib; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* 36062306a36Sopenharmony_ci * First free any FIBs that have not been consumed. 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_ci while (!list_empty(&fibctx->fib_list)) { 36362306a36Sopenharmony_ci struct list_head * entry; 36462306a36Sopenharmony_ci /* 36562306a36Sopenharmony_ci * Pull the next fib from the fibs 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci entry = fibctx->fib_list.next; 36862306a36Sopenharmony_ci list_del(entry); 36962306a36Sopenharmony_ci fib = list_entry(entry, struct fib, fiblink); 37062306a36Sopenharmony_ci fibctx->count--; 37162306a36Sopenharmony_ci /* 37262306a36Sopenharmony_ci * Free the space occupied by this copy of the fib. 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_ci kfree(fib->hw_fib_va); 37562306a36Sopenharmony_ci kfree(fib); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci /* 37862306a36Sopenharmony_ci * Remove the Context from the AdapterFibContext List 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci list_del(&fibctx->next); 38162306a36Sopenharmony_ci /* 38262306a36Sopenharmony_ci * Invalidate context 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_ci fibctx->type = 0; 38562306a36Sopenharmony_ci /* 38662306a36Sopenharmony_ci * Free the space occupied by the Context 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_ci kfree(fibctx); 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci/** 39362306a36Sopenharmony_ci * close_getadapter_fib - close down user fib context 39462306a36Sopenharmony_ci * @dev: adapter 39562306a36Sopenharmony_ci * @arg: ioctl arguments 39662306a36Sopenharmony_ci * 39762306a36Sopenharmony_ci * This routine will close down the fibctx passed in from the user. 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int close_getadapter_fib(struct aac_dev * dev, void __user *arg) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct aac_fib_context *fibctx; 40362306a36Sopenharmony_ci int status; 40462306a36Sopenharmony_ci unsigned long flags; 40562306a36Sopenharmony_ci struct list_head * entry; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* 40862306a36Sopenharmony_ci * Verify that the HANDLE passed in was a valid AdapterFibContext 40962306a36Sopenharmony_ci * 41062306a36Sopenharmony_ci * Search the list of AdapterFibContext addresses on the adapter 41162306a36Sopenharmony_ci * to be sure this is a valid address 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci entry = dev->fib_list.next; 41562306a36Sopenharmony_ci fibctx = NULL; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci while(entry != &dev->fib_list) { 41862306a36Sopenharmony_ci fibctx = list_entry(entry, struct aac_fib_context, next); 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * Extract the fibctx from the input parameters 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_ci if (fibctx->unique == (u32)(uintptr_t)arg) /* We found a winner */ 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci entry = entry->next; 42562306a36Sopenharmony_ci fibctx = NULL; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (!fibctx) 42962306a36Sopenharmony_ci return 0; /* Already gone */ 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || 43262306a36Sopenharmony_ci (fibctx->size != sizeof(struct aac_fib_context))) 43362306a36Sopenharmony_ci return -EINVAL; 43462306a36Sopenharmony_ci spin_lock_irqsave(&dev->fib_lock, flags); 43562306a36Sopenharmony_ci status = aac_close_fib_context(dev, fibctx); 43662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->fib_lock, flags); 43762306a36Sopenharmony_ci return status; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci/** 44162306a36Sopenharmony_ci * check_revision - close down user fib context 44262306a36Sopenharmony_ci * @dev: adapter 44362306a36Sopenharmony_ci * @arg: ioctl arguments 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * This routine returns the driver version. 44662306a36Sopenharmony_ci * Under Linux, there have been no version incompatibilities, so this is 44762306a36Sopenharmony_ci * simple! 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic int check_revision(struct aac_dev *dev, void __user *arg) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct revision response; 45362306a36Sopenharmony_ci char *driver_version = aac_driver_version; 45462306a36Sopenharmony_ci u32 version; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci response.compat = 1; 45762306a36Sopenharmony_ci version = (simple_strtol(driver_version, 45862306a36Sopenharmony_ci &driver_version, 10) << 24) | 0x00000400; 45962306a36Sopenharmony_ci version += simple_strtol(driver_version + 1, &driver_version, 10) << 16; 46062306a36Sopenharmony_ci version += simple_strtol(driver_version + 1, NULL, 10); 46162306a36Sopenharmony_ci response.version = cpu_to_le32(version); 46262306a36Sopenharmony_ci# ifdef AAC_DRIVER_BUILD 46362306a36Sopenharmony_ci response.build = cpu_to_le32(AAC_DRIVER_BUILD); 46462306a36Sopenharmony_ci# else 46562306a36Sopenharmony_ci response.build = cpu_to_le32(9999); 46662306a36Sopenharmony_ci# endif 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (copy_to_user(arg, &response, sizeof(response))) 46962306a36Sopenharmony_ci return -EFAULT; 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/** 47562306a36Sopenharmony_ci * aac_send_raw_srb() 47662306a36Sopenharmony_ci * @dev: adapter is being processed 47762306a36Sopenharmony_ci * @arg: arguments to the send call 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_cistatic int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct fib* srbfib; 48262306a36Sopenharmony_ci int status; 48362306a36Sopenharmony_ci struct aac_srb *srbcmd = NULL; 48462306a36Sopenharmony_ci struct aac_hba_cmd_req *hbacmd = NULL; 48562306a36Sopenharmony_ci struct user_aac_srb *user_srbcmd = NULL; 48662306a36Sopenharmony_ci struct user_aac_srb __user *user_srb = arg; 48762306a36Sopenharmony_ci struct aac_srb_reply __user *user_reply; 48862306a36Sopenharmony_ci u32 chn; 48962306a36Sopenharmony_ci u32 fibsize = 0; 49062306a36Sopenharmony_ci u32 flags = 0; 49162306a36Sopenharmony_ci s32 rcode = 0; 49262306a36Sopenharmony_ci u32 data_dir; 49362306a36Sopenharmony_ci void __user *sg_user[HBA_MAX_SG_EMBEDDED]; 49462306a36Sopenharmony_ci void *sg_list[HBA_MAX_SG_EMBEDDED]; 49562306a36Sopenharmony_ci u32 sg_count[HBA_MAX_SG_EMBEDDED]; 49662306a36Sopenharmony_ci u32 sg_indx = 0; 49762306a36Sopenharmony_ci u32 byte_count = 0; 49862306a36Sopenharmony_ci u32 actual_fibsize64, actual_fibsize = 0; 49962306a36Sopenharmony_ci int i; 50062306a36Sopenharmony_ci int is_native_device; 50162306a36Sopenharmony_ci u64 address; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (dev->in_reset) { 50562306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n")); 50662306a36Sopenharmony_ci return -EBUSY; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)){ 50962306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 51062306a36Sopenharmony_ci return -EPERM; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci /* 51362306a36Sopenharmony_ci * Allocate and initialize a Fib then setup a SRB command 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_ci if (!(srbfib = aac_fib_alloc(dev))) { 51662306a36Sopenharmony_ci return -ENOMEM; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */ 52062306a36Sopenharmony_ci if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){ 52162306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); 52262306a36Sopenharmony_ci rcode = -EFAULT; 52362306a36Sopenharmony_ci goto cleanup; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if ((fibsize < (sizeof(struct user_aac_srb) - sizeof(struct user_sgentry))) || 52762306a36Sopenharmony_ci (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))) { 52862306a36Sopenharmony_ci rcode = -EINVAL; 52962306a36Sopenharmony_ci goto cleanup; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci user_srbcmd = memdup_user(user_srb, fibsize); 53362306a36Sopenharmony_ci if (IS_ERR(user_srbcmd)) { 53462306a36Sopenharmony_ci rcode = PTR_ERR(user_srbcmd); 53562306a36Sopenharmony_ci user_srbcmd = NULL; 53662306a36Sopenharmony_ci goto cleanup; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci flags = user_srbcmd->flags; /* from user in cpu order */ 54062306a36Sopenharmony_ci switch (flags & (SRB_DataIn | SRB_DataOut)) { 54162306a36Sopenharmony_ci case SRB_DataOut: 54262306a36Sopenharmony_ci data_dir = DMA_TO_DEVICE; 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci case (SRB_DataIn | SRB_DataOut): 54562306a36Sopenharmony_ci data_dir = DMA_BIDIRECTIONAL; 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci case SRB_DataIn: 54862306a36Sopenharmony_ci data_dir = DMA_FROM_DEVICE; 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci default: 55162306a36Sopenharmony_ci data_dir = DMA_NONE; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci if (user_srbcmd->sg.count > ARRAY_SIZE(sg_list)) { 55462306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: too many sg entries %d\n", 55562306a36Sopenharmony_ci user_srbcmd->sg.count)); 55662306a36Sopenharmony_ci rcode = -EINVAL; 55762306a36Sopenharmony_ci goto cleanup; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) { 56062306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid:SG with no direction specified\n")); 56162306a36Sopenharmony_ci rcode = -EINVAL; 56262306a36Sopenharmony_ci goto cleanup; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + 56562306a36Sopenharmony_ci ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry)); 56662306a36Sopenharmony_ci actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) * 56762306a36Sopenharmony_ci (sizeof(struct sgentry64) - sizeof(struct sgentry)); 56862306a36Sopenharmony_ci /* User made a mistake - should not continue */ 56962306a36Sopenharmony_ci if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) { 57062306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Bad Size specified in " 57162306a36Sopenharmony_ci "Raw SRB command calculated fibsize=%lu;%lu " 57262306a36Sopenharmony_ci "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu " 57362306a36Sopenharmony_ci "issued fibsize=%d\n", 57462306a36Sopenharmony_ci actual_fibsize, actual_fibsize64, user_srbcmd->sg.count, 57562306a36Sopenharmony_ci sizeof(struct aac_srb), sizeof(struct sgentry), 57662306a36Sopenharmony_ci sizeof(struct sgentry64), fibsize)); 57762306a36Sopenharmony_ci rcode = -EINVAL; 57862306a36Sopenharmony_ci goto cleanup; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci chn = user_srbcmd->channel; 58262306a36Sopenharmony_ci if (chn < AAC_MAX_BUSES && user_srbcmd->id < AAC_MAX_TARGETS && 58362306a36Sopenharmony_ci dev->hba_map[chn][user_srbcmd->id].devtype == 58462306a36Sopenharmony_ci AAC_DEVTYPE_NATIVE_RAW) { 58562306a36Sopenharmony_ci is_native_device = 1; 58662306a36Sopenharmony_ci hbacmd = (struct aac_hba_cmd_req *)srbfib->hw_fib_va; 58762306a36Sopenharmony_ci memset(hbacmd, 0, 96); /* sizeof(*hbacmd) is not necessary */ 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* iu_type is a parameter of aac_hba_send */ 59062306a36Sopenharmony_ci switch (data_dir) { 59162306a36Sopenharmony_ci case DMA_TO_DEVICE: 59262306a36Sopenharmony_ci hbacmd->byte1 = 2; 59362306a36Sopenharmony_ci break; 59462306a36Sopenharmony_ci case DMA_FROM_DEVICE: 59562306a36Sopenharmony_ci case DMA_BIDIRECTIONAL: 59662306a36Sopenharmony_ci hbacmd->byte1 = 1; 59762306a36Sopenharmony_ci break; 59862306a36Sopenharmony_ci case DMA_NONE: 59962306a36Sopenharmony_ci default: 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci hbacmd->lun[1] = cpu_to_le32(user_srbcmd->lun); 60362306a36Sopenharmony_ci hbacmd->it_nexus = dev->hba_map[chn][user_srbcmd->id].rmw_nexus; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* 60662306a36Sopenharmony_ci * we fill in reply_qid later in aac_src_deliver_message 60762306a36Sopenharmony_ci * we fill in iu_type, request_id later in aac_hba_send 60862306a36Sopenharmony_ci * we fill in emb_data_desc_count, data_length later 60962306a36Sopenharmony_ci * in sg list build 61062306a36Sopenharmony_ci */ 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci memcpy(hbacmd->cdb, user_srbcmd->cdb, sizeof(hbacmd->cdb)); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci address = (u64)srbfib->hw_error_pa; 61562306a36Sopenharmony_ci hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); 61662306a36Sopenharmony_ci hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff)); 61762306a36Sopenharmony_ci hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); 61862306a36Sopenharmony_ci hbacmd->emb_data_desc_count = 61962306a36Sopenharmony_ci cpu_to_le32(user_srbcmd->sg.count); 62062306a36Sopenharmony_ci srbfib->hbacmd_size = 64 + 62162306a36Sopenharmony_ci user_srbcmd->sg.count * sizeof(struct aac_hba_sgl); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci } else { 62462306a36Sopenharmony_ci is_native_device = 0; 62562306a36Sopenharmony_ci aac_fib_init(srbfib); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* raw_srb FIB is not FastResponseCapable */ 62862306a36Sopenharmony_ci srbfib->hw_fib_va->header.XferState &= 62962306a36Sopenharmony_ci ~cpu_to_le32(FastResponseCapable); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci srbcmd = (struct aac_srb *) fib_data(srbfib); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci // Fix up srb for endian and force some values 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this 63662306a36Sopenharmony_ci srbcmd->channel = cpu_to_le32(user_srbcmd->channel); 63762306a36Sopenharmony_ci srbcmd->id = cpu_to_le32(user_srbcmd->id); 63862306a36Sopenharmony_ci srbcmd->lun = cpu_to_le32(user_srbcmd->lun); 63962306a36Sopenharmony_ci srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); 64062306a36Sopenharmony_ci srbcmd->flags = cpu_to_le32(flags); 64162306a36Sopenharmony_ci srbcmd->retry_limit = 0; // Obsolete parameter 64262306a36Sopenharmony_ci srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); 64362306a36Sopenharmony_ci memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci byte_count = 0; 64762306a36Sopenharmony_ci if (is_native_device) { 64862306a36Sopenharmony_ci struct user_sgmap *usg32 = &user_srbcmd->sg; 64962306a36Sopenharmony_ci struct user_sgmap64 *usg64 = 65062306a36Sopenharmony_ci (struct user_sgmap64 *)&user_srbcmd->sg; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci for (i = 0; i < usg32->count; i++) { 65362306a36Sopenharmony_ci void *p; 65462306a36Sopenharmony_ci u64 addr; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci sg_count[i] = (actual_fibsize64 == fibsize) ? 65762306a36Sopenharmony_ci usg64->sg[i].count : usg32->sg[i].count; 65862306a36Sopenharmony_ci if (sg_count[i] > 65962306a36Sopenharmony_ci (dev->scsi_host_ptr->max_sectors << 9)) { 66062306a36Sopenharmony_ci pr_err("aacraid: upsg->sg[%d].count=%u>%u\n", 66162306a36Sopenharmony_ci i, sg_count[i], 66262306a36Sopenharmony_ci dev->scsi_host_ptr->max_sectors << 9); 66362306a36Sopenharmony_ci rcode = -EINVAL; 66462306a36Sopenharmony_ci goto cleanup; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci p = kmalloc(sg_count[i], GFP_KERNEL); 66862306a36Sopenharmony_ci if (!p) { 66962306a36Sopenharmony_ci rcode = -ENOMEM; 67062306a36Sopenharmony_ci goto cleanup; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (actual_fibsize64 == fibsize) { 67462306a36Sopenharmony_ci addr = (u64)usg64->sg[i].addr[0]; 67562306a36Sopenharmony_ci addr += ((u64)usg64->sg[i].addr[1]) << 32; 67662306a36Sopenharmony_ci } else { 67762306a36Sopenharmony_ci addr = (u64)usg32->sg[i].addr; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci sg_user[i] = (void __user *)(uintptr_t)addr; 68162306a36Sopenharmony_ci sg_list[i] = p; // save so we can clean up later 68262306a36Sopenharmony_ci sg_indx = i; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (flags & SRB_DataOut) { 68562306a36Sopenharmony_ci if (copy_from_user(p, sg_user[i], 68662306a36Sopenharmony_ci sg_count[i])) { 68762306a36Sopenharmony_ci rcode = -EFAULT; 68862306a36Sopenharmony_ci goto cleanup; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, p, sg_count[i], 69262306a36Sopenharmony_ci data_dir); 69362306a36Sopenharmony_ci hbacmd->sge[i].addr_hi = cpu_to_le32((u32)(addr>>32)); 69462306a36Sopenharmony_ci hbacmd->sge[i].addr_lo = cpu_to_le32( 69562306a36Sopenharmony_ci (u32)(addr & 0xffffffff)); 69662306a36Sopenharmony_ci hbacmd->sge[i].len = cpu_to_le32(sg_count[i]); 69762306a36Sopenharmony_ci hbacmd->sge[i].flags = 0; 69862306a36Sopenharmony_ci byte_count += sg_count[i]; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (usg32->count > 0) /* embedded sglist */ 70262306a36Sopenharmony_ci hbacmd->sge[usg32->count-1].flags = 70362306a36Sopenharmony_ci cpu_to_le32(0x40000000); 70462306a36Sopenharmony_ci hbacmd->data_length = cpu_to_le32(byte_count); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci status = aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, srbfib, 70762306a36Sopenharmony_ci NULL, NULL); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci } else if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) { 71062306a36Sopenharmony_ci struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg; 71162306a36Sopenharmony_ci struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* 71462306a36Sopenharmony_ci * This should also catch if user used the 32 bit sgmap 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_ci if (actual_fibsize64 == fibsize) { 71762306a36Sopenharmony_ci actual_fibsize = actual_fibsize64; 71862306a36Sopenharmony_ci for (i = 0; i < upsg->count; i++) { 71962306a36Sopenharmony_ci u64 addr; 72062306a36Sopenharmony_ci void* p; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci sg_count[i] = upsg->sg[i].count; 72362306a36Sopenharmony_ci if (sg_count[i] > 72462306a36Sopenharmony_ci ((dev->adapter_info.options & 72562306a36Sopenharmony_ci AAC_OPT_NEW_COMM) ? 72662306a36Sopenharmony_ci (dev->scsi_host_ptr->max_sectors << 9) : 72762306a36Sopenharmony_ci 65536)) { 72862306a36Sopenharmony_ci rcode = -EINVAL; 72962306a36Sopenharmony_ci goto cleanup; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci p = kmalloc(sg_count[i], GFP_KERNEL); 73362306a36Sopenharmony_ci if(!p) { 73462306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 73562306a36Sopenharmony_ci sg_count[i], i, upsg->count)); 73662306a36Sopenharmony_ci rcode = -ENOMEM; 73762306a36Sopenharmony_ci goto cleanup; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci addr = (u64)upsg->sg[i].addr[0]; 74062306a36Sopenharmony_ci addr += ((u64)upsg->sg[i].addr[1]) << 32; 74162306a36Sopenharmony_ci sg_user[i] = (void __user *)(uintptr_t)addr; 74262306a36Sopenharmony_ci sg_list[i] = p; // save so we can clean up later 74362306a36Sopenharmony_ci sg_indx = i; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (flags & SRB_DataOut) { 74662306a36Sopenharmony_ci if (copy_from_user(p, sg_user[i], 74762306a36Sopenharmony_ci sg_count[i])){ 74862306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 74962306a36Sopenharmony_ci rcode = -EFAULT; 75062306a36Sopenharmony_ci goto cleanup; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, p, 75462306a36Sopenharmony_ci sg_count[i], data_dir); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 75762306a36Sopenharmony_ci psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 75862306a36Sopenharmony_ci byte_count += sg_count[i]; 75962306a36Sopenharmony_ci psg->sg[i].count = cpu_to_le32(sg_count[i]); 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci } else { 76262306a36Sopenharmony_ci struct user_sgmap* usg; 76362306a36Sopenharmony_ci usg = kmemdup(upsg, 76462306a36Sopenharmony_ci actual_fibsize - sizeof(struct aac_srb) 76562306a36Sopenharmony_ci + sizeof(struct sgmap), GFP_KERNEL); 76662306a36Sopenharmony_ci if (!usg) { 76762306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); 76862306a36Sopenharmony_ci rcode = -ENOMEM; 76962306a36Sopenharmony_ci goto cleanup; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci actual_fibsize = actual_fibsize64; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci for (i = 0; i < usg->count; i++) { 77462306a36Sopenharmony_ci u64 addr; 77562306a36Sopenharmony_ci void* p; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci sg_count[i] = usg->sg[i].count; 77862306a36Sopenharmony_ci if (sg_count[i] > 77962306a36Sopenharmony_ci ((dev->adapter_info.options & 78062306a36Sopenharmony_ci AAC_OPT_NEW_COMM) ? 78162306a36Sopenharmony_ci (dev->scsi_host_ptr->max_sectors << 9) : 78262306a36Sopenharmony_ci 65536)) { 78362306a36Sopenharmony_ci kfree(usg); 78462306a36Sopenharmony_ci rcode = -EINVAL; 78562306a36Sopenharmony_ci goto cleanup; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci p = kmalloc(sg_count[i], GFP_KERNEL); 78962306a36Sopenharmony_ci if(!p) { 79062306a36Sopenharmony_ci dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 79162306a36Sopenharmony_ci sg_count[i], i, usg->count)); 79262306a36Sopenharmony_ci kfree(usg); 79362306a36Sopenharmony_ci rcode = -ENOMEM; 79462306a36Sopenharmony_ci goto cleanup; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci sg_user[i] = (void __user *)(uintptr_t)usg->sg[i].addr; 79762306a36Sopenharmony_ci sg_list[i] = p; // save so we can clean up later 79862306a36Sopenharmony_ci sg_indx = i; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (flags & SRB_DataOut) { 80162306a36Sopenharmony_ci if (copy_from_user(p, sg_user[i], 80262306a36Sopenharmony_ci sg_count[i])) { 80362306a36Sopenharmony_ci kfree (usg); 80462306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 80562306a36Sopenharmony_ci rcode = -EFAULT; 80662306a36Sopenharmony_ci goto cleanup; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, p, 81062306a36Sopenharmony_ci sg_count[i], data_dir); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 81362306a36Sopenharmony_ci psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 81462306a36Sopenharmony_ci byte_count += sg_count[i]; 81562306a36Sopenharmony_ci psg->sg[i].count = cpu_to_le32(sg_count[i]); 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci kfree (usg); 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci srbcmd->count = cpu_to_le32(byte_count); 82062306a36Sopenharmony_ci if (user_srbcmd->sg.count) 82162306a36Sopenharmony_ci psg->count = cpu_to_le32(sg_indx+1); 82262306a36Sopenharmony_ci else 82362306a36Sopenharmony_ci psg->count = 0; 82462306a36Sopenharmony_ci status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); 82562306a36Sopenharmony_ci } else { 82662306a36Sopenharmony_ci struct user_sgmap* upsg = &user_srbcmd->sg; 82762306a36Sopenharmony_ci struct sgmap* psg = &srbcmd->sg; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (actual_fibsize64 == fibsize) { 83062306a36Sopenharmony_ci struct user_sgmap64* usg = (struct user_sgmap64 *)upsg; 83162306a36Sopenharmony_ci for (i = 0; i < upsg->count; i++) { 83262306a36Sopenharmony_ci uintptr_t addr; 83362306a36Sopenharmony_ci void* p; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci sg_count[i] = usg->sg[i].count; 83662306a36Sopenharmony_ci if (sg_count[i] > 83762306a36Sopenharmony_ci ((dev->adapter_info.options & 83862306a36Sopenharmony_ci AAC_OPT_NEW_COMM) ? 83962306a36Sopenharmony_ci (dev->scsi_host_ptr->max_sectors << 9) : 84062306a36Sopenharmony_ci 65536)) { 84162306a36Sopenharmony_ci rcode = -EINVAL; 84262306a36Sopenharmony_ci goto cleanup; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci p = kmalloc(sg_count[i], GFP_KERNEL); 84562306a36Sopenharmony_ci if (!p) { 84662306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 84762306a36Sopenharmony_ci sg_count[i], i, usg->count)); 84862306a36Sopenharmony_ci rcode = -ENOMEM; 84962306a36Sopenharmony_ci goto cleanup; 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci addr = (u64)usg->sg[i].addr[0]; 85262306a36Sopenharmony_ci addr += ((u64)usg->sg[i].addr[1]) << 32; 85362306a36Sopenharmony_ci sg_user[i] = (void __user *)addr; 85462306a36Sopenharmony_ci sg_list[i] = p; // save so we can clean up later 85562306a36Sopenharmony_ci sg_indx = i; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (flags & SRB_DataOut) { 85862306a36Sopenharmony_ci if (copy_from_user(p, sg_user[i], 85962306a36Sopenharmony_ci sg_count[i])){ 86062306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 86162306a36Sopenharmony_ci rcode = -EFAULT; 86262306a36Sopenharmony_ci goto cleanup; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, p, 86662306a36Sopenharmony_ci usg->sg[i].count, 86762306a36Sopenharmony_ci data_dir); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff); 87062306a36Sopenharmony_ci byte_count += usg->sg[i].count; 87162306a36Sopenharmony_ci psg->sg[i].count = cpu_to_le32(sg_count[i]); 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci } else { 87462306a36Sopenharmony_ci for (i = 0; i < upsg->count; i++) { 87562306a36Sopenharmony_ci dma_addr_t addr; 87662306a36Sopenharmony_ci void* p; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci sg_count[i] = upsg->sg[i].count; 87962306a36Sopenharmony_ci if (sg_count[i] > 88062306a36Sopenharmony_ci ((dev->adapter_info.options & 88162306a36Sopenharmony_ci AAC_OPT_NEW_COMM) ? 88262306a36Sopenharmony_ci (dev->scsi_host_ptr->max_sectors << 9) : 88362306a36Sopenharmony_ci 65536)) { 88462306a36Sopenharmony_ci rcode = -EINVAL; 88562306a36Sopenharmony_ci goto cleanup; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci p = kmalloc(sg_count[i], GFP_KERNEL); 88862306a36Sopenharmony_ci if (!p) { 88962306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", 89062306a36Sopenharmony_ci sg_count[i], i, upsg->count)); 89162306a36Sopenharmony_ci rcode = -ENOMEM; 89262306a36Sopenharmony_ci goto cleanup; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci sg_user[i] = (void __user *)(uintptr_t)upsg->sg[i].addr; 89562306a36Sopenharmony_ci sg_list[i] = p; // save so we can clean up later 89662306a36Sopenharmony_ci sg_indx = i; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci if (flags & SRB_DataOut) { 89962306a36Sopenharmony_ci if (copy_from_user(p, sg_user[i], 90062306a36Sopenharmony_ci sg_count[i])) { 90162306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 90262306a36Sopenharmony_ci rcode = -EFAULT; 90362306a36Sopenharmony_ci goto cleanup; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, p, 90762306a36Sopenharmony_ci sg_count[i], data_dir); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci psg->sg[i].addr = cpu_to_le32(addr); 91062306a36Sopenharmony_ci byte_count += sg_count[i]; 91162306a36Sopenharmony_ci psg->sg[i].count = cpu_to_le32(sg_count[i]); 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci srbcmd->count = cpu_to_le32(byte_count); 91562306a36Sopenharmony_ci if (user_srbcmd->sg.count) 91662306a36Sopenharmony_ci psg->count = cpu_to_le32(sg_indx+1); 91762306a36Sopenharmony_ci else 91862306a36Sopenharmony_ci psg->count = 0; 91962306a36Sopenharmony_ci status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL); 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (status == -ERESTARTSYS) { 92362306a36Sopenharmony_ci rcode = -ERESTARTSYS; 92462306a36Sopenharmony_ci goto cleanup; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (status != 0) { 92862306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); 92962306a36Sopenharmony_ci rcode = -ENXIO; 93062306a36Sopenharmony_ci goto cleanup; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (flags & SRB_DataIn) { 93462306a36Sopenharmony_ci for(i = 0 ; i <= sg_indx; i++){ 93562306a36Sopenharmony_ci if (copy_to_user(sg_user[i], sg_list[i], sg_count[i])) { 93662306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); 93762306a36Sopenharmony_ci rcode = -EFAULT; 93862306a36Sopenharmony_ci goto cleanup; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci user_reply = arg + fibsize; 94562306a36Sopenharmony_ci if (is_native_device) { 94662306a36Sopenharmony_ci struct aac_hba_resp *err = 94762306a36Sopenharmony_ci &((struct aac_native_hba *)srbfib->hw_fib_va)->resp.err; 94862306a36Sopenharmony_ci struct aac_srb_reply reply; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci memset(&reply, 0, sizeof(reply)); 95162306a36Sopenharmony_ci reply.status = ST_OK; 95262306a36Sopenharmony_ci if (srbfib->flags & FIB_CONTEXT_FLAG_FASTRESP) { 95362306a36Sopenharmony_ci /* fast response */ 95462306a36Sopenharmony_ci reply.srb_status = SRB_STATUS_SUCCESS; 95562306a36Sopenharmony_ci reply.scsi_status = 0; 95662306a36Sopenharmony_ci reply.data_xfer_length = byte_count; 95762306a36Sopenharmony_ci reply.sense_data_size = 0; 95862306a36Sopenharmony_ci memset(reply.sense_data, 0, AAC_SENSE_BUFFERSIZE); 95962306a36Sopenharmony_ci } else { 96062306a36Sopenharmony_ci reply.srb_status = err->service_response; 96162306a36Sopenharmony_ci reply.scsi_status = err->status; 96262306a36Sopenharmony_ci reply.data_xfer_length = byte_count - 96362306a36Sopenharmony_ci le32_to_cpu(err->residual_count); 96462306a36Sopenharmony_ci reply.sense_data_size = err->sense_response_data_len; 96562306a36Sopenharmony_ci memcpy(reply.sense_data, err->sense_response_buf, 96662306a36Sopenharmony_ci AAC_SENSE_BUFFERSIZE); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci if (copy_to_user(user_reply, &reply, 96962306a36Sopenharmony_ci sizeof(struct aac_srb_reply))) { 97062306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Copy to user failed\n")); 97162306a36Sopenharmony_ci rcode = -EFAULT; 97262306a36Sopenharmony_ci goto cleanup; 97362306a36Sopenharmony_ci } 97462306a36Sopenharmony_ci } else { 97562306a36Sopenharmony_ci struct aac_srb_reply *reply; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci reply = (struct aac_srb_reply *) fib_data(srbfib); 97862306a36Sopenharmony_ci if (copy_to_user(user_reply, reply, 97962306a36Sopenharmony_ci sizeof(struct aac_srb_reply))) { 98062306a36Sopenharmony_ci dprintk((KERN_DEBUG"aacraid: Copy to user failed\n")); 98162306a36Sopenharmony_ci rcode = -EFAULT; 98262306a36Sopenharmony_ci goto cleanup; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cicleanup: 98762306a36Sopenharmony_ci kfree(user_srbcmd); 98862306a36Sopenharmony_ci if (rcode != -ERESTARTSYS) { 98962306a36Sopenharmony_ci for (i = 0; i <= sg_indx; i++) 99062306a36Sopenharmony_ci kfree(sg_list[i]); 99162306a36Sopenharmony_ci aac_fib_complete(srbfib); 99262306a36Sopenharmony_ci aac_fib_free(srbfib); 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci return rcode; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistruct aac_pci_info { 99962306a36Sopenharmony_ci u32 bus; 100062306a36Sopenharmony_ci u32 slot; 100162306a36Sopenharmony_ci}; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic int aac_get_pci_info(struct aac_dev* dev, void __user *arg) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci struct aac_pci_info pci_info; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci pci_info.bus = dev->pdev->bus->number; 100962306a36Sopenharmony_ci pci_info.slot = PCI_SLOT(dev->pdev->devfn); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { 101262306a36Sopenharmony_ci dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); 101362306a36Sopenharmony_ci return -EFAULT; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci return 0; 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic int aac_get_hba_info(struct aac_dev *dev, void __user *arg) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci struct aac_hba_info hbainfo; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci memset(&hbainfo, 0, sizeof(hbainfo)); 102362306a36Sopenharmony_ci hbainfo.adapter_number = (u8) dev->id; 102462306a36Sopenharmony_ci hbainfo.system_io_bus_number = dev->pdev->bus->number; 102562306a36Sopenharmony_ci hbainfo.device_number = (dev->pdev->devfn >> 3); 102662306a36Sopenharmony_ci hbainfo.function_number = (dev->pdev->devfn & 0x0007); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci hbainfo.vendor_id = dev->pdev->vendor; 102962306a36Sopenharmony_ci hbainfo.device_id = dev->pdev->device; 103062306a36Sopenharmony_ci hbainfo.sub_vendor_id = dev->pdev->subsystem_vendor; 103162306a36Sopenharmony_ci hbainfo.sub_system_id = dev->pdev->subsystem_device; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { 103462306a36Sopenharmony_ci dprintk((KERN_DEBUG "aacraid: Could not copy hba info\n")); 103562306a36Sopenharmony_ci return -EFAULT; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci return 0; 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistruct aac_reset_iop { 104262306a36Sopenharmony_ci u8 reset_type; 104362306a36Sopenharmony_ci}; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_cistatic int aac_send_reset_adapter(struct aac_dev *dev, void __user *arg) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci struct aac_reset_iop reset; 104862306a36Sopenharmony_ci int retval; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (copy_from_user((void *)&reset, arg, sizeof(struct aac_reset_iop))) 105162306a36Sopenharmony_ci return -EFAULT; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci dev->adapter_shutdown = 1; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci mutex_unlock(&dev->ioctl_mutex); 105662306a36Sopenharmony_ci retval = aac_reset_adapter(dev, 0, reset.reset_type); 105762306a36Sopenharmony_ci mutex_lock(&dev->ioctl_mutex); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci return retval; 106062306a36Sopenharmony_ci} 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ciint aac_do_ioctl(struct aac_dev *dev, unsigned int cmd, void __user *arg) 106362306a36Sopenharmony_ci{ 106462306a36Sopenharmony_ci int status; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci mutex_lock(&dev->ioctl_mutex); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci if (dev->adapter_shutdown) { 106962306a36Sopenharmony_ci status = -EACCES; 107062306a36Sopenharmony_ci goto cleanup; 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* 107462306a36Sopenharmony_ci * HBA gets first crack 107562306a36Sopenharmony_ci */ 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci status = aac_dev_ioctl(dev, cmd, arg); 107862306a36Sopenharmony_ci if (status != -ENOTTY) 107962306a36Sopenharmony_ci goto cleanup; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci switch (cmd) { 108262306a36Sopenharmony_ci case FSACTL_MINIPORT_REV_CHECK: 108362306a36Sopenharmony_ci status = check_revision(dev, arg); 108462306a36Sopenharmony_ci break; 108562306a36Sopenharmony_ci case FSACTL_SEND_LARGE_FIB: 108662306a36Sopenharmony_ci case FSACTL_SENDFIB: 108762306a36Sopenharmony_ci status = ioctl_send_fib(dev, arg); 108862306a36Sopenharmony_ci break; 108962306a36Sopenharmony_ci case FSACTL_OPEN_GET_ADAPTER_FIB: 109062306a36Sopenharmony_ci status = open_getadapter_fib(dev, arg); 109162306a36Sopenharmony_ci break; 109262306a36Sopenharmony_ci case FSACTL_GET_NEXT_ADAPTER_FIB: 109362306a36Sopenharmony_ci status = next_getadapter_fib(dev, arg); 109462306a36Sopenharmony_ci break; 109562306a36Sopenharmony_ci case FSACTL_CLOSE_GET_ADAPTER_FIB: 109662306a36Sopenharmony_ci status = close_getadapter_fib(dev, arg); 109762306a36Sopenharmony_ci break; 109862306a36Sopenharmony_ci case FSACTL_SEND_RAW_SRB: 109962306a36Sopenharmony_ci status = aac_send_raw_srb(dev,arg); 110062306a36Sopenharmony_ci break; 110162306a36Sopenharmony_ci case FSACTL_GET_PCI_INFO: 110262306a36Sopenharmony_ci status = aac_get_pci_info(dev,arg); 110362306a36Sopenharmony_ci break; 110462306a36Sopenharmony_ci case FSACTL_GET_HBA_INFO: 110562306a36Sopenharmony_ci status = aac_get_hba_info(dev, arg); 110662306a36Sopenharmony_ci break; 110762306a36Sopenharmony_ci case FSACTL_RESET_IOP: 110862306a36Sopenharmony_ci status = aac_send_reset_adapter(dev, arg); 110962306a36Sopenharmony_ci break; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci default: 111262306a36Sopenharmony_ci status = -ENOTTY; 111362306a36Sopenharmony_ci break; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cicleanup: 111762306a36Sopenharmony_ci mutex_unlock(&dev->ioctl_mutex); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci return status; 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 1122