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