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