// SPDX-License-Identifier: GPL-2.0-or-later/* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. * * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * Module Name: * src.c * * Abstract: Hardware Device Interface for PMC SRC based controllers */ #include <linux/kernel.h>#include <linux/init.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/completion.h>#include <linux/time.h>#include <linux/interrupt.h>#include <scsi/scsi_host.h> #include "aacraid.h" static int aac_src_get_sync_status(struct aac_dev *dev); static irqreturn_t aac_src_intr_message(int irq, void *dev_id){ struct aac_msix_ctx *ctx; struct aac_dev *dev; unsigned long bellbits, bellbits_shifted; int vector_no; int isFastResponse, mode; u32 index, handle; ctx = (struct aac_msix_ctx *)dev_id; dev = ctx->dev; vector_no = ctx->vector_no; if (dev->msi_enabled) { mode = AAC_INT_MODE_MSI; if (vector_no == 0) { bellbits = src_readl(dev, MUnit.ODR_MSI); if (bellbits & 0x40000) mode |= AAC_INT_MODE_AIF; if (bellbits & 0x1000) mode |= AAC_INT_MODE_SYNC; } } else { mode = AAC_INT_MODE_INTX; bellbits = src_readl(dev, MUnit.ODR_R); if (bellbits & PmDoorBellResponseSent) { bellbits = PmDoorBellResponseSent; src_writel(dev, MUnit.ODR_C, bellbits); src_readl(dev, MUnit.ODR_C); } else { bellbits_shifted = (bellbits >> SRC_ODR_SHIFT); src_writel(dev, MUnit.ODR_C, bellbits); src_readl(dev, MUnit.ODR_C); if (bellbits_shifted & DoorBellAifPending) mode |= AAC_INT_MODE_AIF; else if (bellbits_shifted & OUTBOUNDDOORBELL_0) mode |= AAC_INT_MODE_SYNC; } } if (mode & AAC_INT_MODE_SYNC) { unsigned long sflags; struct list_head *entry; int send_it = 0; extern int aac_sync_mode; if (!aac_sync_mode && !dev->msi_enabled) { src_writel(dev, MUnit.ODR_C, bellbits); src_readl(dev, MUnit.ODR_C); } if (dev->sync_fib) { if (dev->sync_fib->callback) dev->sync_fib->callback(dev->sync_fib->callback_data, dev->sync_fib); spin_lock_irqsave(&dev->sync_fib->event_lock, sflags); if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) { dev->management_fib_count--; complete(&dev->sync_fib->event_wait); } spin_unlock_irqrestore(&dev->sync_fib->event_lock, sflags); spin_lock_irqsave(&dev->sync_lock, sflags); if (!list_empty(&dev->sync_fib_list)) { entry = dev->sync_fib_list.next; dev->sync_fib = list_entry(entry, struct fib, fiblink); list_del(entry); send_it = 1; } else { dev->sync_fib = NULL; } spin_unlock_irqrestore(&dev->sync_lock, sflags); if (send_it) { aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB, (u32)dev->sync_fib->hw_fib_pa, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } } if (!dev->msi_enabled) mode = 0; } if (mode & AAC_INT_MODE_AIF) { /* handle AIF */ if (dev->sa_firmware) { u32 events = src_readl(dev, MUnit.SCR0); aac_intr_normal(dev, events, 1, 0, NULL); writel(events, &dev->IndexRegs->Mailbox[0]); src_writel(dev, MUnit.IDR, 1 << 23); } else { if (dev->aif_thread && dev->fsa_dev) aac_intr_normal(dev, 0, 2, 0, NULL); } if (dev->msi_enabled) aac_src_access_devreg(dev, AAC_CLEAR_AIF_BIT); mode = 0; } if (mode) { index = dev->host_rrq_idx[vector_no]; for (;;) { isFastResponse = 0; /* remove toggle bit (31) */ handle = le32_to_cpu((dev->host_rrq[index]) & 0x7fffffff); /* check fast response bits (30, 1) */ if (handle & 0x40000000) isFastResponse = 1; handle &= 0x0000ffff; if (handle == 0) break; handle >>= 2; if (dev->msi_enabled && dev->max_msix > 1) atomic_dec(&dev->rrq_outstanding[vector_no]); aac_intr_normal(dev, handle, 0, isFastResponse, NULL); dev->host_rrq[index++] = 0; if (index == (vector_no + 1) * dev->vector_cap) index = vector_no * dev->vector_cap; dev->host_rrq_idx[vector_no] = index; } mode = 0; } return IRQ_HANDLED;} /** * aac_src_disable_interrupt - Disable interrupts * @dev: Adapter */ static void aac_src_disable_interrupt(struct aac_dev *dev){ src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff);} /** * aac_src_enable_interrupt_message - Enable interrupts * @dev: Adapter */ static void aac_src_enable_interrupt_message(struct aac_dev *dev){ aac_src_access_devreg(dev, AAC_ENABLE_INTERRUPT);} /** * src_sync_cmd - send a command and wait * @dev: Adapter * @command: Command to execute * @p1: first parameter * @p2: second parameter * @p3: third parameter * @p4: forth parameter * @p5: fifth parameter * @p6: sixth parameter * @status: adapter status * @r1: first return value * @r2: second return valu * @r3: third return value * @r4: forth return value * * This routine will send a synchronous command to the adapter and wait * for its completion. */ static int src_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4){ unsigned long start; unsigned long delay; int ok; /* * Write the command into Mailbox 0 */ writel(command, &dev->IndexRegs->Mailbox[0]); /* * Write the parameters into Mailboxes 1 - 6 */ writel(p1, &dev->IndexRegs->Mailbox[1]); writel(p2, &dev->IndexRegs->Mailbox[2]); writel(p3, &dev->IndexRegs->Mailbox[3]); writel(p4, &dev->IndexRegs->Mailbox[4]); /* * Clear the synch command doorbell to start on a clean slate. */ if (!dev->msi_enabled) src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); /* * Disable doorbell interrupts */ src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); /* * Force the completion of the mask register write before issuing * the interrupt. */ src_readl(dev, MUnit.OIMR); /* * Signal that there is a new synch command */ src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); if ((!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) && !dev->in_soft_reset) { ok = 0; start = jiffies; if (command == IOP_RESET_ALWAYS) { /* Wait up to 10 sec */ delay = 10*HZ; } else { /* Wait up to 5 minutes */ delay = 300*HZ; } while (time_before(jiffies, start+delay)) { udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ /* * Mon960 will set doorbell0 bit when it has completed the command. */ if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) { /* * Clear the doorbell. */ if (dev->msi_enabled) aac_src_access_devreg(dev, AAC_CLEAR_SYNC_BIT); else src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); ok = 1; break; } /* * Yield the processor in case we are slow */ msleep(1); } if (unlikely(ok != 1)) { /* * Restore interrupt mask even though we timed out */ aac_adapter_enable_int(dev); return -ETIMEDOUT; } /* * Pull the synch status from Mailbox 0. */ if (status) *status = readl(&dev->IndexRegs->Mailbox[0]); if (r1) *r1 = readl(&dev->IndexRegs->Mailbox[1]); if (r2) *r2 = readl(&dev->IndexRegs->Mailbox[2]); if (r3) *r3 = readl(&dev->IndexRegs->Mailbox[3]); if (r4) *r4 = readl(&dev->IndexRegs->Mailbox[4]); if (command == GET_COMM_PREFERRED_SETTINGS) dev->max_msix = readl(&dev->IndexRegs->Mailbox[5]) & 0xFFFF; /* * Clear the synch command doorbell. */ if (!dev->msi_enabled) src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); } /* * Restore interrupt mask */ aac_adapter_enable_int(dev); return 0;} /** * aac_src_interrupt_adapter - interrupt adapter * @dev: Adapter * * Send an interrupt to the i960 and breakpoint it. */ static void aac_src_interrupt_adapter(struct aac_dev *dev){ src_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);} /** * aac_src_notify_adapter - send an event to the adapter * @dev: Adapter * @event: Event to send * * Notify the i960 that something it probably cares about has * happened. */ static void aac_src_notify_adapter(struct aac_dev *dev, u32 event){ switch (event) { case AdapNormCmdQue: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_1 << SRC_ODR_SHIFT); break; case HostNormRespNotFull: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_4 << SRC_ODR_SHIFT); break; case AdapNormRespQue: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_2 << SRC_ODR_SHIFT); break; case HostNormCmdNotFull: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_3 << SRC_ODR_SHIFT); break; case FastIo: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_6 << SRC_ODR_SHIFT); break; case AdapPrintfDone: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_5 << SRC_ODR_SHIFT); break; default: BUG(); break; }} /** * aac_src_start_adapter - activate adapter * @dev: Adapter * * Start up processing on an i960 based AAC adapter */ static void aac_src_start_adapter(struct aac_dev *dev){ union aac_init *init; int i; /* reset host_rrq_idx first */ for (i = 0; i < dev->max_msix; i++) { dev->host_rrq_idx[i] = i * dev->vector_cap; atomic_set(&dev->rrq_outstanding[i], 0); } atomic_set(&dev->msix_counter, 0); dev->fibs_pushed_no = 0; init = dev->init; if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { init->r8.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds()); src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, lower_32_bits(dev->init_pa), upper_32_bits(dev->init_pa), sizeof(struct _r8) + AAC_MAX_HRRQ * sizeof(struct _rrq), 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } else { init->r7.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds()); // We can only use a 32 bit address here src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } } /** * aac_src_check_health * @dev: device to check if healthy * * Will attempt to determine if the specified adapter is alive and * capable of handling requests, returning 0 if alive. */static int aac_src_check_health(struct aac_dev *dev){ u32 status = src_readl(dev, MUnit.OMR); /* * Check to see if the board panic'd. */ if (unlikely(status & KERNEL_PANIC)) goto err_blink; /* * Check to see if the board failed any self tests. */ if (unlikely(status & SELF_TEST_FAILED)) goto err_out; /* * Check to see if the board failed any self tests. */ if (unlikely(status & MONITOR_PANIC)) goto err_out; /* * Wait for the adapter to be up and running. */ if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) return -3; /* * Everything is OK */ return 0; err_out: return -1; err_blink: return (status >> 16) & 0xFF;} static inline u32 aac_get_vector(struct aac_dev *dev){ return atomic_inc_return(&dev->msix_counter)%dev->max_msix;} /** * aac_src_deliver_message * @fib: fib to issue * * Will send a fib, returning 0 if successful. */static int aac_src_deliver_message(struct fib *fib){ struct aac_dev *dev = fib->dev; struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; u32 fibsize; dma_addr_t address; struct aac_fib_xporthdr *pFibX; int native_hba;#if !defined(writeq) unsigned long flags;#endif u16 vector_no; atomic_inc(&q->numpending); native_hba = (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) ? 1 : 0; Lines 1–500 of 1436. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. * * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * Module Name: * src.c * * Abstract: Hardware Device Interface for PMC SRC based controllers */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/completion.h> #include <linux/time.h> #include <linux/interrupt.h> #include <scsi/scsi_host.h> #include "aacraid.h" static int aac_src_get_sync_status(struct aac_dev *dev); static irqreturn_t aac_src_intr_message(int irq, void *dev_id) { struct aac_msix_ctx *ctx; struct aac_dev *dev; unsigned long bellbits, bellbits_shifted; int vector_no; int isFastResponse, mode; u32 index, handle; ctx = (struct aac_msix_ctx *)dev_id; dev = ctx->dev; vector_no = ctx->vector_no; if (dev->msi_enabled) { mode = AAC_INT_MODE_MSI; if (vector_no == 0) { bellbits = src_readl(dev, MUnit.ODR_MSI); if (bellbits & 0x40000) mode |= AAC_INT_MODE_AIF; if (bellbits & 0x1000) mode |= AAC_INT_MODE_SYNC; } } else { mode = AAC_INT_MODE_INTX; bellbits = src_readl(dev, MUnit.ODR_R); if (bellbits & PmDoorBellResponseSent) { bellbits = PmDoorBellResponseSent; src_writel(dev, MUnit.ODR_C, bellbits); src_readl(dev, MUnit.ODR_C); } else { bellbits_shifted = (bellbits >> SRC_ODR_SHIFT); src_writel(dev, MUnit.ODR_C, bellbits); src_readl(dev, MUnit.ODR_C); if (bellbits_shifted & DoorBellAifPending) mode |= AAC_INT_MODE_AIF; else if (bellbits_shifted & OUTBOUNDDOORBELL_0) mode |= AAC_INT_MODE_SYNC; } } if (mode & AAC_INT_MODE_SYNC) { unsigned long sflags; struct list_head *entry; int send_it = 0; extern int aac_sync_mode; if (!aac_sync_mode && !dev->msi_enabled) { src_writel(dev, MUnit.ODR_C, bellbits); src_readl(dev, MUnit.ODR_C); } if (dev->sync_fib) { if (dev->sync_fib->callback) dev->sync_fib->callback(dev->sync_fib->callback_data, dev->sync_fib); spin_lock_irqsave(&dev->sync_fib->event_lock, sflags); if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) { dev->management_fib_count--; complete(&dev->sync_fib->event_wait); } spin_unlock_irqrestore(&dev->sync_fib->event_lock, sflags); spin_lock_irqsave(&dev->sync_lock, sflags); if (!list_empty(&dev->sync_fib_list)) { entry = dev->sync_fib_list.next; dev->sync_fib = list_entry(entry, struct fib, fiblink); list_del(entry); send_it = 1; } else { dev->sync_fib = NULL; } spin_unlock_irqrestore(&dev->sync_lock, sflags); if (send_it) { aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB, (u32)dev->sync_fib->hw_fib_pa, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } } if (!dev->msi_enabled) mode = 0; } if (mode & AAC_INT_MODE_AIF) { /* handle AIF */ if (dev->sa_firmware) { u32 events = src_readl(dev, MUnit.SCR0); aac_intr_normal(dev, events, 1, 0, NULL); writel(events, &dev->IndexRegs->Mailbox[0]); src_writel(dev, MUnit.IDR, 1 << 23); } else { if (dev->aif_thread && dev->fsa_dev) aac_intr_normal(dev, 0, 2, 0, NULL); } if (dev->msi_enabled) aac_src_access_devreg(dev, AAC_CLEAR_AIF_BIT); mode = 0; } if (mode) { index = dev->host_rrq_idx[vector_no]; for (;;) { isFastResponse = 0; /* remove toggle bit (31) */ handle = le32_to_cpu((dev->host_rrq[index]) & 0x7fffffff); /* check fast response bits (30, 1) */ if (handle & 0x40000000) isFastResponse = 1; handle &= 0x0000ffff; if (handle == 0) break; handle >>= 2; if (dev->msi_enabled && dev->max_msix > 1) atomic_dec(&dev->rrq_outstanding[vector_no]); aac_intr_normal(dev, handle, 0, isFastResponse, NULL); dev->host_rrq[index++] = 0; if (index == (vector_no + 1) * dev->vector_cap) index = vector_no * dev->vector_cap; dev->host_rrq_idx[vector_no] = index; } mode = 0; } return IRQ_HANDLED; } /** * aac_src_disable_interrupt - Disable interrupts * @dev: Adapter */ static void aac_src_disable_interrupt(struct aac_dev *dev) { src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); } /** * aac_src_enable_interrupt_message - Enable interrupts * @dev: Adapter */ static void aac_src_enable_interrupt_message(struct aac_dev *dev) { aac_src_access_devreg(dev, AAC_ENABLE_INTERRUPT); } /** * src_sync_cmd - send a command and wait * @dev: Adapter * @command: Command to execute * @p1: first parameter * @p2: second parameter * @p3: third parameter * @p4: forth parameter * @p5: fifth parameter * @p6: sixth parameter * @status: adapter status * @r1: first return value * @r2: second return valu * @r3: third return value * @r4: forth return value * * This routine will send a synchronous command to the adapter and wait * for its completion. */ static int src_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) { unsigned long start; unsigned long delay; int ok; /* * Write the command into Mailbox 0 */ writel(command, &dev->IndexRegs->Mailbox[0]); /* * Write the parameters into Mailboxes 1 - 6 */ writel(p1, &dev->IndexRegs->Mailbox[1]); writel(p2, &dev->IndexRegs->Mailbox[2]); writel(p3, &dev->IndexRegs->Mailbox[3]); writel(p4, &dev->IndexRegs->Mailbox[4]); /* * Clear the synch command doorbell to start on a clean slate. */ if (!dev->msi_enabled) src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); /* * Disable doorbell interrupts */ src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); /* * Force the completion of the mask register write before issuing * the interrupt. */ src_readl(dev, MUnit.OIMR); /* * Signal that there is a new synch command */ src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); if ((!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) && !dev->in_soft_reset) { ok = 0; start = jiffies; if (command == IOP_RESET_ALWAYS) { /* Wait up to 10 sec */ delay = 10*HZ; } else { /* Wait up to 5 minutes */ delay = 300*HZ; } while (time_before(jiffies, start+delay)) { udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ /* * Mon960 will set doorbell0 bit when it has completed the command. */ if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) { /* * Clear the doorbell. */ if (dev->msi_enabled) aac_src_access_devreg(dev, AAC_CLEAR_SYNC_BIT); else src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); ok = 1; break; } /* * Yield the processor in case we are slow */ msleep(1); } if (unlikely(ok != 1)) { /* * Restore interrupt mask even though we timed out */ aac_adapter_enable_int(dev); return -ETIMEDOUT; } /* * Pull the synch status from Mailbox 0. */ if (status) *status = readl(&dev->IndexRegs->Mailbox[0]); if (r1) *r1 = readl(&dev->IndexRegs->Mailbox[1]); if (r2) *r2 = readl(&dev->IndexRegs->Mailbox[2]); if (r3) *r3 = readl(&dev->IndexRegs->Mailbox[3]); if (r4) *r4 = readl(&dev->IndexRegs->Mailbox[4]); if (command == GET_COMM_PREFERRED_SETTINGS) dev->max_msix = readl(&dev->IndexRegs->Mailbox[5]) & 0xFFFF; /* * Clear the synch command doorbell. */ if (!dev->msi_enabled) src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); } /* * Restore interrupt mask */ aac_adapter_enable_int(dev); return 0; } /** * aac_src_interrupt_adapter - interrupt adapter * @dev: Adapter * * Send an interrupt to the i960 and breakpoint it. */ static void aac_src_interrupt_adapter(struct aac_dev *dev) { src_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } /** * aac_src_notify_adapter - send an event to the adapter * @dev: Adapter * @event: Event to send * * Notify the i960 that something it probably cares about has * happened. */ static void aac_src_notify_adapter(struct aac_dev *dev, u32 event) { switch (event) { case AdapNormCmdQue: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_1 << SRC_ODR_SHIFT); break; case HostNormRespNotFull: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_4 << SRC_ODR_SHIFT); break; case AdapNormRespQue: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_2 << SRC_ODR_SHIFT); break; case HostNormCmdNotFull: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_3 << SRC_ODR_SHIFT); break; case FastIo: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_6 << SRC_ODR_SHIFT); break; case AdapPrintfDone: src_writel(dev, MUnit.ODR_C, INBOUNDDOORBELL_5 << SRC_ODR_SHIFT); break; default: BUG(); break; } } /** * aac_src_start_adapter - activate adapter * @dev: Adapter * * Start up processing on an i960 based AAC adapter */ static void aac_src_start_adapter(struct aac_dev *dev) { union aac_init *init; int i; /* reset host_rrq_idx first */ for (i = 0; i < dev->max_msix; i++) { dev->host_rrq_idx[i] = i * dev->vector_cap; atomic_set(&dev->rrq_outstanding[i], 0); } atomic_set(&dev->msix_counter, 0); dev->fibs_pushed_no = 0; init = dev->init; if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { init->r8.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds()); src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, lower_32_bits(dev->init_pa), upper_32_bits(dev->init_pa), sizeof(struct _r8) + AAC_MAX_HRRQ * sizeof(struct _rrq), 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } else { init->r7.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds()); // We can only use a 32 bit address here src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } } /** * aac_src_check_health * @dev: device to check if healthy * * Will attempt to determine if the specified adapter is alive and * capable of handling requests, returning 0 if alive. */ static int aac_src_check_health(struct aac_dev *dev) { u32 status = src_readl(dev, MUnit.OMR); /* * Check to see if the board panic'd. */ if (unlikely(status & KERNEL_PANIC)) goto err_blink; /* * Check to see if the board failed any self tests. */ if (unlikely(status & SELF_TEST_FAILED)) goto err_out; /* * Check to see if the board failed any self tests. */ if (unlikely(status & MONITOR_PANIC)) goto err_out; /* * Wait for the adapter to be up and running. */ if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) return -3; /* * Everything is OK */ return 0; err_out: return -1; err_blink: return (status >> 16) & 0xFF; } static inline u32 aac_get_vector(struct aac_dev *dev) { return atomic_inc_return(&dev->msix_counter)%dev->max_msix; } /** * aac_src_deliver_message * @fib: fib to issue * * Will send a fib, returning 0 if successful. */ static int aac_src_deliver_message(struct fib *fib) { struct aac_dev *dev = fib->dev; struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; u32 fibsize; dma_addr_t address; struct aac_fib_xporthdr *pFibX; int native_hba; #if !defined(writeq) unsigned long flags; #endif u16 vector_no; atomic_inc(&q->numpending); native_hba = (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) ? 1 : 0;