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