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 *  dpcsup.c
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Abstract: All DPC processing routines for the cyclone board occur here.
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/spinlock.h>
238c2ecf20Sopenharmony_ci#include <linux/slab.h>
248c2ecf20Sopenharmony_ci#include <linux/completion.h>
258c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "aacraid.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/**
308c2ecf20Sopenharmony_ci *	aac_response_normal	-	Handle command replies
318c2ecf20Sopenharmony_ci *	@q: Queue to read from
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci *	This DPC routine will be run when the adapter interrupts us to let us
348c2ecf20Sopenharmony_ci *	know there is a response on our normal priority queue. We will pull off
358c2ecf20Sopenharmony_ci *	all QE there are and wake up all the waiters before exiting. We will
368c2ecf20Sopenharmony_ci *	take a spinlock out on the queue before operating on it.
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciunsigned int aac_response_normal(struct aac_queue * q)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct aac_dev * dev = q->dev;
428c2ecf20Sopenharmony_ci	struct aac_entry *entry;
438c2ecf20Sopenharmony_ci	struct hw_fib * hwfib;
448c2ecf20Sopenharmony_ci	struct fib * fib;
458c2ecf20Sopenharmony_ci	int consumed = 0;
468c2ecf20Sopenharmony_ci	unsigned long flags, mflags;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	spin_lock_irqsave(q->lock, flags);
498c2ecf20Sopenharmony_ci	/*
508c2ecf20Sopenharmony_ci	 *	Keep pulling response QEs off the response queue and waking
518c2ecf20Sopenharmony_ci	 *	up the waiters until there are no more QEs. We then return
528c2ecf20Sopenharmony_ci	 *	back to the system. If no response was requested we just
538c2ecf20Sopenharmony_ci	 *	deallocate the Fib here and continue.
548c2ecf20Sopenharmony_ci	 */
558c2ecf20Sopenharmony_ci	while(aac_consumer_get(dev, q, &entry))
568c2ecf20Sopenharmony_ci	{
578c2ecf20Sopenharmony_ci		int fast;
588c2ecf20Sopenharmony_ci		u32 index = le32_to_cpu(entry->addr);
598c2ecf20Sopenharmony_ci		fast = index & 0x01;
608c2ecf20Sopenharmony_ci		fib = &dev->fibs[index >> 2];
618c2ecf20Sopenharmony_ci		hwfib = fib->hw_fib_va;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci		aac_consumer_free(dev, q, HostNormRespQueue);
648c2ecf20Sopenharmony_ci		/*
658c2ecf20Sopenharmony_ci		 *	Remove this fib from the Outstanding I/O queue.
668c2ecf20Sopenharmony_ci		 *	But only if it has not already been timed out.
678c2ecf20Sopenharmony_ci		 *
688c2ecf20Sopenharmony_ci		 *	If the fib has been timed out already, then just
698c2ecf20Sopenharmony_ci		 *	continue. The caller has already been notified that
708c2ecf20Sopenharmony_ci		 *	the fib timed out.
718c2ecf20Sopenharmony_ci		 */
728c2ecf20Sopenharmony_ci		atomic_dec(&dev->queues->queue[AdapNormCmdQueue].numpending);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
758c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(q->lock, flags);
768c2ecf20Sopenharmony_ci			aac_fib_complete(fib);
778c2ecf20Sopenharmony_ci			aac_fib_free(fib);
788c2ecf20Sopenharmony_ci			spin_lock_irqsave(q->lock, flags);
798c2ecf20Sopenharmony_ci			continue;
808c2ecf20Sopenharmony_ci		}
818c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(q->lock, flags);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		if (fast) {
848c2ecf20Sopenharmony_ci			/*
858c2ecf20Sopenharmony_ci			 *	Doctor the fib
868c2ecf20Sopenharmony_ci			 */
878c2ecf20Sopenharmony_ci			*(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
888c2ecf20Sopenharmony_ci			hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
898c2ecf20Sopenharmony_ci			fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
908c2ecf20Sopenharmony_ci		}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci		FIB_COUNTER_INCREMENT(aac_config.FibRecved);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
958c2ecf20Sopenharmony_ci		{
968c2ecf20Sopenharmony_ci			__le32 *pstatus = (__le32 *)hwfib->data;
978c2ecf20Sopenharmony_ci			if (*pstatus & cpu_to_le32(0xffff0000))
988c2ecf20Sopenharmony_ci				*pstatus = cpu_to_le32(ST_OK);
998c2ecf20Sopenharmony_ci		}
1008c2ecf20Sopenharmony_ci		if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async))
1018c2ecf20Sopenharmony_ci		{
1028c2ecf20Sopenharmony_ci			if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected)) {
1038c2ecf20Sopenharmony_ci				FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved);
1048c2ecf20Sopenharmony_ci			} else {
1058c2ecf20Sopenharmony_ci				FIB_COUNTER_INCREMENT(aac_config.AsyncRecved);
1068c2ecf20Sopenharmony_ci			}
1078c2ecf20Sopenharmony_ci			/*
1088c2ecf20Sopenharmony_ci			 *	NOTE:  we cannot touch the fib after this
1098c2ecf20Sopenharmony_ci			 *	    call, because it may have been deallocated.
1108c2ecf20Sopenharmony_ci			 */
1118c2ecf20Sopenharmony_ci			fib->callback(fib->callback_data, fib);
1128c2ecf20Sopenharmony_ci		} else {
1138c2ecf20Sopenharmony_ci			unsigned long flagv;
1148c2ecf20Sopenharmony_ci			spin_lock_irqsave(&fib->event_lock, flagv);
1158c2ecf20Sopenharmony_ci			if (!fib->done) {
1168c2ecf20Sopenharmony_ci				fib->done = 1;
1178c2ecf20Sopenharmony_ci				complete(&fib->event_wait);
1188c2ecf20Sopenharmony_ci			}
1198c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&fib->event_lock, flagv);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci			spin_lock_irqsave(&dev->manage_lock, mflags);
1228c2ecf20Sopenharmony_ci			dev->management_fib_count--;
1238c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&dev->manage_lock, mflags);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci			FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
1268c2ecf20Sopenharmony_ci			if (fib->done == 2) {
1278c2ecf20Sopenharmony_ci				spin_lock_irqsave(&fib->event_lock, flagv);
1288c2ecf20Sopenharmony_ci				fib->done = 0;
1298c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&fib->event_lock, flagv);
1308c2ecf20Sopenharmony_ci				aac_fib_complete(fib);
1318c2ecf20Sopenharmony_ci				aac_fib_free(fib);
1328c2ecf20Sopenharmony_ci			}
1338c2ecf20Sopenharmony_ci		}
1348c2ecf20Sopenharmony_ci		consumed++;
1358c2ecf20Sopenharmony_ci		spin_lock_irqsave(q->lock, flags);
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (consumed > aac_config.peak_fibs)
1398c2ecf20Sopenharmony_ci		aac_config.peak_fibs = consumed;
1408c2ecf20Sopenharmony_ci	if (consumed == 0)
1418c2ecf20Sopenharmony_ci		aac_config.zero_fibs++;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(q->lock, flags);
1448c2ecf20Sopenharmony_ci	return 0;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci/**
1498c2ecf20Sopenharmony_ci *	aac_command_normal	-	handle commands
1508c2ecf20Sopenharmony_ci *	@q: queue to process
1518c2ecf20Sopenharmony_ci *
1528c2ecf20Sopenharmony_ci *	This DPC routine will be queued when the adapter interrupts us to
1538c2ecf20Sopenharmony_ci *	let us know there is a command on our normal priority queue. We will
1548c2ecf20Sopenharmony_ci *	pull off all QE there are and wake up all the waiters before exiting.
1558c2ecf20Sopenharmony_ci *	We will take a spinlock out on the queue before operating on it.
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ciunsigned int aac_command_normal(struct aac_queue *q)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	struct aac_dev * dev = q->dev;
1618c2ecf20Sopenharmony_ci	struct aac_entry *entry;
1628c2ecf20Sopenharmony_ci	unsigned long flags;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	spin_lock_irqsave(q->lock, flags);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/*
1678c2ecf20Sopenharmony_ci	 *	Keep pulling response QEs off the response queue and waking
1688c2ecf20Sopenharmony_ci	 *	up the waiters until there are no more QEs. We then return
1698c2ecf20Sopenharmony_ci	 *	back to the system.
1708c2ecf20Sopenharmony_ci	 */
1718c2ecf20Sopenharmony_ci	while(aac_consumer_get(dev, q, &entry))
1728c2ecf20Sopenharmony_ci	{
1738c2ecf20Sopenharmony_ci		struct fib fibctx;
1748c2ecf20Sopenharmony_ci		struct hw_fib * hw_fib;
1758c2ecf20Sopenharmony_ci		u32 index;
1768c2ecf20Sopenharmony_ci		struct fib *fib = &fibctx;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		index = le32_to_cpu(entry->addr) / sizeof(struct hw_fib);
1798c2ecf20Sopenharmony_ci		hw_fib = &dev->aif_base_va[index];
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci		/*
1828c2ecf20Sopenharmony_ci		 *	Allocate a FIB at all costs. For non queued stuff
1838c2ecf20Sopenharmony_ci		 *	we can just use the stack so we are happy. We need
1848c2ecf20Sopenharmony_ci		 *	a fib object in order to manage the linked lists
1858c2ecf20Sopenharmony_ci		 */
1868c2ecf20Sopenharmony_ci		if (dev->aif_thread)
1878c2ecf20Sopenharmony_ci			if((fib = kmalloc(sizeof(struct fib), GFP_ATOMIC)) == NULL)
1888c2ecf20Sopenharmony_ci				fib = &fibctx;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci		memset(fib, 0, sizeof(struct fib));
1918c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&fib->fiblink);
1928c2ecf20Sopenharmony_ci		fib->type = FSAFS_NTC_FIB_CONTEXT;
1938c2ecf20Sopenharmony_ci		fib->size = sizeof(struct fib);
1948c2ecf20Sopenharmony_ci		fib->hw_fib_va = hw_fib;
1958c2ecf20Sopenharmony_ci		fib->data = hw_fib->data;
1968c2ecf20Sopenharmony_ci		fib->dev = dev;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci		if (dev->aif_thread && fib != &fibctx) {
2008c2ecf20Sopenharmony_ci		        list_add_tail(&fib->fiblink, &q->cmdq);
2018c2ecf20Sopenharmony_ci	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
2028c2ecf20Sopenharmony_ci		        wake_up_interruptible(&q->cmdready);
2038c2ecf20Sopenharmony_ci		} else {
2048c2ecf20Sopenharmony_ci	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
2058c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(q->lock, flags);
2068c2ecf20Sopenharmony_ci			/*
2078c2ecf20Sopenharmony_ci			 *	Set the status of this FIB
2088c2ecf20Sopenharmony_ci			 */
2098c2ecf20Sopenharmony_ci			*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
2108c2ecf20Sopenharmony_ci			aac_fib_adapter_complete(fib, sizeof(u32));
2118c2ecf20Sopenharmony_ci			spin_lock_irqsave(q->lock, flags);
2128c2ecf20Sopenharmony_ci		}
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(q->lock, flags);
2158c2ecf20Sopenharmony_ci	return 0;
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci/*
2198c2ecf20Sopenharmony_ci *
2208c2ecf20Sopenharmony_ci * aac_aif_callback
2218c2ecf20Sopenharmony_ci * @context: the context set in the fib - here it is scsi cmd
2228c2ecf20Sopenharmony_ci * @fibptr: pointer to the fib
2238c2ecf20Sopenharmony_ci *
2248c2ecf20Sopenharmony_ci * Handles the AIFs - new method (SRC)
2258c2ecf20Sopenharmony_ci *
2268c2ecf20Sopenharmony_ci */
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic void aac_aif_callback(void *context, struct fib * fibptr)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct fib *fibctx;
2318c2ecf20Sopenharmony_ci	struct aac_dev *dev;
2328c2ecf20Sopenharmony_ci	struct aac_aifcmd *cmd;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	fibctx = (struct fib *)context;
2358c2ecf20Sopenharmony_ci	BUG_ON(fibptr == NULL);
2368c2ecf20Sopenharmony_ci	dev = fibptr->dev;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if ((fibptr->hw_fib_va->header.XferState &
2398c2ecf20Sopenharmony_ci	    cpu_to_le32(NoMoreAifDataAvailable)) ||
2408c2ecf20Sopenharmony_ci		dev->sa_firmware) {
2418c2ecf20Sopenharmony_ci		aac_fib_complete(fibptr);
2428c2ecf20Sopenharmony_ci		aac_fib_free(fibptr);
2438c2ecf20Sopenharmony_ci		return;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	aac_intr_normal(dev, 0, 1, 0, fibptr->hw_fib_va);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	aac_fib_init(fibctx);
2498c2ecf20Sopenharmony_ci	cmd = (struct aac_aifcmd *) fib_data(fibctx);
2508c2ecf20Sopenharmony_ci	cmd->command = cpu_to_le32(AifReqEvent);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	aac_fib_send(AifRequest,
2538c2ecf20Sopenharmony_ci		fibctx,
2548c2ecf20Sopenharmony_ci		sizeof(struct hw_fib)-sizeof(struct aac_fibhdr),
2558c2ecf20Sopenharmony_ci		FsaNormal,
2568c2ecf20Sopenharmony_ci		0, 1,
2578c2ecf20Sopenharmony_ci		(fib_callback)aac_aif_callback, fibctx);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci/*
2628c2ecf20Sopenharmony_ci *	aac_intr_normal	-	Handle command replies
2638c2ecf20Sopenharmony_ci *	@dev: Device
2648c2ecf20Sopenharmony_ci *	@index: completion reference
2658c2ecf20Sopenharmony_ci *
2668c2ecf20Sopenharmony_ci *	This DPC routine will be run when the adapter interrupts us to let us
2678c2ecf20Sopenharmony_ci *	know there is a response on our normal priority queue. We will pull off
2688c2ecf20Sopenharmony_ci *	all QE there are and wake up all the waiters before exiting.
2698c2ecf20Sopenharmony_ci */
2708c2ecf20Sopenharmony_ciunsigned int aac_intr_normal(struct aac_dev *dev, u32 index, int isAif,
2718c2ecf20Sopenharmony_ci	int isFastResponse, struct hw_fib *aif_fib)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	unsigned long mflags;
2748c2ecf20Sopenharmony_ci	dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
2758c2ecf20Sopenharmony_ci	if (isAif == 1) {	/* AIF - common */
2768c2ecf20Sopenharmony_ci		struct hw_fib * hw_fib;
2778c2ecf20Sopenharmony_ci		struct fib * fib;
2788c2ecf20Sopenharmony_ci		struct aac_queue *q = &dev->queues->queue[HostNormCmdQueue];
2798c2ecf20Sopenharmony_ci		unsigned long flags;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci		/*
2828c2ecf20Sopenharmony_ci		 *	Allocate a FIB. For non queued stuff we can just use
2838c2ecf20Sopenharmony_ci		 * the stack so we are happy. We need a fib object in order to
2848c2ecf20Sopenharmony_ci		 * manage the linked lists.
2858c2ecf20Sopenharmony_ci		 */
2868c2ecf20Sopenharmony_ci		if ((!dev->aif_thread)
2878c2ecf20Sopenharmony_ci		 || (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC))))
2888c2ecf20Sopenharmony_ci			return 1;
2898c2ecf20Sopenharmony_ci		if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
2908c2ecf20Sopenharmony_ci			kfree (fib);
2918c2ecf20Sopenharmony_ci			return 1;
2928c2ecf20Sopenharmony_ci		}
2938c2ecf20Sopenharmony_ci		if (dev->sa_firmware) {
2948c2ecf20Sopenharmony_ci			fib->hbacmd_size = index;	/* store event type */
2958c2ecf20Sopenharmony_ci		} else if (aif_fib != NULL) {
2968c2ecf20Sopenharmony_ci			memcpy(hw_fib, aif_fib, sizeof(struct hw_fib));
2978c2ecf20Sopenharmony_ci		} else {
2988c2ecf20Sopenharmony_ci			memcpy(hw_fib, (struct hw_fib *)
2998c2ecf20Sopenharmony_ci				(((uintptr_t)(dev->regs.sa)) + index),
3008c2ecf20Sopenharmony_ci				sizeof(struct hw_fib));
3018c2ecf20Sopenharmony_ci		}
3028c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&fib->fiblink);
3038c2ecf20Sopenharmony_ci		fib->type = FSAFS_NTC_FIB_CONTEXT;
3048c2ecf20Sopenharmony_ci		fib->size = sizeof(struct fib);
3058c2ecf20Sopenharmony_ci		fib->hw_fib_va = hw_fib;
3068c2ecf20Sopenharmony_ci		fib->data = hw_fib->data;
3078c2ecf20Sopenharmony_ci		fib->dev = dev;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		spin_lock_irqsave(q->lock, flags);
3108c2ecf20Sopenharmony_ci		list_add_tail(&fib->fiblink, &q->cmdq);
3118c2ecf20Sopenharmony_ci	        wake_up_interruptible(&q->cmdready);
3128c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(q->lock, flags);
3138c2ecf20Sopenharmony_ci		return 1;
3148c2ecf20Sopenharmony_ci	} else if (isAif == 2) {	/* AIF - new (SRC) */
3158c2ecf20Sopenharmony_ci		struct fib *fibctx;
3168c2ecf20Sopenharmony_ci		struct aac_aifcmd *cmd;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci		fibctx = aac_fib_alloc(dev);
3198c2ecf20Sopenharmony_ci		if (!fibctx)
3208c2ecf20Sopenharmony_ci			return 1;
3218c2ecf20Sopenharmony_ci		aac_fib_init(fibctx);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci		cmd = (struct aac_aifcmd *) fib_data(fibctx);
3248c2ecf20Sopenharmony_ci		cmd->command = cpu_to_le32(AifReqEvent);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci		return aac_fib_send(AifRequest,
3278c2ecf20Sopenharmony_ci			fibctx,
3288c2ecf20Sopenharmony_ci			sizeof(struct hw_fib)-sizeof(struct aac_fibhdr),
3298c2ecf20Sopenharmony_ci			FsaNormal,
3308c2ecf20Sopenharmony_ci			0, 1,
3318c2ecf20Sopenharmony_ci			(fib_callback)aac_aif_callback, fibctx);
3328c2ecf20Sopenharmony_ci	} else {
3338c2ecf20Sopenharmony_ci		struct fib *fib = &dev->fibs[index];
3348c2ecf20Sopenharmony_ci		int start_callback = 0;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci		/*
3378c2ecf20Sopenharmony_ci		 *	Remove this fib from the Outstanding I/O queue.
3388c2ecf20Sopenharmony_ci		 *	But only if it has not already been timed out.
3398c2ecf20Sopenharmony_ci		 *
3408c2ecf20Sopenharmony_ci		 *	If the fib has been timed out already, then just
3418c2ecf20Sopenharmony_ci		 *	continue. The caller has already been notified that
3428c2ecf20Sopenharmony_ci		 *	the fib timed out.
3438c2ecf20Sopenharmony_ci		 */
3448c2ecf20Sopenharmony_ci		atomic_dec(&dev->queues->queue[AdapNormCmdQueue].numpending);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
3478c2ecf20Sopenharmony_ci			aac_fib_complete(fib);
3488c2ecf20Sopenharmony_ci			aac_fib_free(fib);
3498c2ecf20Sopenharmony_ci			return 0;
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci		FIB_COUNTER_INCREMENT(aac_config.FibRecved);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		if (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) {
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci			if (isFastResponse)
3578c2ecf20Sopenharmony_ci				fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci			if (fib->callback) {
3608c2ecf20Sopenharmony_ci				start_callback = 1;
3618c2ecf20Sopenharmony_ci			} else {
3628c2ecf20Sopenharmony_ci				unsigned long flagv;
3638c2ecf20Sopenharmony_ci				int completed = 0;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci				dprintk((KERN_INFO "event_wait up\n"));
3668c2ecf20Sopenharmony_ci				spin_lock_irqsave(&fib->event_lock, flagv);
3678c2ecf20Sopenharmony_ci				if (fib->done == 2) {
3688c2ecf20Sopenharmony_ci					fib->done = 1;
3698c2ecf20Sopenharmony_ci					completed = 1;
3708c2ecf20Sopenharmony_ci				} else {
3718c2ecf20Sopenharmony_ci					fib->done = 1;
3728c2ecf20Sopenharmony_ci					complete(&fib->event_wait);
3738c2ecf20Sopenharmony_ci				}
3748c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&fib->event_lock, flagv);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci				spin_lock_irqsave(&dev->manage_lock, mflags);
3778c2ecf20Sopenharmony_ci				dev->management_fib_count--;
3788c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&dev->manage_lock,
3798c2ecf20Sopenharmony_ci					mflags);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci				FIB_COUNTER_INCREMENT(aac_config.NativeRecved);
3828c2ecf20Sopenharmony_ci				if (completed)
3838c2ecf20Sopenharmony_ci					aac_fib_complete(fib);
3848c2ecf20Sopenharmony_ci			}
3858c2ecf20Sopenharmony_ci		} else {
3868c2ecf20Sopenharmony_ci			struct hw_fib *hwfib = fib->hw_fib_va;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci			if (isFastResponse) {
3898c2ecf20Sopenharmony_ci				/* Doctor the fib */
3908c2ecf20Sopenharmony_ci				*(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
3918c2ecf20Sopenharmony_ci				hwfib->header.XferState |=
3928c2ecf20Sopenharmony_ci					cpu_to_le32(AdapterProcessed);
3938c2ecf20Sopenharmony_ci				fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
3948c2ecf20Sopenharmony_ci			}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci			if (hwfib->header.Command ==
3978c2ecf20Sopenharmony_ci				cpu_to_le16(NuFileSystem)) {
3988c2ecf20Sopenharmony_ci				__le32 *pstatus = (__le32 *)hwfib->data;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci				if (*pstatus & cpu_to_le32(0xffff0000))
4018c2ecf20Sopenharmony_ci					*pstatus = cpu_to_le32(ST_OK);
4028c2ecf20Sopenharmony_ci			}
4038c2ecf20Sopenharmony_ci			if (hwfib->header.XferState &
4048c2ecf20Sopenharmony_ci				cpu_to_le32(NoResponseExpected | Async)) {
4058c2ecf20Sopenharmony_ci				if (hwfib->header.XferState & cpu_to_le32(
4068c2ecf20Sopenharmony_ci					NoResponseExpected)) {
4078c2ecf20Sopenharmony_ci					FIB_COUNTER_INCREMENT(
4088c2ecf20Sopenharmony_ci						aac_config.NoResponseRecved);
4098c2ecf20Sopenharmony_ci				} else {
4108c2ecf20Sopenharmony_ci					FIB_COUNTER_INCREMENT(
4118c2ecf20Sopenharmony_ci						aac_config.AsyncRecved);
4128c2ecf20Sopenharmony_ci				}
4138c2ecf20Sopenharmony_ci				start_callback = 1;
4148c2ecf20Sopenharmony_ci			} else {
4158c2ecf20Sopenharmony_ci				unsigned long flagv;
4168c2ecf20Sopenharmony_ci				int completed = 0;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci				dprintk((KERN_INFO "event_wait up\n"));
4198c2ecf20Sopenharmony_ci				spin_lock_irqsave(&fib->event_lock, flagv);
4208c2ecf20Sopenharmony_ci				if (fib->done == 2) {
4218c2ecf20Sopenharmony_ci					fib->done = 1;
4228c2ecf20Sopenharmony_ci					completed = 1;
4238c2ecf20Sopenharmony_ci				} else {
4248c2ecf20Sopenharmony_ci					fib->done = 1;
4258c2ecf20Sopenharmony_ci					complete(&fib->event_wait);
4268c2ecf20Sopenharmony_ci				}
4278c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&fib->event_lock, flagv);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci				spin_lock_irqsave(&dev->manage_lock, mflags);
4308c2ecf20Sopenharmony_ci				dev->management_fib_count--;
4318c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&dev->manage_lock,
4328c2ecf20Sopenharmony_ci					mflags);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci				FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
4358c2ecf20Sopenharmony_ci				if (completed)
4368c2ecf20Sopenharmony_ci					aac_fib_complete(fib);
4378c2ecf20Sopenharmony_ci			}
4388c2ecf20Sopenharmony_ci		}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci		if (start_callback) {
4428c2ecf20Sopenharmony_ci			/*
4438c2ecf20Sopenharmony_ci			 * NOTE:  we cannot touch the fib after this
4448c2ecf20Sopenharmony_ci			 *  call, because it may have been deallocated.
4458c2ecf20Sopenharmony_ci			 */
4468c2ecf20Sopenharmony_ci			if (likely(fib->callback && fib->callback_data)) {
4478c2ecf20Sopenharmony_ci				fib->callback(fib->callback_data, fib);
4488c2ecf20Sopenharmony_ci			} else {
4498c2ecf20Sopenharmony_ci				aac_fib_complete(fib);
4508c2ecf20Sopenharmony_ci				aac_fib_free(fib);
4518c2ecf20Sopenharmony_ci			}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci		}
4548c2ecf20Sopenharmony_ci		return 0;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci}
457