diff options
Diffstat (limited to 'drivers/scsi/aacraid/dpcsup.c')
-rw-r--r-- | drivers/scsi/aacraid/dpcsup.c | 159 |
1 files changed, 103 insertions, 56 deletions
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c index 7e836205aef1..417ba349e10e 100644 --- a/drivers/scsi/aacraid/dpcsup.c +++ b/drivers/scsi/aacraid/dpcsup.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -122,7 +123,6 @@ unsigned int aac_response_normal(struct aac_queue * q) * NOTE: we cannot touch the fib after this * call, because it may have been deallocated. */ - fib->flags &= FIB_CONTEXT_FLAG_FASTRESP; fib->callback(fib->callback_data, fib); } else { unsigned long flagv; @@ -251,8 +251,9 @@ static void aac_aif_callback(void *context, struct fib * fibptr) BUG_ON(fibptr == NULL); dev = fibptr->dev; - if (fibptr->hw_fib_va->header.XferState & - cpu_to_le32(NoMoreAifDataAvailable)) { + if ((fibptr->hw_fib_va->header.XferState & + cpu_to_le32(NoMoreAifDataAvailable)) || + dev->sa_firmware) { aac_fib_complete(fibptr); aac_fib_free(fibptr); return; @@ -282,8 +283,8 @@ static void aac_aif_callback(void *context, struct fib * fibptr) * know there is a response on our normal priority queue. We will pull off * all QE there are and wake up all the waiters before exiting. */ -unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, - int isAif, int isFastResponse, struct hw_fib *aif_fib) +unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, int isAif, + int isFastResponse, struct hw_fib *aif_fib) { unsigned long mflags; dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index)); @@ -305,12 +306,14 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, kfree (fib); return 1; } - if (aif_fib != NULL) { + if (dev->sa_firmware) { + fib->hbacmd_size = index; /* store event type */ + } else if (aif_fib != NULL) { memcpy(hw_fib, aif_fib, sizeof(struct hw_fib)); } else { - memcpy(hw_fib, - (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) + - index), sizeof(struct hw_fib)); + memcpy(hw_fib, (struct hw_fib *) + (((uintptr_t)(dev->regs.sa)) + index), + sizeof(struct hw_fib)); } INIT_LIST_HEAD(&fib->fiblink); fib->type = FSAFS_NTC_FIB_CONTEXT; @@ -344,7 +347,7 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, (fib_callback)aac_aif_callback, fibctx); } else { struct fib *fib = &dev->fibs[index]; - struct hw_fib * hwfib = fib->hw_fib_va; + int start_callback = 0; /* * Remove this fib from the Outstanding I/O queue. @@ -362,60 +365,104 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, return 0; } - if (isFastResponse) { - /* - * Doctor the fib - */ - *(__le32 *)hwfib->data = cpu_to_le32(ST_OK); - hwfib->header.XferState |= cpu_to_le32(AdapterProcessed); - fib->flags |= FIB_CONTEXT_FLAG_FASTRESP; - } - FIB_COUNTER_INCREMENT(aac_config.FibRecved); - if (hwfib->header.Command == cpu_to_le16(NuFileSystem)) - { - __le32 *pstatus = (__le32 *)hwfib->data; - if (*pstatus & cpu_to_le32(0xffff0000)) - *pstatus = cpu_to_le32(ST_OK); - } - if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) - { - if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected)) - FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved); - else - FIB_COUNTER_INCREMENT(aac_config.AsyncRecved); - /* - * NOTE: we cannot touch the fib after this - * call, because it may have been deallocated. - */ - if (likely(fib->callback && fib->callback_data)) { - fib->flags &= FIB_CONTEXT_FLAG_FASTRESP; - fib->callback(fib->callback_data, fib); - } else - dev_info(&dev->pdev->dev, - "Invalid callback_fib[%d] (*%p)(%p)\n", - index, fib->callback, fib->callback_data); + if (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) { + + if (isFastResponse) + fib->flags |= FIB_CONTEXT_FLAG_FASTRESP; + + if (fib->callback) { + start_callback = 1; + } else { + unsigned long flagv; + int complete = 0; + + dprintk((KERN_INFO "event_wait up\n")); + spin_lock_irqsave(&fib->event_lock, flagv); + if (fib->done == 2) { + fib->done = 1; + complete = 1; + } else { + fib->done = 1; + up(&fib->event_wait); + } + spin_unlock_irqrestore(&fib->event_lock, flagv); + + spin_lock_irqsave(&dev->manage_lock, mflags); + dev->management_fib_count--; + spin_unlock_irqrestore(&dev->manage_lock, + mflags); + + FIB_COUNTER_INCREMENT(aac_config.NativeRecved); + if (complete) + aac_fib_complete(fib); + } } else { - unsigned long flagv; - dprintk((KERN_INFO "event_wait up\n")); - spin_lock_irqsave(&fib->event_lock, flagv); - if (!fib->done) { - fib->done = 1; - up(&fib->event_wait); + struct hw_fib *hwfib = fib->hw_fib_va; + + if (isFastResponse) { + /* Doctor the fib */ + *(__le32 *)hwfib->data = cpu_to_le32(ST_OK); + hwfib->header.XferState |= + cpu_to_le32(AdapterProcessed); + fib->flags |= FIB_CONTEXT_FLAG_FASTRESP; } - spin_unlock_irqrestore(&fib->event_lock, flagv); - spin_lock_irqsave(&dev->manage_lock, mflags); - dev->management_fib_count--; - spin_unlock_irqrestore(&dev->manage_lock, mflags); + if (hwfib->header.Command == + cpu_to_le16(NuFileSystem)) { + __le32 *pstatus = (__le32 *)hwfib->data; - FIB_COUNTER_INCREMENT(aac_config.NormalRecved); - if (fib->done == 2) { + if (*pstatus & cpu_to_le32(0xffff0000)) + *pstatus = cpu_to_le32(ST_OK); + } + if (hwfib->header.XferState & + cpu_to_le32(NoResponseExpected | Async)) { + if (hwfib->header.XferState & cpu_to_le32( + NoResponseExpected)) + FIB_COUNTER_INCREMENT( + aac_config.NoResponseRecved); + else + FIB_COUNTER_INCREMENT( + aac_config.AsyncRecved); + start_callback = 1; + } else { + unsigned long flagv; + int complete = 0; + + dprintk((KERN_INFO "event_wait up\n")); spin_lock_irqsave(&fib->event_lock, flagv); - fib->done = 0; + if (fib->done == 2) { + fib->done = 1; + complete = 1; + } else { + fib->done = 1; + up(&fib->event_wait); + } spin_unlock_irqrestore(&fib->event_lock, flagv); + + spin_lock_irqsave(&dev->manage_lock, mflags); + dev->management_fib_count--; + spin_unlock_irqrestore(&dev->manage_lock, + mflags); + + FIB_COUNTER_INCREMENT(aac_config.NormalRecved); + if (complete) + aac_fib_complete(fib); + } + } + + + if (start_callback) { + /* + * NOTE: we cannot touch the fib after this + * call, because it may have been deallocated. + */ + if (likely(fib->callback && fib->callback_data)) { + fib->callback(fib->callback_data, fib); + } else { aac_fib_complete(fib); + aac_fib_free(fib); } } |