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 *  dpcsup.c
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Abstract: All DPC processing routines for the cyclone board occur here.
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/spinlock.h>
2362306a36Sopenharmony_ci#include <linux/slab.h>
2462306a36Sopenharmony_ci#include <linux/completion.h>
2562306a36Sopenharmony_ci#include <linux/blkdev.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "aacraid.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/**
3062306a36Sopenharmony_ci *	aac_response_normal	-	Handle command replies
3162306a36Sopenharmony_ci *	@q: Queue to read from
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci *	This DPC routine will be run when the adapter interrupts us to let us
3462306a36Sopenharmony_ci *	know there is a response on our normal priority queue. We will pull off
3562306a36Sopenharmony_ci *	all QE there are and wake up all the waiters before exiting. We will
3662306a36Sopenharmony_ci *	take a spinlock out on the queue before operating on it.
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ciunsigned int aac_response_normal(struct aac_queue * q)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	struct aac_dev * dev = q->dev;
4262306a36Sopenharmony_ci	struct aac_entry *entry;
4362306a36Sopenharmony_ci	struct hw_fib * hwfib;
4462306a36Sopenharmony_ci	struct fib * fib;
4562306a36Sopenharmony_ci	int consumed = 0;
4662306a36Sopenharmony_ci	unsigned long flags, mflags;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	spin_lock_irqsave(q->lock, flags);
4962306a36Sopenharmony_ci	/*
5062306a36Sopenharmony_ci	 *	Keep pulling response QEs off the response queue and waking
5162306a36Sopenharmony_ci	 *	up the waiters until there are no more QEs. We then return
5262306a36Sopenharmony_ci	 *	back to the system. If no response was requested we just
5362306a36Sopenharmony_ci	 *	deallocate the Fib here and continue.
5462306a36Sopenharmony_ci	 */
5562306a36Sopenharmony_ci	while(aac_consumer_get(dev, q, &entry))
5662306a36Sopenharmony_ci	{
5762306a36Sopenharmony_ci		int fast;
5862306a36Sopenharmony_ci		u32 index = le32_to_cpu(entry->addr);
5962306a36Sopenharmony_ci		fast = index & 0x01;
6062306a36Sopenharmony_ci		fib = &dev->fibs[index >> 2];
6162306a36Sopenharmony_ci		hwfib = fib->hw_fib_va;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		aac_consumer_free(dev, q, HostNormRespQueue);
6462306a36Sopenharmony_ci		/*
6562306a36Sopenharmony_ci		 *	Remove this fib from the Outstanding I/O queue.
6662306a36Sopenharmony_ci		 *	But only if it has not already been timed out.
6762306a36Sopenharmony_ci		 *
6862306a36Sopenharmony_ci		 *	If the fib has been timed out already, then just
6962306a36Sopenharmony_ci		 *	continue. The caller has already been notified that
7062306a36Sopenharmony_ci		 *	the fib timed out.
7162306a36Sopenharmony_ci		 */
7262306a36Sopenharmony_ci		atomic_dec(&dev->queues->queue[AdapNormCmdQueue].numpending);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci		if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
7562306a36Sopenharmony_ci			spin_unlock_irqrestore(q->lock, flags);
7662306a36Sopenharmony_ci			aac_fib_complete(fib);
7762306a36Sopenharmony_ci			aac_fib_free(fib);
7862306a36Sopenharmony_ci			spin_lock_irqsave(q->lock, flags);
7962306a36Sopenharmony_ci			continue;
8062306a36Sopenharmony_ci		}
8162306a36Sopenharmony_ci		spin_unlock_irqrestore(q->lock, flags);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		if (fast) {
8462306a36Sopenharmony_ci			/*
8562306a36Sopenharmony_ci			 *	Doctor the fib
8662306a36Sopenharmony_ci			 */
8762306a36Sopenharmony_ci			*(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
8862306a36Sopenharmony_ci			hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
8962306a36Sopenharmony_ci			fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
9062306a36Sopenharmony_ci		}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		FIB_COUNTER_INCREMENT(aac_config.FibRecved);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
9562306a36Sopenharmony_ci		{
9662306a36Sopenharmony_ci			__le32 *pstatus = (__le32 *)hwfib->data;
9762306a36Sopenharmony_ci			if (*pstatus & cpu_to_le32(0xffff0000))
9862306a36Sopenharmony_ci				*pstatus = cpu_to_le32(ST_OK);
9962306a36Sopenharmony_ci		}
10062306a36Sopenharmony_ci		if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async))
10162306a36Sopenharmony_ci		{
10262306a36Sopenharmony_ci			if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected)) {
10362306a36Sopenharmony_ci				FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved);
10462306a36Sopenharmony_ci			} else {
10562306a36Sopenharmony_ci				FIB_COUNTER_INCREMENT(aac_config.AsyncRecved);
10662306a36Sopenharmony_ci			}
10762306a36Sopenharmony_ci			/*
10862306a36Sopenharmony_ci			 *	NOTE:  we cannot touch the fib after this
10962306a36Sopenharmony_ci			 *	    call, because it may have been deallocated.
11062306a36Sopenharmony_ci			 */
11162306a36Sopenharmony_ci			fib->callback(fib->callback_data, fib);
11262306a36Sopenharmony_ci		} else {
11362306a36Sopenharmony_ci			unsigned long flagv;
11462306a36Sopenharmony_ci			spin_lock_irqsave(&fib->event_lock, flagv);
11562306a36Sopenharmony_ci			if (!fib->done) {
11662306a36Sopenharmony_ci				fib->done = 1;
11762306a36Sopenharmony_ci				complete(&fib->event_wait);
11862306a36Sopenharmony_ci			}
11962306a36Sopenharmony_ci			spin_unlock_irqrestore(&fib->event_lock, flagv);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci			spin_lock_irqsave(&dev->manage_lock, mflags);
12262306a36Sopenharmony_ci			dev->management_fib_count--;
12362306a36Sopenharmony_ci			spin_unlock_irqrestore(&dev->manage_lock, mflags);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci			FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
12662306a36Sopenharmony_ci			if (fib->done == 2) {
12762306a36Sopenharmony_ci				spin_lock_irqsave(&fib->event_lock, flagv);
12862306a36Sopenharmony_ci				fib->done = 0;
12962306a36Sopenharmony_ci				spin_unlock_irqrestore(&fib->event_lock, flagv);
13062306a36Sopenharmony_ci				aac_fib_complete(fib);
13162306a36Sopenharmony_ci				aac_fib_free(fib);
13262306a36Sopenharmony_ci			}
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci		consumed++;
13562306a36Sopenharmony_ci		spin_lock_irqsave(q->lock, flags);
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if (consumed > aac_config.peak_fibs)
13962306a36Sopenharmony_ci		aac_config.peak_fibs = consumed;
14062306a36Sopenharmony_ci	if (consumed == 0)
14162306a36Sopenharmony_ci		aac_config.zero_fibs++;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	spin_unlock_irqrestore(q->lock, flags);
14462306a36Sopenharmony_ci	return 0;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/**
14962306a36Sopenharmony_ci *	aac_command_normal	-	handle commands
15062306a36Sopenharmony_ci *	@q: queue to process
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci *	This DPC routine will be queued when the adapter interrupts us to
15362306a36Sopenharmony_ci *	let us know there is a command on our normal priority queue. We will
15462306a36Sopenharmony_ci *	pull off all QE there are and wake up all the waiters before exiting.
15562306a36Sopenharmony_ci *	We will take a spinlock out on the queue before operating on it.
15662306a36Sopenharmony_ci */
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ciunsigned int aac_command_normal(struct aac_queue *q)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct aac_dev * dev = q->dev;
16162306a36Sopenharmony_ci	struct aac_entry *entry;
16262306a36Sopenharmony_ci	unsigned long flags;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	spin_lock_irqsave(q->lock, flags);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/*
16762306a36Sopenharmony_ci	 *	Keep pulling response QEs off the response queue and waking
16862306a36Sopenharmony_ci	 *	up the waiters until there are no more QEs. We then return
16962306a36Sopenharmony_ci	 *	back to the system.
17062306a36Sopenharmony_ci	 */
17162306a36Sopenharmony_ci	while(aac_consumer_get(dev, q, &entry))
17262306a36Sopenharmony_ci	{
17362306a36Sopenharmony_ci		struct fib fibctx;
17462306a36Sopenharmony_ci		struct hw_fib * hw_fib;
17562306a36Sopenharmony_ci		u32 index;
17662306a36Sopenharmony_ci		struct fib *fib = &fibctx;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci		index = le32_to_cpu(entry->addr) / sizeof(struct hw_fib);
17962306a36Sopenharmony_ci		hw_fib = &dev->aif_base_va[index];
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		/*
18262306a36Sopenharmony_ci		 *	Allocate a FIB at all costs. For non queued stuff
18362306a36Sopenharmony_ci		 *	we can just use the stack so we are happy. We need
18462306a36Sopenharmony_ci		 *	a fib object in order to manage the linked lists
18562306a36Sopenharmony_ci		 */
18662306a36Sopenharmony_ci		if (dev->aif_thread)
18762306a36Sopenharmony_ci			if((fib = kmalloc(sizeof(struct fib), GFP_ATOMIC)) == NULL)
18862306a36Sopenharmony_ci				fib = &fibctx;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		memset(fib, 0, sizeof(struct fib));
19162306a36Sopenharmony_ci		INIT_LIST_HEAD(&fib->fiblink);
19262306a36Sopenharmony_ci		fib->type = FSAFS_NTC_FIB_CONTEXT;
19362306a36Sopenharmony_ci		fib->size = sizeof(struct fib);
19462306a36Sopenharmony_ci		fib->hw_fib_va = hw_fib;
19562306a36Sopenharmony_ci		fib->data = hw_fib->data;
19662306a36Sopenharmony_ci		fib->dev = dev;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		if (dev->aif_thread && fib != &fibctx) {
20062306a36Sopenharmony_ci		        list_add_tail(&fib->fiblink, &q->cmdq);
20162306a36Sopenharmony_ci	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
20262306a36Sopenharmony_ci		        wake_up_interruptible(&q->cmdready);
20362306a36Sopenharmony_ci		} else {
20462306a36Sopenharmony_ci	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
20562306a36Sopenharmony_ci			spin_unlock_irqrestore(q->lock, flags);
20662306a36Sopenharmony_ci			/*
20762306a36Sopenharmony_ci			 *	Set the status of this FIB
20862306a36Sopenharmony_ci			 */
20962306a36Sopenharmony_ci			*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
21062306a36Sopenharmony_ci			aac_fib_adapter_complete(fib, sizeof(u32));
21162306a36Sopenharmony_ci			spin_lock_irqsave(q->lock, flags);
21262306a36Sopenharmony_ci		}
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci	spin_unlock_irqrestore(q->lock, flags);
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/*
21962306a36Sopenharmony_ci *
22062306a36Sopenharmony_ci * aac_aif_callback
22162306a36Sopenharmony_ci * @context: the context set in the fib - here it is scsi cmd
22262306a36Sopenharmony_ci * @fibptr: pointer to the fib
22362306a36Sopenharmony_ci *
22462306a36Sopenharmony_ci * Handles the AIFs - new method (SRC)
22562306a36Sopenharmony_ci *
22662306a36Sopenharmony_ci */
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic void aac_aif_callback(void *context, struct fib * fibptr)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct fib *fibctx;
23162306a36Sopenharmony_ci	struct aac_dev *dev;
23262306a36Sopenharmony_ci	struct aac_aifcmd *cmd;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	fibctx = (struct fib *)context;
23562306a36Sopenharmony_ci	BUG_ON(fibptr == NULL);
23662306a36Sopenharmony_ci	dev = fibptr->dev;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if ((fibptr->hw_fib_va->header.XferState &
23962306a36Sopenharmony_ci	    cpu_to_le32(NoMoreAifDataAvailable)) ||
24062306a36Sopenharmony_ci		dev->sa_firmware) {
24162306a36Sopenharmony_ci		aac_fib_complete(fibptr);
24262306a36Sopenharmony_ci		aac_fib_free(fibptr);
24362306a36Sopenharmony_ci		return;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	aac_intr_normal(dev, 0, 1, 0, fibptr->hw_fib_va);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	aac_fib_init(fibctx);
24962306a36Sopenharmony_ci	cmd = (struct aac_aifcmd *) fib_data(fibctx);
25062306a36Sopenharmony_ci	cmd->command = cpu_to_le32(AifReqEvent);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	aac_fib_send(AifRequest,
25362306a36Sopenharmony_ci		fibctx,
25462306a36Sopenharmony_ci		sizeof(struct hw_fib)-sizeof(struct aac_fibhdr),
25562306a36Sopenharmony_ci		FsaNormal,
25662306a36Sopenharmony_ci		0, 1,
25762306a36Sopenharmony_ci		(fib_callback)aac_aif_callback, fibctx);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/*
26262306a36Sopenharmony_ci *	aac_intr_normal	-	Handle command replies
26362306a36Sopenharmony_ci *	@dev: Device
26462306a36Sopenharmony_ci *	@index: completion reference
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci *	This DPC routine will be run when the adapter interrupts us to let us
26762306a36Sopenharmony_ci *	know there is a response on our normal priority queue. We will pull off
26862306a36Sopenharmony_ci *	all QE there are and wake up all the waiters before exiting.
26962306a36Sopenharmony_ci */
27062306a36Sopenharmony_ciunsigned int aac_intr_normal(struct aac_dev *dev, u32 index, int isAif,
27162306a36Sopenharmony_ci	int isFastResponse, struct hw_fib *aif_fib)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	unsigned long mflags;
27462306a36Sopenharmony_ci	dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
27562306a36Sopenharmony_ci	if (isAif == 1) {	/* AIF - common */
27662306a36Sopenharmony_ci		struct hw_fib * hw_fib;
27762306a36Sopenharmony_ci		struct fib * fib;
27862306a36Sopenharmony_ci		struct aac_queue *q = &dev->queues->queue[HostNormCmdQueue];
27962306a36Sopenharmony_ci		unsigned long flags;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		/*
28262306a36Sopenharmony_ci		 *	Allocate a FIB. For non queued stuff we can just use
28362306a36Sopenharmony_ci		 * the stack so we are happy. We need a fib object in order to
28462306a36Sopenharmony_ci		 * manage the linked lists.
28562306a36Sopenharmony_ci		 */
28662306a36Sopenharmony_ci		if ((!dev->aif_thread)
28762306a36Sopenharmony_ci		 || (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC))))
28862306a36Sopenharmony_ci			return 1;
28962306a36Sopenharmony_ci		if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
29062306a36Sopenharmony_ci			kfree (fib);
29162306a36Sopenharmony_ci			return 1;
29262306a36Sopenharmony_ci		}
29362306a36Sopenharmony_ci		if (dev->sa_firmware) {
29462306a36Sopenharmony_ci			fib->hbacmd_size = index;	/* store event type */
29562306a36Sopenharmony_ci		} else if (aif_fib != NULL) {
29662306a36Sopenharmony_ci			memcpy(hw_fib, aif_fib, sizeof(struct hw_fib));
29762306a36Sopenharmony_ci		} else {
29862306a36Sopenharmony_ci			memcpy(hw_fib, (struct hw_fib *)
29962306a36Sopenharmony_ci				(((uintptr_t)(dev->regs.sa)) + index),
30062306a36Sopenharmony_ci				sizeof(struct hw_fib));
30162306a36Sopenharmony_ci		}
30262306a36Sopenharmony_ci		INIT_LIST_HEAD(&fib->fiblink);
30362306a36Sopenharmony_ci		fib->type = FSAFS_NTC_FIB_CONTEXT;
30462306a36Sopenharmony_ci		fib->size = sizeof(struct fib);
30562306a36Sopenharmony_ci		fib->hw_fib_va = hw_fib;
30662306a36Sopenharmony_ci		fib->data = hw_fib->data;
30762306a36Sopenharmony_ci		fib->dev = dev;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		spin_lock_irqsave(q->lock, flags);
31062306a36Sopenharmony_ci		list_add_tail(&fib->fiblink, &q->cmdq);
31162306a36Sopenharmony_ci	        wake_up_interruptible(&q->cmdready);
31262306a36Sopenharmony_ci		spin_unlock_irqrestore(q->lock, flags);
31362306a36Sopenharmony_ci		return 1;
31462306a36Sopenharmony_ci	} else if (isAif == 2) {	/* AIF - new (SRC) */
31562306a36Sopenharmony_ci		struct fib *fibctx;
31662306a36Sopenharmony_ci		struct aac_aifcmd *cmd;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		fibctx = aac_fib_alloc(dev);
31962306a36Sopenharmony_ci		if (!fibctx)
32062306a36Sopenharmony_ci			return 1;
32162306a36Sopenharmony_ci		aac_fib_init(fibctx);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci		cmd = (struct aac_aifcmd *) fib_data(fibctx);
32462306a36Sopenharmony_ci		cmd->command = cpu_to_le32(AifReqEvent);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		return aac_fib_send(AifRequest,
32762306a36Sopenharmony_ci			fibctx,
32862306a36Sopenharmony_ci			sizeof(struct hw_fib)-sizeof(struct aac_fibhdr),
32962306a36Sopenharmony_ci			FsaNormal,
33062306a36Sopenharmony_ci			0, 1,
33162306a36Sopenharmony_ci			(fib_callback)aac_aif_callback, fibctx);
33262306a36Sopenharmony_ci	} else {
33362306a36Sopenharmony_ci		struct fib *fib = &dev->fibs[index];
33462306a36Sopenharmony_ci		int start_callback = 0;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		/*
33762306a36Sopenharmony_ci		 *	Remove this fib from the Outstanding I/O queue.
33862306a36Sopenharmony_ci		 *	But only if it has not already been timed out.
33962306a36Sopenharmony_ci		 *
34062306a36Sopenharmony_ci		 *	If the fib has been timed out already, then just
34162306a36Sopenharmony_ci		 *	continue. The caller has already been notified that
34262306a36Sopenharmony_ci		 *	the fib timed out.
34362306a36Sopenharmony_ci		 */
34462306a36Sopenharmony_ci		atomic_dec(&dev->queues->queue[AdapNormCmdQueue].numpending);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
34762306a36Sopenharmony_ci			aac_fib_complete(fib);
34862306a36Sopenharmony_ci			aac_fib_free(fib);
34962306a36Sopenharmony_ci			return 0;
35062306a36Sopenharmony_ci		}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci		FIB_COUNTER_INCREMENT(aac_config.FibRecved);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		if (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) {
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci			if (isFastResponse)
35762306a36Sopenharmony_ci				fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci			if (fib->callback) {
36062306a36Sopenharmony_ci				start_callback = 1;
36162306a36Sopenharmony_ci			} else {
36262306a36Sopenharmony_ci				unsigned long flagv;
36362306a36Sopenharmony_ci				int completed = 0;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci				dprintk((KERN_INFO "event_wait up\n"));
36662306a36Sopenharmony_ci				spin_lock_irqsave(&fib->event_lock, flagv);
36762306a36Sopenharmony_ci				if (fib->done == 2) {
36862306a36Sopenharmony_ci					fib->done = 1;
36962306a36Sopenharmony_ci					completed = 1;
37062306a36Sopenharmony_ci				} else {
37162306a36Sopenharmony_ci					fib->done = 1;
37262306a36Sopenharmony_ci					complete(&fib->event_wait);
37362306a36Sopenharmony_ci				}
37462306a36Sopenharmony_ci				spin_unlock_irqrestore(&fib->event_lock, flagv);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci				spin_lock_irqsave(&dev->manage_lock, mflags);
37762306a36Sopenharmony_ci				dev->management_fib_count--;
37862306a36Sopenharmony_ci				spin_unlock_irqrestore(&dev->manage_lock,
37962306a36Sopenharmony_ci					mflags);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci				FIB_COUNTER_INCREMENT(aac_config.NativeRecved);
38262306a36Sopenharmony_ci				if (completed)
38362306a36Sopenharmony_ci					aac_fib_complete(fib);
38462306a36Sopenharmony_ci			}
38562306a36Sopenharmony_ci		} else {
38662306a36Sopenharmony_ci			struct hw_fib *hwfib = fib->hw_fib_va;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci			if (isFastResponse) {
38962306a36Sopenharmony_ci				/* Doctor the fib */
39062306a36Sopenharmony_ci				*(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
39162306a36Sopenharmony_ci				hwfib->header.XferState |=
39262306a36Sopenharmony_ci					cpu_to_le32(AdapterProcessed);
39362306a36Sopenharmony_ci				fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
39462306a36Sopenharmony_ci			}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci			if (hwfib->header.Command ==
39762306a36Sopenharmony_ci				cpu_to_le16(NuFileSystem)) {
39862306a36Sopenharmony_ci				__le32 *pstatus = (__le32 *)hwfib->data;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci				if (*pstatus & cpu_to_le32(0xffff0000))
40162306a36Sopenharmony_ci					*pstatus = cpu_to_le32(ST_OK);
40262306a36Sopenharmony_ci			}
40362306a36Sopenharmony_ci			if (hwfib->header.XferState &
40462306a36Sopenharmony_ci				cpu_to_le32(NoResponseExpected | Async)) {
40562306a36Sopenharmony_ci				if (hwfib->header.XferState & cpu_to_le32(
40662306a36Sopenharmony_ci					NoResponseExpected)) {
40762306a36Sopenharmony_ci					FIB_COUNTER_INCREMENT(
40862306a36Sopenharmony_ci						aac_config.NoResponseRecved);
40962306a36Sopenharmony_ci				} else {
41062306a36Sopenharmony_ci					FIB_COUNTER_INCREMENT(
41162306a36Sopenharmony_ci						aac_config.AsyncRecved);
41262306a36Sopenharmony_ci				}
41362306a36Sopenharmony_ci				start_callback = 1;
41462306a36Sopenharmony_ci			} else {
41562306a36Sopenharmony_ci				unsigned long flagv;
41662306a36Sopenharmony_ci				int completed = 0;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci				dprintk((KERN_INFO "event_wait up\n"));
41962306a36Sopenharmony_ci				spin_lock_irqsave(&fib->event_lock, flagv);
42062306a36Sopenharmony_ci				if (fib->done == 2) {
42162306a36Sopenharmony_ci					fib->done = 1;
42262306a36Sopenharmony_ci					completed = 1;
42362306a36Sopenharmony_ci				} else {
42462306a36Sopenharmony_ci					fib->done = 1;
42562306a36Sopenharmony_ci					complete(&fib->event_wait);
42662306a36Sopenharmony_ci				}
42762306a36Sopenharmony_ci				spin_unlock_irqrestore(&fib->event_lock, flagv);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci				spin_lock_irqsave(&dev->manage_lock, mflags);
43062306a36Sopenharmony_ci				dev->management_fib_count--;
43162306a36Sopenharmony_ci				spin_unlock_irqrestore(&dev->manage_lock,
43262306a36Sopenharmony_ci					mflags);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci				FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
43562306a36Sopenharmony_ci				if (completed)
43662306a36Sopenharmony_ci					aac_fib_complete(fib);
43762306a36Sopenharmony_ci			}
43862306a36Sopenharmony_ci		}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci		if (start_callback) {
44262306a36Sopenharmony_ci			/*
44362306a36Sopenharmony_ci			 * NOTE:  we cannot touch the fib after this
44462306a36Sopenharmony_ci			 *  call, because it may have been deallocated.
44562306a36Sopenharmony_ci			 */
44662306a36Sopenharmony_ci			if (likely(fib->callback && fib->callback_data)) {
44762306a36Sopenharmony_ci				fib->callback(fib->callback_data, fib);
44862306a36Sopenharmony_ci			} else {
44962306a36Sopenharmony_ci				aac_fib_complete(fib);
45062306a36Sopenharmony_ci				aac_fib_free(fib);
45162306a36Sopenharmony_ci			}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		}
45462306a36Sopenharmony_ci		return 0;
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci}
457