mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-09 01:28:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
8
drivers/scsi/aacraid/Makefile
Normal file
8
drivers/scsi/aacraid/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Adaptec aacraid
|
||||
|
||||
obj-$(CONFIG_SCSI_AACRAID) := aacraid.o
|
||||
|
||||
aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \
|
||||
dpcsup.o rx.o sa.o rkt.o nark.o src.o
|
||||
|
||||
ccflags-y := -Idrivers/scsi
|
3
drivers/scsi/aacraid/TODO
Normal file
3
drivers/scsi/aacraid/TODO
Normal file
|
@ -0,0 +1,3 @@
|
|||
o Testing
|
||||
o More testing
|
||||
o I/O size increase
|
3215
drivers/scsi/aacraid/aachba.c
Normal file
3215
drivers/scsi/aacraid/aachba.c
Normal file
File diff suppressed because it is too large
Load diff
2073
drivers/scsi/aacraid/aacraid.h
Normal file
2073
drivers/scsi/aacraid/aacraid.h
Normal file
File diff suppressed because it is too large
Load diff
889
drivers/scsi/aacraid/commctrl.c
Normal file
889
drivers/scsi/aacraid/commctrl.c
Normal file
|
@ -0,0 +1,889 @@
|
|||
/*
|
||||
* 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 PMC-Sierra, Inc. (aacraid@pmc-sierra.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
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Module Name:
|
||||
* commctrl.c
|
||||
*
|
||||
* Abstract: Contains all routines for control of the AFA comm layer
|
||||
*
|
||||
*/
|
||||
|
||||
#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/completion.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/delay.h> /* ssleep prototype */
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include "aacraid.h"
|
||||
|
||||
/**
|
||||
* ioctl_send_fib - send a FIB from userspace
|
||||
* @dev: adapter is being processed
|
||||
* @arg: arguments to the ioctl call
|
||||
*
|
||||
* This routine sends a fib to the adapter on behalf of a user level
|
||||
* program.
|
||||
*/
|
||||
# define AAC_DEBUG_PREAMBLE KERN_INFO
|
||||
# define AAC_DEBUG_POSTAMBLE
|
||||
|
||||
static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
|
||||
{
|
||||
struct hw_fib * kfib;
|
||||
struct fib *fibptr;
|
||||
struct hw_fib * hw_fib = (struct hw_fib *)0;
|
||||
dma_addr_t hw_fib_pa = (dma_addr_t)0LL;
|
||||
unsigned size;
|
||||
int retval;
|
||||
|
||||
if (dev->in_reset) {
|
||||
return -EBUSY;
|
||||
}
|
||||
fibptr = aac_fib_alloc(dev);
|
||||
if(fibptr == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kfib = fibptr->hw_fib_va;
|
||||
/*
|
||||
* First copy in the header so that we can check the size field.
|
||||
*/
|
||||
if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) {
|
||||
aac_fib_free(fibptr);
|
||||
return -EFAULT;
|
||||
}
|
||||
/*
|
||||
* Since we copy based on the fib header size, make sure that we
|
||||
* will not overrun the buffer when we copy the memory. Return
|
||||
* an error if we would.
|
||||
*/
|
||||
size = le16_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr);
|
||||
if (size < le16_to_cpu(kfib->header.SenderSize))
|
||||
size = le16_to_cpu(kfib->header.SenderSize);
|
||||
if (size > dev->max_fib_size) {
|
||||
dma_addr_t daddr;
|
||||
|
||||
if (size > 2048) {
|
||||
retval = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
kfib = pci_alloc_consistent(dev->pdev, size, &daddr);
|
||||
if (!kfib) {
|
||||
retval = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Highjack the hw_fib */
|
||||
hw_fib = fibptr->hw_fib_va;
|
||||
hw_fib_pa = fibptr->hw_fib_pa;
|
||||
fibptr->hw_fib_va = kfib;
|
||||
fibptr->hw_fib_pa = daddr;
|
||||
memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size);
|
||||
memcpy(kfib, hw_fib, dev->max_fib_size);
|
||||
}
|
||||
|
||||
if (copy_from_user(kfib, arg, size)) {
|
||||
retval = -EFAULT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) {
|
||||
aac_adapter_interrupt(dev);
|
||||
/*
|
||||
* Since we didn't really send a fib, zero out the state to allow
|
||||
* cleanup code not to assert.
|
||||
*/
|
||||
kfib->header.XferState = 0;
|
||||
} else {
|
||||
retval = aac_fib_send(le16_to_cpu(kfib->header.Command), fibptr,
|
||||
le16_to_cpu(kfib->header.Size) , FsaNormal,
|
||||
1, 1, NULL, NULL);
|
||||
if (retval) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (aac_fib_complete(fibptr) != 0) {
|
||||
retval = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Make sure that the size returned by the adapter (which includes
|
||||
* the header) is less than or equal to the size of a fib, so we
|
||||
* don't corrupt application data. Then copy that size to the user
|
||||
* buffer. (Don't try to add the header information again, since it
|
||||
* was already included by the adapter.)
|
||||
*/
|
||||
|
||||
retval = 0;
|
||||
if (copy_to_user(arg, (void *)kfib, size))
|
||||
retval = -EFAULT;
|
||||
cleanup:
|
||||
if (hw_fib) {
|
||||
pci_free_consistent(dev->pdev, size, kfib, fibptr->hw_fib_pa);
|
||||
fibptr->hw_fib_pa = hw_fib_pa;
|
||||
fibptr->hw_fib_va = hw_fib;
|
||||
}
|
||||
if (retval != -ERESTARTSYS)
|
||||
aac_fib_free(fibptr);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* open_getadapter_fib - Get the next fib
|
||||
*
|
||||
* This routine will get the next Fib, if available, from the AdapterFibContext
|
||||
* passed in from the user.
|
||||
*/
|
||||
|
||||
static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
|
||||
{
|
||||
struct aac_fib_context * fibctx;
|
||||
int status;
|
||||
|
||||
fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL);
|
||||
if (fibctx == NULL) {
|
||||
status = -ENOMEM;
|
||||
} else {
|
||||
unsigned long flags;
|
||||
struct list_head * entry;
|
||||
struct aac_fib_context * context;
|
||||
|
||||
fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
|
||||
fibctx->size = sizeof(struct aac_fib_context);
|
||||
/*
|
||||
* Yes yes, I know this could be an index, but we have a
|
||||
* better guarantee of uniqueness for the locked loop below.
|
||||
* Without the aid of a persistent history, this also helps
|
||||
* reduce the chance that the opaque context would be reused.
|
||||
*/
|
||||
fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF);
|
||||
/*
|
||||
* Initialize the mutex used to wait for the next AIF.
|
||||
*/
|
||||
sema_init(&fibctx->wait_sem, 0);
|
||||
fibctx->wait = 0;
|
||||
/*
|
||||
* Initialize the fibs and set the count of fibs on
|
||||
* the list to 0.
|
||||
*/
|
||||
fibctx->count = 0;
|
||||
INIT_LIST_HEAD(&fibctx->fib_list);
|
||||
fibctx->jiffies = jiffies/HZ;
|
||||
/*
|
||||
* Now add this context onto the adapter's
|
||||
* AdapterFibContext list.
|
||||
*/
|
||||
spin_lock_irqsave(&dev->fib_lock, flags);
|
||||
/* Ensure that we have a unique identifier */
|
||||
entry = dev->fib_list.next;
|
||||
while (entry != &dev->fib_list) {
|
||||
context = list_entry(entry, struct aac_fib_context, next);
|
||||
if (context->unique == fibctx->unique) {
|
||||
/* Not unique (32 bits) */
|
||||
fibctx->unique++;
|
||||
entry = dev->fib_list.next;
|
||||
} else {
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
list_add_tail(&fibctx->next, &dev->fib_list);
|
||||
spin_unlock_irqrestore(&dev->fib_lock, flags);
|
||||
if (copy_to_user(arg, &fibctx->unique,
|
||||
sizeof(fibctx->unique))) {
|
||||
status = -EFAULT;
|
||||
} else {
|
||||
status = 0;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* next_getadapter_fib - get the next fib
|
||||
* @dev: adapter to use
|
||||
* @arg: ioctl argument
|
||||
*
|
||||
* This routine will get the next Fib, if available, from the AdapterFibContext
|
||||
* passed in from the user.
|
||||
*/
|
||||
|
||||
static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
|
||||
{
|
||||
struct fib_ioctl f;
|
||||
struct fib *fib;
|
||||
struct aac_fib_context *fibctx;
|
||||
int status;
|
||||
struct list_head * entry;
|
||||
unsigned long flags;
|
||||
|
||||
if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
|
||||
return -EFAULT;
|
||||
/*
|
||||
* Verify that the HANDLE passed in was a valid AdapterFibContext
|
||||
*
|
||||
* Search the list of AdapterFibContext addresses on the adapter
|
||||
* to be sure this is a valid address
|
||||
*/
|
||||
spin_lock_irqsave(&dev->fib_lock, flags);
|
||||
entry = dev->fib_list.next;
|
||||
fibctx = NULL;
|
||||
|
||||
while (entry != &dev->fib_list) {
|
||||
fibctx = list_entry(entry, struct aac_fib_context, next);
|
||||
/*
|
||||
* Extract the AdapterFibContext from the Input parameters.
|
||||
*/
|
||||
if (fibctx->unique == f.fibctx) { /* We found a winner */
|
||||
break;
|
||||
}
|
||||
entry = entry->next;
|
||||
fibctx = NULL;
|
||||
}
|
||||
if (!fibctx) {
|
||||
spin_unlock_irqrestore(&dev->fib_lock, flags);
|
||||
dprintk ((KERN_INFO "Fib Context not found\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
|
||||
(fibctx->size != sizeof(struct aac_fib_context))) {
|
||||
spin_unlock_irqrestore(&dev->fib_lock, flags);
|
||||
dprintk ((KERN_INFO "Fib Context corrupt?\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
status = 0;
|
||||
/*
|
||||
* If there are no fibs to send back, then either wait or return
|
||||
* -EAGAIN
|
||||
*/
|
||||
return_fib:
|
||||
if (!list_empty(&fibctx->fib_list)) {
|
||||
/*
|
||||
* Pull the next fib from the fibs
|
||||
*/
|
||||
entry = fibctx->fib_list.next;
|
||||
list_del(entry);
|
||||
|
||||
fib = list_entry(entry, struct fib, fiblink);
|
||||
fibctx->count--;
|
||||
spin_unlock_irqrestore(&dev->fib_lock, flags);
|
||||
if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) {
|
||||
kfree(fib->hw_fib_va);
|
||||
kfree(fib);
|
||||
return -EFAULT;
|
||||
}
|
||||
/*
|
||||
* Free the space occupied by this copy of the fib.
|
||||
*/
|
||||
kfree(fib->hw_fib_va);
|
||||
kfree(fib);
|
||||
status = 0;
|
||||
} else {
|
||||
spin_unlock_irqrestore(&dev->fib_lock, flags);
|
||||
/* If someone killed the AIF aacraid thread, restart it */
|
||||
status = !dev->aif_thread;
|
||||
if (status && !dev->in_reset && dev->queues && dev->fsa_dev) {
|
||||
/* Be paranoid, be very paranoid! */
|
||||
kthread_stop(dev->thread);
|
||||
ssleep(1);
|
||||
dev->aif_thread = 0;
|
||||
dev->thread = kthread_run(aac_command_thread, dev,
|
||||
"%s", dev->name);
|
||||
ssleep(1);
|
||||
}
|
||||
if (f.wait) {
|
||||
if(down_interruptible(&fibctx->wait_sem) < 0) {
|
||||
status = -ERESTARTSYS;
|
||||
} else {
|
||||
/* Lock again and retry */
|
||||
spin_lock_irqsave(&dev->fib_lock, flags);
|
||||
goto return_fib;
|
||||
}
|
||||
} else {
|
||||
status = -EAGAIN;
|
||||
}
|
||||
}
|
||||
fibctx->jiffies = jiffies/HZ;
|
||||
return status;
|
||||
}
|
||||
|
||||
int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
|
||||
{
|
||||
struct fib *fib;
|
||||
|
||||
/*
|
||||
* First free any FIBs that have not been consumed.
|
||||
*/
|
||||
while (!list_empty(&fibctx->fib_list)) {
|
||||
struct list_head * entry;
|
||||
/*
|
||||
* Pull the next fib from the fibs
|
||||
*/
|
||||
entry = fibctx->fib_list.next;
|
||||
list_del(entry);
|
||||
fib = list_entry(entry, struct fib, fiblink);
|
||||
fibctx->count--;
|
||||
/*
|
||||
* Free the space occupied by this copy of the fib.
|
||||
*/
|
||||
kfree(fib->hw_fib_va);
|
||||
kfree(fib);
|
||||
}
|
||||
/*
|
||||
* Remove the Context from the AdapterFibContext List
|
||||
*/
|
||||
list_del(&fibctx->next);
|
||||
/*
|
||||
* Invalidate context
|
||||
*/
|
||||
fibctx->type = 0;
|
||||
/*
|
||||
* Free the space occupied by the Context
|
||||
*/
|
||||
kfree(fibctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* close_getadapter_fib - close down user fib context
|
||||
* @dev: adapter
|
||||
* @arg: ioctl arguments
|
||||
*
|
||||
* This routine will close down the fibctx passed in from the user.
|
||||
*/
|
||||
|
||||
static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
|
||||
{
|
||||
struct aac_fib_context *fibctx;
|
||||
int status;
|
||||
unsigned long flags;
|
||||
struct list_head * entry;
|
||||
|
||||
/*
|
||||
* Verify that the HANDLE passed in was a valid AdapterFibContext
|
||||
*
|
||||
* Search the list of AdapterFibContext addresses on the adapter
|
||||
* to be sure this is a valid address
|
||||
*/
|
||||
|
||||
entry = dev->fib_list.next;
|
||||
fibctx = NULL;
|
||||
|
||||
while(entry != &dev->fib_list) {
|
||||
fibctx = list_entry(entry, struct aac_fib_context, next);
|
||||
/*
|
||||
* Extract the fibctx from the input parameters
|
||||
*/
|
||||
if (fibctx->unique == (u32)(uintptr_t)arg) /* We found a winner */
|
||||
break;
|
||||
entry = entry->next;
|
||||
fibctx = NULL;
|
||||
}
|
||||
|
||||
if (!fibctx)
|
||||
return 0; /* Already gone */
|
||||
|
||||
if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
|
||||
(fibctx->size != sizeof(struct aac_fib_context)))
|
||||
return -EINVAL;
|
||||
spin_lock_irqsave(&dev->fib_lock, flags);
|
||||
status = aac_close_fib_context(dev, fibctx);
|
||||
spin_unlock_irqrestore(&dev->fib_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* check_revision - close down user fib context
|
||||
* @dev: adapter
|
||||
* @arg: ioctl arguments
|
||||
*
|
||||
* This routine returns the driver version.
|
||||
* Under Linux, there have been no version incompatibilities, so this is
|
||||
* simple!
|
||||
*/
|
||||
|
||||
static int check_revision(struct aac_dev *dev, void __user *arg)
|
||||
{
|
||||
struct revision response;
|
||||
char *driver_version = aac_driver_version;
|
||||
u32 version;
|
||||
|
||||
response.compat = 1;
|
||||
version = (simple_strtol(driver_version,
|
||||
&driver_version, 10) << 24) | 0x00000400;
|
||||
version += simple_strtol(driver_version + 1, &driver_version, 10) << 16;
|
||||
version += simple_strtol(driver_version + 1, NULL, 10);
|
||||
response.version = cpu_to_le32(version);
|
||||
# ifdef AAC_DRIVER_BUILD
|
||||
response.build = cpu_to_le32(AAC_DRIVER_BUILD);
|
||||
# else
|
||||
response.build = cpu_to_le32(9999);
|
||||
# endif
|
||||
|
||||
if (copy_to_user(arg, &response, sizeof(response)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* aac_send_raw_scb
|
||||
*
|
||||
*/
|
||||
|
||||
static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
|
||||
{
|
||||
struct fib* srbfib;
|
||||
int status;
|
||||
struct aac_srb *srbcmd = NULL;
|
||||
struct user_aac_srb *user_srbcmd = NULL;
|
||||
struct user_aac_srb __user *user_srb = arg;
|
||||
struct aac_srb_reply __user *user_reply;
|
||||
struct aac_srb_reply* reply;
|
||||
u32 fibsize = 0;
|
||||
u32 flags = 0;
|
||||
s32 rcode = 0;
|
||||
u32 data_dir;
|
||||
void __user *sg_user[32];
|
||||
void *sg_list[32];
|
||||
u32 sg_indx = 0;
|
||||
u32 byte_count = 0;
|
||||
u32 actual_fibsize64, actual_fibsize = 0;
|
||||
int i;
|
||||
|
||||
|
||||
if (dev->in_reset) {
|
||||
dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n"));
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!capable(CAP_SYS_ADMIN)){
|
||||
dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n"));
|
||||
return -EPERM;
|
||||
}
|
||||
/*
|
||||
* Allocate and initialize a Fib then setup a SRB command
|
||||
*/
|
||||
if (!(srbfib = aac_fib_alloc(dev))) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
aac_fib_init(srbfib);
|
||||
/* raw_srb FIB is not FastResponseCapable */
|
||||
srbfib->hw_fib_va->header.XferState &= ~cpu_to_le32(FastResponseCapable);
|
||||
|
||||
srbcmd = (struct aac_srb*) fib_data(srbfib);
|
||||
|
||||
memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */
|
||||
if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
|
||||
dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n"));
|
||||
rcode = -EFAULT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((fibsize < (sizeof(struct user_aac_srb) - sizeof(struct user_sgentry))) ||
|
||||
(fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))) {
|
||||
rcode = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
user_srbcmd = kmalloc(fibsize, GFP_KERNEL);
|
||||
if (!user_srbcmd) {
|
||||
dprintk((KERN_DEBUG"aacraid: Could not make a copy of the srb\n"));
|
||||
rcode = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
if(copy_from_user(user_srbcmd, user_srb,fibsize)){
|
||||
dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n"));
|
||||
rcode = -EFAULT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
user_reply = arg+fibsize;
|
||||
|
||||
flags = user_srbcmd->flags; /* from user in cpu order */
|
||||
// Fix up srb for endian and force some values
|
||||
|
||||
srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this
|
||||
srbcmd->channel = cpu_to_le32(user_srbcmd->channel);
|
||||
srbcmd->id = cpu_to_le32(user_srbcmd->id);
|
||||
srbcmd->lun = cpu_to_le32(user_srbcmd->lun);
|
||||
srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout);
|
||||
srbcmd->flags = cpu_to_le32(flags);
|
||||
srbcmd->retry_limit = 0; // Obsolete parameter
|
||||
srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size);
|
||||
memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb));
|
||||
|
||||
switch (flags & (SRB_DataIn | SRB_DataOut)) {
|
||||
case SRB_DataOut:
|
||||
data_dir = DMA_TO_DEVICE;
|
||||
break;
|
||||
case (SRB_DataIn | SRB_DataOut):
|
||||
data_dir = DMA_BIDIRECTIONAL;
|
||||
break;
|
||||
case SRB_DataIn:
|
||||
data_dir = DMA_FROM_DEVICE;
|
||||
break;
|
||||
default:
|
||||
data_dir = DMA_NONE;
|
||||
}
|
||||
if (user_srbcmd->sg.count > ARRAY_SIZE(sg_list)) {
|
||||
dprintk((KERN_DEBUG"aacraid: too many sg entries %d\n",
|
||||
le32_to_cpu(srbcmd->sg.count)));
|
||||
rcode = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) +
|
||||
((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry));
|
||||
actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) *
|
||||
(sizeof(struct sgentry64) - sizeof(struct sgentry));
|
||||
/* User made a mistake - should not continue */
|
||||
if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) {
|
||||
dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
|
||||
"Raw SRB command calculated fibsize=%lu;%lu "
|
||||
"user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu "
|
||||
"issued fibsize=%d\n",
|
||||
actual_fibsize, actual_fibsize64, user_srbcmd->sg.count,
|
||||
sizeof(struct aac_srb), sizeof(struct sgentry),
|
||||
sizeof(struct sgentry64), fibsize));
|
||||
rcode = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) {
|
||||
dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
|
||||
rcode = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
byte_count = 0;
|
||||
if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) {
|
||||
struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg;
|
||||
struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
|
||||
|
||||
/*
|
||||
* This should also catch if user used the 32 bit sgmap
|
||||
*/
|
||||
if (actual_fibsize64 == fibsize) {
|
||||
actual_fibsize = actual_fibsize64;
|
||||
for (i = 0; i < upsg->count; i++) {
|
||||
u64 addr;
|
||||
void* p;
|
||||
if (upsg->sg[i].count >
|
||||
((dev->adapter_info.options &
|
||||
AAC_OPT_NEW_COMM) ?
|
||||
(dev->scsi_host_ptr->max_sectors << 9) :
|
||||
65536)) {
|
||||
rcode = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Does this really need to be GFP_DMA? */
|
||||
p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA);
|
||||
if(!p) {
|
||||
dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
|
||||
upsg->sg[i].count,i,upsg->count));
|
||||
rcode = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
addr = (u64)upsg->sg[i].addr[0];
|
||||
addr += ((u64)upsg->sg[i].addr[1]) << 32;
|
||||
sg_user[i] = (void __user *)(uintptr_t)addr;
|
||||
sg_list[i] = p; // save so we can clean up later
|
||||
sg_indx = i;
|
||||
|
||||
if (flags & SRB_DataOut) {
|
||||
if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
|
||||
dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
|
||||
rcode = -EFAULT;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
addr = pci_map_single(dev->pdev, p, upsg->sg[i].count, data_dir);
|
||||
|
||||
psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
|
||||
psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
|
||||
byte_count += upsg->sg[i].count;
|
||||
psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
|
||||
}
|
||||
} else {
|
||||
struct user_sgmap* usg;
|
||||
usg = kmalloc(actual_fibsize - sizeof(struct aac_srb)
|
||||
+ sizeof(struct sgmap), GFP_KERNEL);
|
||||
if (!usg) {
|
||||
dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n"));
|
||||
rcode = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb)
|
||||
+ sizeof(struct sgmap));
|
||||
actual_fibsize = actual_fibsize64;
|
||||
|
||||
for (i = 0; i < usg->count; i++) {
|
||||
u64 addr;
|
||||
void* p;
|
||||
if (usg->sg[i].count >
|
||||
((dev->adapter_info.options &
|
||||
AAC_OPT_NEW_COMM) ?
|
||||
(dev->scsi_host_ptr->max_sectors << 9) :
|
||||
65536)) {
|
||||
kfree(usg);
|
||||
rcode = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Does this really need to be GFP_DMA? */
|
||||
p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
|
||||
if(!p) {
|
||||
dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
|
||||
usg->sg[i].count,i,usg->count));
|
||||
kfree(usg);
|
||||
rcode = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
sg_user[i] = (void __user *)(uintptr_t)usg->sg[i].addr;
|
||||
sg_list[i] = p; // save so we can clean up later
|
||||
sg_indx = i;
|
||||
|
||||
if (flags & SRB_DataOut) {
|
||||
if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
|
||||
kfree (usg);
|
||||
dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
|
||||
rcode = -EFAULT;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
|
||||
|
||||
psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
|
||||
psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
|
||||
byte_count += usg->sg[i].count;
|
||||
psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
|
||||
}
|
||||
kfree (usg);
|
||||
}
|
||||
srbcmd->count = cpu_to_le32(byte_count);
|
||||
psg->count = cpu_to_le32(sg_indx+1);
|
||||
status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL);
|
||||
} else {
|
||||
struct user_sgmap* upsg = &user_srbcmd->sg;
|
||||
struct sgmap* psg = &srbcmd->sg;
|
||||
|
||||
if (actual_fibsize64 == fibsize) {
|
||||
struct user_sgmap64* usg = (struct user_sgmap64 *)upsg;
|
||||
for (i = 0; i < upsg->count; i++) {
|
||||
uintptr_t addr;
|
||||
void* p;
|
||||
if (usg->sg[i].count >
|
||||
((dev->adapter_info.options &
|
||||
AAC_OPT_NEW_COMM) ?
|
||||
(dev->scsi_host_ptr->max_sectors << 9) :
|
||||
65536)) {
|
||||
rcode = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Does this really need to be GFP_DMA? */
|
||||
p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
|
||||
if(!p) {
|
||||
dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
|
||||
usg->sg[i].count,i,usg->count));
|
||||
rcode = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
addr = (u64)usg->sg[i].addr[0];
|
||||
addr += ((u64)usg->sg[i].addr[1]) << 32;
|
||||
sg_user[i] = (void __user *)addr;
|
||||
sg_list[i] = p; // save so we can clean up later
|
||||
sg_indx = i;
|
||||
|
||||
if (flags & SRB_DataOut) {
|
||||
if(copy_from_user(p,sg_user[i],usg->sg[i].count)){
|
||||
dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
|
||||
rcode = -EFAULT;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
|
||||
|
||||
psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff);
|
||||
byte_count += usg->sg[i].count;
|
||||
psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < upsg->count; i++) {
|
||||
dma_addr_t addr;
|
||||
void* p;
|
||||
if (upsg->sg[i].count >
|
||||
((dev->adapter_info.options &
|
||||
AAC_OPT_NEW_COMM) ?
|
||||
(dev->scsi_host_ptr->max_sectors << 9) :
|
||||
65536)) {
|
||||
rcode = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
|
||||
if (!p) {
|
||||
dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
|
||||
upsg->sg[i].count, i, upsg->count));
|
||||
rcode = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
sg_user[i] = (void __user *)(uintptr_t)upsg->sg[i].addr;
|
||||
sg_list[i] = p; // save so we can clean up later
|
||||
sg_indx = i;
|
||||
|
||||
if (flags & SRB_DataOut) {
|
||||
if(copy_from_user(p, sg_user[i],
|
||||
upsg->sg[i].count)) {
|
||||
dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
|
||||
rcode = -EFAULT;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
addr = pci_map_single(dev->pdev, p,
|
||||
upsg->sg[i].count, data_dir);
|
||||
|
||||
psg->sg[i].addr = cpu_to_le32(addr);
|
||||
byte_count += upsg->sg[i].count;
|
||||
psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
|
||||
}
|
||||
}
|
||||
srbcmd->count = cpu_to_le32(byte_count);
|
||||
psg->count = cpu_to_le32(sg_indx+1);
|
||||
status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
|
||||
}
|
||||
if (status == -ERESTARTSYS) {
|
||||
rcode = -ERESTARTSYS;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (status != 0){
|
||||
dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"));
|
||||
rcode = -ENXIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (flags & SRB_DataIn) {
|
||||
for(i = 0 ; i <= sg_indx; i++){
|
||||
byte_count = le32_to_cpu(
|
||||
(dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)
|
||||
? ((struct sgmap64*)&srbcmd->sg)->sg[i].count
|
||||
: srbcmd->sg.sg[i].count);
|
||||
if(copy_to_user(sg_user[i], sg_list[i], byte_count)){
|
||||
dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n"));
|
||||
rcode = -EFAULT;
|
||||
goto cleanup;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reply = (struct aac_srb_reply *) fib_data(srbfib);
|
||||
if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
|
||||
dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n"));
|
||||
rcode = -EFAULT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
kfree(user_srbcmd);
|
||||
for(i=0; i <= sg_indx; i++){
|
||||
kfree(sg_list[i]);
|
||||
}
|
||||
if (rcode != -ERESTARTSYS) {
|
||||
aac_fib_complete(srbfib);
|
||||
aac_fib_free(srbfib);
|
||||
}
|
||||
|
||||
return rcode;
|
||||
}
|
||||
|
||||
struct aac_pci_info {
|
||||
u32 bus;
|
||||
u32 slot;
|
||||
};
|
||||
|
||||
|
||||
static int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
|
||||
{
|
||||
struct aac_pci_info pci_info;
|
||||
|
||||
pci_info.bus = dev->pdev->bus->number;
|
||||
pci_info.slot = PCI_SLOT(dev->pdev->devfn);
|
||||
|
||||
if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
|
||||
dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* HBA gets first crack
|
||||
*/
|
||||
|
||||
status = aac_dev_ioctl(dev, cmd, arg);
|
||||
if (status != -ENOTTY)
|
||||
return status;
|
||||
|
||||
switch (cmd) {
|
||||
case FSACTL_MINIPORT_REV_CHECK:
|
||||
status = check_revision(dev, arg);
|
||||
break;
|
||||
case FSACTL_SEND_LARGE_FIB:
|
||||
case FSACTL_SENDFIB:
|
||||
status = ioctl_send_fib(dev, arg);
|
||||
break;
|
||||
case FSACTL_OPEN_GET_ADAPTER_FIB:
|
||||
status = open_getadapter_fib(dev, arg);
|
||||
break;
|
||||
case FSACTL_GET_NEXT_ADAPTER_FIB:
|
||||
status = next_getadapter_fib(dev, arg);
|
||||
break;
|
||||
case FSACTL_CLOSE_GET_ADAPTER_FIB:
|
||||
status = close_getadapter_fib(dev, arg);
|
||||
break;
|
||||
case FSACTL_SEND_RAW_SRB:
|
||||
status = aac_send_raw_srb(dev,arg);
|
||||
break;
|
||||
case FSACTL_GET_PCI_INFO:
|
||||
status = aac_get_pci_info(dev,arg);
|
||||
break;
|
||||
default:
|
||||
status = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
492
drivers/scsi/aacraid/comminit.c
Normal file
492
drivers/scsi/aacraid/comminit.c
Normal file
|
@ -0,0 +1,492 @@
|
|||
/*
|
||||
* 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 PMC-Sierra, Inc. (aacraid@pmc-sierra.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
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Module Name:
|
||||
* comminit.c
|
||||
*
|
||||
* Abstract: This supports the initialization of the host adapter commuication interface.
|
||||
* This is a platform dependent module for the pci cyclone board.
|
||||
*
|
||||
*/
|
||||
|
||||
#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/completion.h>
|
||||
#include <linux/mm.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include "aacraid.h"
|
||||
|
||||
struct aac_common aac_config = {
|
||||
.irq_mod = 1
|
||||
};
|
||||
|
||||
static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign)
|
||||
{
|
||||
unsigned char *base;
|
||||
unsigned long size, align;
|
||||
const unsigned long fibsize = 4096;
|
||||
const unsigned long printfbufsiz = 256;
|
||||
unsigned long host_rrq_size = 0;
|
||||
struct aac_init *init;
|
||||
dma_addr_t phys;
|
||||
unsigned long aac_max_hostphysmempages;
|
||||
|
||||
if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 ||
|
||||
dev->comm_interface == AAC_COMM_MESSAGE_TYPE2)
|
||||
host_rrq_size = (dev->scsi_host_ptr->can_queue
|
||||
+ AAC_NUM_MGT_FIB) * sizeof(u32);
|
||||
size = fibsize + sizeof(struct aac_init) + commsize +
|
||||
commalign + printfbufsiz + host_rrq_size;
|
||||
|
||||
base = pci_alloc_consistent(dev->pdev, size, &phys);
|
||||
|
||||
if(base == NULL)
|
||||
{
|
||||
printk(KERN_ERR "aacraid: unable to create mapping.\n");
|
||||
return 0;
|
||||
}
|
||||
dev->comm_addr = (void *)base;
|
||||
dev->comm_phys = phys;
|
||||
dev->comm_size = size;
|
||||
|
||||
if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 ||
|
||||
dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
|
||||
dev->host_rrq = (u32 *)(base + fibsize);
|
||||
dev->host_rrq_pa = phys + fibsize;
|
||||
memset(dev->host_rrq, 0, host_rrq_size);
|
||||
}
|
||||
|
||||
dev->init = (struct aac_init *)(base + fibsize + host_rrq_size);
|
||||
dev->init_pa = phys + fibsize + host_rrq_size;
|
||||
|
||||
init = dev->init;
|
||||
|
||||
init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
|
||||
if (dev->max_fib_size != sizeof(struct hw_fib))
|
||||
init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4);
|
||||
init->MiniPortRevision = cpu_to_le32(Sa_MINIPORT_REVISION);
|
||||
init->fsrev = cpu_to_le32(dev->fsrev);
|
||||
|
||||
/*
|
||||
* Adapter Fibs are the first thing allocated so that they
|
||||
* start page aligned
|
||||
*/
|
||||
dev->aif_base_va = (struct hw_fib *)base;
|
||||
|
||||
init->AdapterFibsVirtualAddress = 0;
|
||||
init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys);
|
||||
init->AdapterFibsSize = cpu_to_le32(fibsize);
|
||||
init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
|
||||
/*
|
||||
* number of 4k pages of host physical memory. The aacraid fw needs
|
||||
* this number to be less than 4gb worth of pages. New firmware doesn't
|
||||
* have any issues with the mapping system, but older Firmware did, and
|
||||
* had *troubles* dealing with the math overloading past 32 bits, thus
|
||||
* we must limit this field.
|
||||
*/
|
||||
aac_max_hostphysmempages = dma_get_required_mask(&dev->pdev->dev) >> 12;
|
||||
if (aac_max_hostphysmempages < AAC_MAX_HOSTPHYSMEMPAGES)
|
||||
init->HostPhysMemPages = cpu_to_le32(aac_max_hostphysmempages);
|
||||
else
|
||||
init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES);
|
||||
|
||||
init->InitFlags = cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME |
|
||||
INITFLAGS_DRIVER_SUPPORTS_PM);
|
||||
init->MaxIoCommands = cpu_to_le32(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
|
||||
init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
|
||||
init->MaxFibSize = cpu_to_le32(dev->max_fib_size);
|
||||
init->MaxNumAif = cpu_to_le32(dev->max_num_aif);
|
||||
|
||||
if (dev->comm_interface == AAC_COMM_MESSAGE) {
|
||||
init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
|
||||
dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n"));
|
||||
} else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) {
|
||||
init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_6);
|
||||
init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED |
|
||||
INITFLAGS_NEW_COMM_TYPE1_SUPPORTED | INITFLAGS_FAST_JBOD_SUPPORTED);
|
||||
init->HostRRQ_AddrHigh = cpu_to_le32((u32)((u64)dev->host_rrq_pa >> 32));
|
||||
init->HostRRQ_AddrLow = cpu_to_le32((u32)(dev->host_rrq_pa & 0xffffffff));
|
||||
dprintk((KERN_WARNING"aacraid: New Comm Interface type1 enabled\n"));
|
||||
} else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
|
||||
init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_7);
|
||||
init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED |
|
||||
INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | INITFLAGS_FAST_JBOD_SUPPORTED);
|
||||
init->HostRRQ_AddrHigh = cpu_to_le32((u32)((u64)dev->host_rrq_pa >> 32));
|
||||
init->HostRRQ_AddrLow = cpu_to_le32((u32)(dev->host_rrq_pa & 0xffffffff));
|
||||
init->MiniPortRevision = cpu_to_le32(0L); /* number of MSI-X */
|
||||
dprintk((KERN_WARNING"aacraid: New Comm Interface type2 enabled\n"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment the base address by the amount already used
|
||||
*/
|
||||
base = base + fibsize + host_rrq_size + sizeof(struct aac_init);
|
||||
phys = (dma_addr_t)((ulong)phys + fibsize + host_rrq_size +
|
||||
sizeof(struct aac_init));
|
||||
|
||||
/*
|
||||
* Align the beginning of Headers to commalign
|
||||
*/
|
||||
align = (commalign - ((uintptr_t)(base) & (commalign - 1)));
|
||||
base = base + align;
|
||||
phys = phys + align;
|
||||
/*
|
||||
* Fill in addresses of the Comm Area Headers and Queues
|
||||
*/
|
||||
*commaddr = base;
|
||||
init->CommHeaderAddress = cpu_to_le32((u32)phys);
|
||||
/*
|
||||
* Increment the base address by the size of the CommArea
|
||||
*/
|
||||
base = base + commsize;
|
||||
phys = phys + commsize;
|
||||
/*
|
||||
* Place the Printf buffer area after the Fast I/O comm area.
|
||||
*/
|
||||
dev->printfbuf = (void *)base;
|
||||
init->printfbuf = cpu_to_le32(phys);
|
||||
init->printfbufsiz = cpu_to_le32(printfbufsiz);
|
||||
memset(base, 0, printfbufsiz);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, int qsize)
|
||||
{
|
||||
q->numpending = 0;
|
||||
q->dev = dev;
|
||||
init_waitqueue_head(&q->cmdready);
|
||||
INIT_LIST_HEAD(&q->cmdq);
|
||||
init_waitqueue_head(&q->qfull);
|
||||
spin_lock_init(&q->lockdata);
|
||||
q->lock = &q->lockdata;
|
||||
q->headers.producer = (__le32 *)mem;
|
||||
q->headers.consumer = (__le32 *)(mem+1);
|
||||
*(q->headers.producer) = cpu_to_le32(qsize);
|
||||
*(q->headers.consumer) = cpu_to_le32(qsize);
|
||||
q->entries = qsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_send_shutdown - shutdown an adapter
|
||||
* @dev: Adapter to shutdown
|
||||
*
|
||||
* This routine will send a VM_CloseAll (shutdown) request to the adapter.
|
||||
*/
|
||||
|
||||
int aac_send_shutdown(struct aac_dev * dev)
|
||||
{
|
||||
struct fib * fibctx;
|
||||
struct aac_close *cmd;
|
||||
int status;
|
||||
|
||||
fibctx = aac_fib_alloc(dev);
|
||||
if (!fibctx)
|
||||
return -ENOMEM;
|
||||
aac_fib_init(fibctx);
|
||||
|
||||
cmd = (struct aac_close *) fib_data(fibctx);
|
||||
|
||||
cmd->command = cpu_to_le32(VM_CloseAll);
|
||||
cmd->cid = cpu_to_le32(0xfffffffe);
|
||||
|
||||
status = aac_fib_send(ContainerCommand,
|
||||
fibctx,
|
||||
sizeof(struct aac_close),
|
||||
FsaNormal,
|
||||
-2 /* Timeout silently */, 1,
|
||||
NULL, NULL);
|
||||
|
||||
if (status >= 0)
|
||||
aac_fib_complete(fibctx);
|
||||
/* FIB should be freed only after getting the response from the F/W */
|
||||
if (status != -ERESTARTSYS)
|
||||
aac_fib_free(fibctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_comm_init - Initialise FSA data structures
|
||||
* @dev: Adapter to initialise
|
||||
*
|
||||
* Initializes the data structures that are required for the FSA commuication
|
||||
* interface to operate.
|
||||
* Returns
|
||||
* 1 - if we were able to init the commuication interface.
|
||||
* 0 - If there were errors initing. This is a fatal error.
|
||||
*/
|
||||
|
||||
static int aac_comm_init(struct aac_dev * dev)
|
||||
{
|
||||
unsigned long hdrsize = (sizeof(u32) * NUMBER_OF_COMM_QUEUES) * 2;
|
||||
unsigned long queuesize = sizeof(struct aac_entry) * TOTAL_QUEUE_ENTRIES;
|
||||
u32 *headers;
|
||||
struct aac_entry * queues;
|
||||
unsigned long size;
|
||||
struct aac_queue_block * comm = dev->queues;
|
||||
/*
|
||||
* Now allocate and initialize the zone structures used as our
|
||||
* pool of FIB context records. The size of the zone is based
|
||||
* on the system memory size. We also initialize the mutex used
|
||||
* to protect the zone.
|
||||
*/
|
||||
spin_lock_init(&dev->fib_lock);
|
||||
|
||||
/*
|
||||
* Allocate the physically contiguous space for the commuication
|
||||
* queue headers.
|
||||
*/
|
||||
|
||||
size = hdrsize + queuesize;
|
||||
|
||||
if (!aac_alloc_comm(dev, (void * *)&headers, size, QUEUE_ALIGNMENT))
|
||||
return -ENOMEM;
|
||||
|
||||
queues = (struct aac_entry *)(((ulong)headers) + hdrsize);
|
||||
|
||||
/* Adapter to Host normal priority Command queue */
|
||||
comm->queue[HostNormCmdQueue].base = queues;
|
||||
aac_queue_init(dev, &comm->queue[HostNormCmdQueue], headers, HOST_NORM_CMD_ENTRIES);
|
||||
queues += HOST_NORM_CMD_ENTRIES;
|
||||
headers += 2;
|
||||
|
||||
/* Adapter to Host high priority command queue */
|
||||
comm->queue[HostHighCmdQueue].base = queues;
|
||||
aac_queue_init(dev, &comm->queue[HostHighCmdQueue], headers, HOST_HIGH_CMD_ENTRIES);
|
||||
|
||||
queues += HOST_HIGH_CMD_ENTRIES;
|
||||
headers +=2;
|
||||
|
||||
/* Host to adapter normal priority command queue */
|
||||
comm->queue[AdapNormCmdQueue].base = queues;
|
||||
aac_queue_init(dev, &comm->queue[AdapNormCmdQueue], headers, ADAP_NORM_CMD_ENTRIES);
|
||||
|
||||
queues += ADAP_NORM_CMD_ENTRIES;
|
||||
headers += 2;
|
||||
|
||||
/* host to adapter high priority command queue */
|
||||
comm->queue[AdapHighCmdQueue].base = queues;
|
||||
aac_queue_init(dev, &comm->queue[AdapHighCmdQueue], headers, ADAP_HIGH_CMD_ENTRIES);
|
||||
|
||||
queues += ADAP_HIGH_CMD_ENTRIES;
|
||||
headers += 2;
|
||||
|
||||
/* adapter to host normal priority response queue */
|
||||
comm->queue[HostNormRespQueue].base = queues;
|
||||
aac_queue_init(dev, &comm->queue[HostNormRespQueue], headers, HOST_NORM_RESP_ENTRIES);
|
||||
queues += HOST_NORM_RESP_ENTRIES;
|
||||
headers += 2;
|
||||
|
||||
/* adapter to host high priority response queue */
|
||||
comm->queue[HostHighRespQueue].base = queues;
|
||||
aac_queue_init(dev, &comm->queue[HostHighRespQueue], headers, HOST_HIGH_RESP_ENTRIES);
|
||||
|
||||
queues += HOST_HIGH_RESP_ENTRIES;
|
||||
headers += 2;
|
||||
|
||||
/* host to adapter normal priority response queue */
|
||||
comm->queue[AdapNormRespQueue].base = queues;
|
||||
aac_queue_init(dev, &comm->queue[AdapNormRespQueue], headers, ADAP_NORM_RESP_ENTRIES);
|
||||
|
||||
queues += ADAP_NORM_RESP_ENTRIES;
|
||||
headers += 2;
|
||||
|
||||
/* host to adapter high priority response queue */
|
||||
comm->queue[AdapHighRespQueue].base = queues;
|
||||
aac_queue_init(dev, &comm->queue[AdapHighRespQueue], headers, ADAP_HIGH_RESP_ENTRIES);
|
||||
|
||||
comm->queue[AdapNormCmdQueue].lock = comm->queue[HostNormRespQueue].lock;
|
||||
comm->queue[AdapHighCmdQueue].lock = comm->queue[HostHighRespQueue].lock;
|
||||
comm->queue[AdapNormRespQueue].lock = comm->queue[HostNormCmdQueue].lock;
|
||||
comm->queue[AdapHighRespQueue].lock = comm->queue[HostHighCmdQueue].lock;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct aac_dev *aac_init_adapter(struct aac_dev *dev)
|
||||
{
|
||||
u32 status[5];
|
||||
struct Scsi_Host * host = dev->scsi_host_ptr;
|
||||
extern int aac_sync_mode;
|
||||
|
||||
/*
|
||||
* Check the preferred comm settings, defaults from template.
|
||||
*/
|
||||
dev->management_fib_count = 0;
|
||||
spin_lock_init(&dev->manage_lock);
|
||||
spin_lock_init(&dev->sync_lock);
|
||||
dev->max_fib_size = sizeof(struct hw_fib);
|
||||
dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size
|
||||
- sizeof(struct aac_fibhdr)
|
||||
- sizeof(struct aac_write) + sizeof(struct sgentry))
|
||||
/ sizeof(struct sgentry);
|
||||
dev->comm_interface = AAC_COMM_PRODUCER;
|
||||
dev->raw_io_interface = dev->raw_io_64 = 0;
|
||||
|
||||
if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
|
||||
0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) &&
|
||||
(status[0] == 0x00000001)) {
|
||||
if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
|
||||
dev->raw_io_64 = 1;
|
||||
dev->sync_mode = aac_sync_mode;
|
||||
if (dev->a_ops.adapter_comm &&
|
||||
(status[1] & le32_to_cpu(AAC_OPT_NEW_COMM))) {
|
||||
dev->comm_interface = AAC_COMM_MESSAGE;
|
||||
dev->raw_io_interface = 1;
|
||||
if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1))) {
|
||||
/* driver supports TYPE1 (Tupelo) */
|
||||
dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
|
||||
} else if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE2))) {
|
||||
/* driver supports TYPE2 (Denali) */
|
||||
dev->comm_interface = AAC_COMM_MESSAGE_TYPE2;
|
||||
} else if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE4)) ||
|
||||
(status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE3))) {
|
||||
/* driver doesn't TYPE3 and TYPE4 */
|
||||
/* switch to sync. mode */
|
||||
dev->comm_interface = AAC_COMM_MESSAGE_TYPE2;
|
||||
dev->sync_mode = 1;
|
||||
}
|
||||
}
|
||||
if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
|
||||
(status[2] > dev->base_size)) {
|
||||
aac_adapter_ioremap(dev, 0);
|
||||
dev->base_size = status[2];
|
||||
if (aac_adapter_ioremap(dev, status[2])) {
|
||||
/* remap failed, go back ... */
|
||||
dev->comm_interface = AAC_COMM_PRODUCER;
|
||||
if (aac_adapter_ioremap(dev, AAC_MIN_FOOTPRINT_SIZE)) {
|
||||
printk(KERN_WARNING
|
||||
"aacraid: unable to map adapter.\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((!aac_adapter_sync_cmd(dev, GET_COMM_PREFERRED_SETTINGS,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
status+0, status+1, status+2, status+3, status+4))
|
||||
&& (status[0] == 0x00000001)) {
|
||||
/*
|
||||
* status[1] >> 16 maximum command size in KB
|
||||
* status[1] & 0xFFFF maximum FIB size
|
||||
* status[2] >> 16 maximum SG elements to driver
|
||||
* status[2] & 0xFFFF maximum SG elements from driver
|
||||
* status[3] & 0xFFFF maximum number FIBs outstanding
|
||||
*/
|
||||
host->max_sectors = (status[1] >> 16) << 1;
|
||||
/* Multiple of 32 for PMC */
|
||||
dev->max_fib_size = status[1] & 0xFFE0;
|
||||
host->sg_tablesize = status[2] >> 16;
|
||||
dev->sg_tablesize = status[2] & 0xFFFF;
|
||||
if (dev->pdev->device == PMC_DEVICE_S7 ||
|
||||
dev->pdev->device == PMC_DEVICE_S8 ||
|
||||
dev->pdev->device == PMC_DEVICE_S9)
|
||||
host->can_queue = ((status[3] >> 16) ? (status[3] >> 16) :
|
||||
(status[3] & 0xFFFF)) - AAC_NUM_MGT_FIB;
|
||||
else
|
||||
host->can_queue = (status[3] & 0xFFFF) - AAC_NUM_MGT_FIB;
|
||||
dev->max_num_aif = status[4] & 0xFFFF;
|
||||
/*
|
||||
* NOTE:
|
||||
* All these overrides are based on a fixed internal
|
||||
* knowledge and understanding of existing adapters,
|
||||
* acbsize should be set with caution.
|
||||
*/
|
||||
if (acbsize == 512) {
|
||||
host->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
|
||||
dev->max_fib_size = 512;
|
||||
dev->sg_tablesize = host->sg_tablesize
|
||||
= (512 - sizeof(struct aac_fibhdr)
|
||||
- sizeof(struct aac_write) + sizeof(struct sgentry))
|
||||
/ sizeof(struct sgentry);
|
||||
host->can_queue = AAC_NUM_IO_FIB;
|
||||
} else if (acbsize == 2048) {
|
||||
host->max_sectors = 512;
|
||||
dev->max_fib_size = 2048;
|
||||
host->sg_tablesize = 65;
|
||||
dev->sg_tablesize = 81;
|
||||
host->can_queue = 512 - AAC_NUM_MGT_FIB;
|
||||
} else if (acbsize == 4096) {
|
||||
host->max_sectors = 1024;
|
||||
dev->max_fib_size = 4096;
|
||||
host->sg_tablesize = 129;
|
||||
dev->sg_tablesize = 166;
|
||||
host->can_queue = 256 - AAC_NUM_MGT_FIB;
|
||||
} else if (acbsize == 8192) {
|
||||
host->max_sectors = 2048;
|
||||
dev->max_fib_size = 8192;
|
||||
host->sg_tablesize = 257;
|
||||
dev->sg_tablesize = 337;
|
||||
host->can_queue = 128 - AAC_NUM_MGT_FIB;
|
||||
} else if (acbsize > 0) {
|
||||
printk("Illegal acbsize=%d ignored\n", acbsize);
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
if (numacb > 0) {
|
||||
if (numacb < host->can_queue)
|
||||
host->can_queue = numacb;
|
||||
else
|
||||
printk("numacb=%d ignored\n", numacb);
|
||||
}
|
||||
}
|
||||
|
||||
if (host->can_queue > AAC_NUM_IO_FIB)
|
||||
host->can_queue = AAC_NUM_IO_FIB;
|
||||
|
||||
/*
|
||||
* Ok now init the communication subsystem
|
||||
*/
|
||||
|
||||
dev->queues = kzalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
|
||||
if (dev->queues == NULL) {
|
||||
printk(KERN_ERR "Error could not allocate comm region.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (aac_comm_init(dev)<0){
|
||||
kfree(dev->queues);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Initialize the list of fibs
|
||||
*/
|
||||
if (aac_fib_setup(dev) < 0) {
|
||||
kfree(dev->queues);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&dev->fib_list);
|
||||
INIT_LIST_HEAD(&dev->sync_fib_list);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
1930
drivers/scsi/aacraid/commsup.c
Normal file
1930
drivers/scsi/aacraid/commsup.c
Normal file
File diff suppressed because it is too large
Load diff
420
drivers/scsi/aacraid/dpcsup.c
Normal file
420
drivers/scsi/aacraid/dpcsup.c
Normal file
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
* 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 PMC-Sierra, Inc. (aacraid@pmc-sierra.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
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Module Name:
|
||||
* dpcsup.c
|
||||
*
|
||||
* Abstract: All DPC processing routines for the cyclone board occur here.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/semaphore.h>
|
||||
|
||||
#include "aacraid.h"
|
||||
|
||||
/**
|
||||
* aac_response_normal - Handle command replies
|
||||
* @q: Queue to read from
|
||||
*
|
||||
* This DPC routine will be run when the adapter interrupts us to let us
|
||||
* 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. We will
|
||||
* take a spinlock out on the queue before operating on it.
|
||||
*/
|
||||
|
||||
unsigned int aac_response_normal(struct aac_queue * q)
|
||||
{
|
||||
struct aac_dev * dev = q->dev;
|
||||
struct aac_entry *entry;
|
||||
struct hw_fib * hwfib;
|
||||
struct fib * fib;
|
||||
int consumed = 0;
|
||||
unsigned long flags, mflags;
|
||||
|
||||
spin_lock_irqsave(q->lock, flags);
|
||||
/*
|
||||
* Keep pulling response QEs off the response queue and waking
|
||||
* up the waiters until there are no more QEs. We then return
|
||||
* back to the system. If no response was requesed we just
|
||||
* deallocate the Fib here and continue.
|
||||
*/
|
||||
while(aac_consumer_get(dev, q, &entry))
|
||||
{
|
||||
int fast;
|
||||
u32 index = le32_to_cpu(entry->addr);
|
||||
fast = index & 0x01;
|
||||
fib = &dev->fibs[index >> 2];
|
||||
hwfib = fib->hw_fib_va;
|
||||
|
||||
aac_consumer_free(dev, q, HostNormRespQueue);
|
||||
/*
|
||||
* Remove this fib from the Outstanding I/O queue.
|
||||
* But only if it has not already been timed out.
|
||||
*
|
||||
* If the fib has been timed out already, then just
|
||||
* continue. The caller has already been notified that
|
||||
* the fib timed out.
|
||||
*/
|
||||
dev->queues->queue[AdapNormCmdQueue].numpending--;
|
||||
|
||||
if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
|
||||
spin_unlock_irqrestore(q->lock, flags);
|
||||
aac_fib_complete(fib);
|
||||
aac_fib_free(fib);
|
||||
spin_lock_irqsave(q->lock, flags);
|
||||
continue;
|
||||
}
|
||||
spin_unlock_irqrestore(q->lock, flags);
|
||||
|
||||
if (fast) {
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
fib->flags &= FIB_CONTEXT_FLAG_FASTRESP;
|
||||
fib->callback(fib->callback_data, fib);
|
||||
} else {
|
||||
unsigned long flagv;
|
||||
spin_lock_irqsave(&fib->event_lock, flagv);
|
||||
if (!fib->done) {
|
||||
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 (fib->done == 2) {
|
||||
spin_lock_irqsave(&fib->event_lock, flagv);
|
||||
fib->done = 0;
|
||||
spin_unlock_irqrestore(&fib->event_lock, flagv);
|
||||
aac_fib_complete(fib);
|
||||
aac_fib_free(fib);
|
||||
}
|
||||
}
|
||||
consumed++;
|
||||
spin_lock_irqsave(q->lock, flags);
|
||||
}
|
||||
|
||||
if (consumed > aac_config.peak_fibs)
|
||||
aac_config.peak_fibs = consumed;
|
||||
if (consumed == 0)
|
||||
aac_config.zero_fibs++;
|
||||
|
||||
spin_unlock_irqrestore(q->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* aac_command_normal - handle commands
|
||||
* @q: queue to process
|
||||
*
|
||||
* This DPC routine will be queued when the adapter interrupts us to
|
||||
* let us know there is a command on our normal priority queue. We will
|
||||
* pull off all QE there are and wake up all the waiters before exiting.
|
||||
* We will take a spinlock out on the queue before operating on it.
|
||||
*/
|
||||
|
||||
unsigned int aac_command_normal(struct aac_queue *q)
|
||||
{
|
||||
struct aac_dev * dev = q->dev;
|
||||
struct aac_entry *entry;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(q->lock, flags);
|
||||
|
||||
/*
|
||||
* Keep pulling response QEs off the response queue and waking
|
||||
* up the waiters until there are no more QEs. We then return
|
||||
* back to the system.
|
||||
*/
|
||||
while(aac_consumer_get(dev, q, &entry))
|
||||
{
|
||||
struct fib fibctx;
|
||||
struct hw_fib * hw_fib;
|
||||
u32 index;
|
||||
struct fib *fib = &fibctx;
|
||||
|
||||
index = le32_to_cpu(entry->addr) / sizeof(struct hw_fib);
|
||||
hw_fib = &dev->aif_base_va[index];
|
||||
|
||||
/*
|
||||
* Allocate a FIB at all costs. For non queued stuff
|
||||
* we can just use the stack so we are happy. We need
|
||||
* a fib object in order to manage the linked lists
|
||||
*/
|
||||
if (dev->aif_thread)
|
||||
if((fib = kmalloc(sizeof(struct fib), GFP_ATOMIC)) == NULL)
|
||||
fib = &fibctx;
|
||||
|
||||
memset(fib, 0, sizeof(struct fib));
|
||||
INIT_LIST_HEAD(&fib->fiblink);
|
||||
fib->type = FSAFS_NTC_FIB_CONTEXT;
|
||||
fib->size = sizeof(struct fib);
|
||||
fib->hw_fib_va = hw_fib;
|
||||
fib->data = hw_fib->data;
|
||||
fib->dev = dev;
|
||||
|
||||
|
||||
if (dev->aif_thread && fib != &fibctx) {
|
||||
list_add_tail(&fib->fiblink, &q->cmdq);
|
||||
aac_consumer_free(dev, q, HostNormCmdQueue);
|
||||
wake_up_interruptible(&q->cmdready);
|
||||
} else {
|
||||
aac_consumer_free(dev, q, HostNormCmdQueue);
|
||||
spin_unlock_irqrestore(q->lock, flags);
|
||||
/*
|
||||
* Set the status of this FIB
|
||||
*/
|
||||
*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
|
||||
aac_fib_adapter_complete(fib, sizeof(u32));
|
||||
spin_lock_irqsave(q->lock, flags);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(q->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* aac_aif_callback
|
||||
* @context: the context set in the fib - here it is scsi cmd
|
||||
* @fibptr: pointer to the fib
|
||||
*
|
||||
* Handles the AIFs - new method (SRC)
|
||||
*
|
||||
*/
|
||||
|
||||
static void aac_aif_callback(void *context, struct fib * fibptr)
|
||||
{
|
||||
struct fib *fibctx;
|
||||
struct aac_dev *dev;
|
||||
struct aac_aifcmd *cmd;
|
||||
int status;
|
||||
|
||||
fibctx = (struct fib *)context;
|
||||
BUG_ON(fibptr == NULL);
|
||||
dev = fibptr->dev;
|
||||
|
||||
if (fibptr->hw_fib_va->header.XferState &
|
||||
cpu_to_le32(NoMoreAifDataAvailable)) {
|
||||
aac_fib_complete(fibptr);
|
||||
aac_fib_free(fibptr);
|
||||
return;
|
||||
}
|
||||
|
||||
aac_intr_normal(dev, 0, 1, 0, fibptr->hw_fib_va);
|
||||
|
||||
aac_fib_init(fibctx);
|
||||
cmd = (struct aac_aifcmd *) fib_data(fibctx);
|
||||
cmd->command = cpu_to_le32(AifReqEvent);
|
||||
|
||||
status = aac_fib_send(AifRequest,
|
||||
fibctx,
|
||||
sizeof(struct hw_fib)-sizeof(struct aac_fibhdr),
|
||||
FsaNormal,
|
||||
0, 1,
|
||||
(fib_callback)aac_aif_callback, fibctx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* aac_intr_normal - Handle command replies
|
||||
* @dev: Device
|
||||
* @index: completion reference
|
||||
*
|
||||
* This DPC routine will be run when the adapter interrupts us to let us
|
||||
* 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 long mflags;
|
||||
dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
|
||||
if (isAif == 1) { /* AIF - common */
|
||||
struct hw_fib * hw_fib;
|
||||
struct fib * fib;
|
||||
struct aac_queue *q = &dev->queues->queue[HostNormCmdQueue];
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Allocate a FIB. For non queued stuff we can just use
|
||||
* the stack so we are happy. We need a fib object in order to
|
||||
* manage the linked lists.
|
||||
*/
|
||||
if ((!dev->aif_thread)
|
||||
|| (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC))))
|
||||
return 1;
|
||||
if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
|
||||
kfree (fib);
|
||||
return 1;
|
||||
}
|
||||
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));
|
||||
}
|
||||
INIT_LIST_HEAD(&fib->fiblink);
|
||||
fib->type = FSAFS_NTC_FIB_CONTEXT;
|
||||
fib->size = sizeof(struct fib);
|
||||
fib->hw_fib_va = hw_fib;
|
||||
fib->data = hw_fib->data;
|
||||
fib->dev = dev;
|
||||
|
||||
spin_lock_irqsave(q->lock, flags);
|
||||
list_add_tail(&fib->fiblink, &q->cmdq);
|
||||
wake_up_interruptible(&q->cmdready);
|
||||
spin_unlock_irqrestore(q->lock, flags);
|
||||
return 1;
|
||||
} else if (isAif == 2) { /* AIF - new (SRC) */
|
||||
struct fib *fibctx;
|
||||
struct aac_aifcmd *cmd;
|
||||
|
||||
fibctx = aac_fib_alloc(dev);
|
||||
if (!fibctx)
|
||||
return 1;
|
||||
aac_fib_init(fibctx);
|
||||
|
||||
cmd = (struct aac_aifcmd *) fib_data(fibctx);
|
||||
cmd->command = cpu_to_le32(AifReqEvent);
|
||||
|
||||
return aac_fib_send(AifRequest,
|
||||
fibctx,
|
||||
sizeof(struct hw_fib)-sizeof(struct aac_fibhdr),
|
||||
FsaNormal,
|
||||
0, 1,
|
||||
(fib_callback)aac_aif_callback, fibctx);
|
||||
} else {
|
||||
struct fib *fib = &dev->fibs[index];
|
||||
struct hw_fib * hwfib = fib->hw_fib_va;
|
||||
|
||||
/*
|
||||
* Remove this fib from the Outstanding I/O queue.
|
||||
* But only if it has not already been timed out.
|
||||
*
|
||||
* If the fib has been timed out already, then just
|
||||
* continue. The caller has already been notified that
|
||||
* the fib timed out.
|
||||
*/
|
||||
dev->queues->queue[AdapNormCmdQueue].numpending--;
|
||||
|
||||
if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
|
||||
aac_fib_complete(fib);
|
||||
aac_fib_free(fib);
|
||||
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.
|
||||
*/
|
||||
fib->flags &= FIB_CONTEXT_FLAG_FASTRESP;
|
||||
fib->callback(fib->callback_data, 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);
|
||||
}
|
||||
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 (fib->done == 2) {
|
||||
spin_lock_irqsave(&fib->event_lock, flagv);
|
||||
fib->done = 0;
|
||||
spin_unlock_irqrestore(&fib->event_lock, flagv);
|
||||
aac_fib_complete(fib);
|
||||
aac_fib_free(fib);
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
1373
drivers/scsi/aacraid/linit.c
Normal file
1373
drivers/scsi/aacraid/linit.c
Normal file
File diff suppressed because it is too large
Load diff
84
drivers/scsi/aacraid/nark.c
Normal file
84
drivers/scsi/aacraid/nark.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Adaptec AAC series RAID controller driver
|
||||
*
|
||||
* based on the old aacraid driver that is..
|
||||
* Adaptec aacraid device driver for Linux.
|
||||
*
|
||||
* Copyright (c) 2000-2010 Adaptec, Inc.
|
||||
* 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.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
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Module Name:
|
||||
* nark.c
|
||||
*
|
||||
* Abstract: Hardware Device Interface for NEMER/ARK
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/blkdev.h>
|
||||
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include "aacraid.h"
|
||||
|
||||
/**
|
||||
* aac_nark_ioremap
|
||||
* @size: mapping resize request
|
||||
*
|
||||
*/
|
||||
static int aac_nark_ioremap(struct aac_dev * dev, u32 size)
|
||||
{
|
||||
if (!size) {
|
||||
iounmap(dev->regs.rx);
|
||||
dev->regs.rx = NULL;
|
||||
iounmap(dev->base);
|
||||
dev->base = NULL;
|
||||
return 0;
|
||||
}
|
||||
dev->base_start = pci_resource_start(dev->pdev, 2);
|
||||
dev->regs.rx = ioremap((u64)pci_resource_start(dev->pdev, 0) |
|
||||
((u64)pci_resource_start(dev->pdev, 1) << 32),
|
||||
sizeof(struct rx_registers) - sizeof(struct rx_inbound));
|
||||
dev->base = NULL;
|
||||
if (dev->regs.rx == NULL)
|
||||
return -1;
|
||||
dev->base = ioremap(dev->base_start, size);
|
||||
if (dev->base == NULL) {
|
||||
iounmap(dev->regs.rx);
|
||||
dev->regs.rx = NULL;
|
||||
return -1;
|
||||
}
|
||||
dev->IndexRegs = &((struct rx_registers __iomem *)dev->base)->IndexRegs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_nark_init - initialize an NEMER/ARK Split Bar card
|
||||
* @dev: device to configure
|
||||
*
|
||||
*/
|
||||
|
||||
int aac_nark_init(struct aac_dev * dev)
|
||||
{
|
||||
/*
|
||||
* Fill in the function dispatch table.
|
||||
*/
|
||||
dev->a_ops.adapter_ioremap = aac_nark_ioremap;
|
||||
dev->a_ops.adapter_comm = aac_rx_select_comm;
|
||||
|
||||
return _aac_rx_init(dev);
|
||||
}
|
107
drivers/scsi/aacraid/rkt.c
Normal file
107
drivers/scsi/aacraid/rkt.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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 PMC-Sierra, Inc. (aacraid@pmc-sierra.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
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Module Name:
|
||||
* rkt.c
|
||||
*
|
||||
* Abstract: Hardware miniport for Drawbridge specific hardware functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include "aacraid.h"
|
||||
|
||||
#define AAC_NUM_IO_FIB_RKT (246 - AAC_NUM_MGT_FIB)
|
||||
|
||||
/**
|
||||
* aac_rkt_select_comm - Select communications method
|
||||
* @dev: Adapter
|
||||
* @comm: communications method
|
||||
*/
|
||||
|
||||
static int aac_rkt_select_comm(struct aac_dev *dev, int comm)
|
||||
{
|
||||
int retval;
|
||||
retval = aac_rx_select_comm(dev, comm);
|
||||
if (comm == AAC_COMM_MESSAGE) {
|
||||
/*
|
||||
* FIB Setup has already been done, but we can minimize the
|
||||
* damage by at least ensuring the OS never issues more
|
||||
* commands than we can handle. The Rocket adapters currently
|
||||
* can only handle 246 commands and 8 AIFs at the same time,
|
||||
* and in fact do notify us accordingly if we negotiate the
|
||||
* FIB size. The problem that causes us to add this check is
|
||||
* to ensure that we do not overdo it with the adapter when a
|
||||
* hard coded FIB override is being utilized. This special
|
||||
* case warrants this half baked, but convenient, check here.
|
||||
*/
|
||||
if (dev->scsi_host_ptr->can_queue > AAC_NUM_IO_FIB_RKT) {
|
||||
dev->init->MaxIoCommands =
|
||||
cpu_to_le32(AAC_NUM_IO_FIB_RKT + AAC_NUM_MGT_FIB);
|
||||
dev->scsi_host_ptr->can_queue = AAC_NUM_IO_FIB_RKT;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rkt_ioremap
|
||||
* @size: mapping resize request
|
||||
*
|
||||
*/
|
||||
static int aac_rkt_ioremap(struct aac_dev * dev, u32 size)
|
||||
{
|
||||
if (!size) {
|
||||
iounmap(dev->regs.rkt);
|
||||
return 0;
|
||||
}
|
||||
dev->base = dev->regs.rkt = ioremap(dev->base_start, size);
|
||||
if (dev->base == NULL)
|
||||
return -1;
|
||||
dev->IndexRegs = &dev->regs.rkt->IndexRegs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rkt_init - initialize an i960 based AAC card
|
||||
* @dev: device to configure
|
||||
*
|
||||
* Allocate and set up resources for the i960 based AAC variants. The
|
||||
* device_interface in the commregion will be allocated and linked
|
||||
* to the comm region.
|
||||
*/
|
||||
|
||||
int aac_rkt_init(struct aac_dev *dev)
|
||||
{
|
||||
/*
|
||||
* Fill in the function dispatch table.
|
||||
*/
|
||||
dev->a_ops.adapter_ioremap = aac_rkt_ioremap;
|
||||
dev->a_ops.adapter_comm = aac_rkt_select_comm;
|
||||
|
||||
return _aac_rx_init(dev);
|
||||
}
|
684
drivers/scsi/aacraid/rx.c
Normal file
684
drivers/scsi/aacraid/rx.c
Normal file
|
@ -0,0 +1,684 @@
|
|||
/*
|
||||
* 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 PMC-Sierra, Inc. (aacraid@pmc-sierra.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
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Module Name:
|
||||
* rx.c
|
||||
*
|
||||
* Abstract: Hardware miniport for Drawbridge specific hardware functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.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 irqreturn_t aac_rx_intr_producer(int irq, void *dev_id)
|
||||
{
|
||||
struct aac_dev *dev = dev_id;
|
||||
unsigned long bellbits;
|
||||
u8 intstat = rx_readb(dev, MUnit.OISR);
|
||||
|
||||
/*
|
||||
* Read mask and invert because drawbridge is reversed.
|
||||
* This allows us to only service interrupts that have
|
||||
* been enabled.
|
||||
* Check to see if this is our interrupt. If it isn't just return
|
||||
*/
|
||||
if (likely(intstat & ~(dev->OIMR))) {
|
||||
bellbits = rx_readl(dev, OutboundDoorbellReg);
|
||||
if (unlikely(bellbits & DoorBellPrintfReady)) {
|
||||
aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));
|
||||
rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
|
||||
rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
|
||||
}
|
||||
else if (unlikely(bellbits & DoorBellAdapterNormCmdReady)) {
|
||||
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
|
||||
aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
|
||||
}
|
||||
else if (likely(bellbits & DoorBellAdapterNormRespReady)) {
|
||||
rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
|
||||
aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
|
||||
}
|
||||
else if (unlikely(bellbits & DoorBellAdapterNormCmdNotFull)) {
|
||||
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
|
||||
}
|
||||
else if (unlikely(bellbits & DoorBellAdapterNormRespNotFull)) {
|
||||
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
|
||||
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static irqreturn_t aac_rx_intr_message(int irq, void *dev_id)
|
||||
{
|
||||
int isAif, isFastResponse, isSpecial;
|
||||
struct aac_dev *dev = dev_id;
|
||||
u32 Index = rx_readl(dev, MUnit.OutboundQueue);
|
||||
if (unlikely(Index == 0xFFFFFFFFL))
|
||||
Index = rx_readl(dev, MUnit.OutboundQueue);
|
||||
if (likely(Index != 0xFFFFFFFFL)) {
|
||||
do {
|
||||
isAif = isFastResponse = isSpecial = 0;
|
||||
if (Index & 0x00000002L) {
|
||||
isAif = 1;
|
||||
if (Index == 0xFFFFFFFEL)
|
||||
isSpecial = 1;
|
||||
Index &= ~0x00000002L;
|
||||
} else {
|
||||
if (Index & 0x00000001L)
|
||||
isFastResponse = 1;
|
||||
Index >>= 2;
|
||||
}
|
||||
if (!isSpecial) {
|
||||
if (unlikely(aac_intr_normal(dev,
|
||||
Index, isAif,
|
||||
isFastResponse, NULL))) {
|
||||
rx_writel(dev,
|
||||
MUnit.OutboundQueue,
|
||||
Index);
|
||||
rx_writel(dev,
|
||||
MUnit.ODR,
|
||||
DoorBellAdapterNormRespReady);
|
||||
}
|
||||
}
|
||||
Index = rx_readl(dev, MUnit.OutboundQueue);
|
||||
} while (Index != 0xFFFFFFFFL);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_disable_interrupt - Disable interrupts
|
||||
* @dev: Adapter
|
||||
*/
|
||||
|
||||
static void aac_rx_disable_interrupt(struct aac_dev *dev)
|
||||
{
|
||||
rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_enable_interrupt_producer - Enable interrupts
|
||||
* @dev: Adapter
|
||||
*/
|
||||
|
||||
static void aac_rx_enable_interrupt_producer(struct aac_dev *dev)
|
||||
{
|
||||
rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_enable_interrupt_message - Enable interrupts
|
||||
* @dev: Adapter
|
||||
*/
|
||||
|
||||
static void aac_rx_enable_interrupt_message(struct aac_dev *dev)
|
||||
{
|
||||
rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
|
||||
}
|
||||
|
||||
/**
|
||||
* rx_sync_cmd - send a command and wait
|
||||
* @dev: Adapter
|
||||
* @command: Command to execute
|
||||
* @p1: first parameter
|
||||
* @ret: adapter status
|
||||
*
|
||||
* This routine will send a synchronous command to the adapter and wait
|
||||
* for its completion.
|
||||
*/
|
||||
|
||||
static int rx_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;
|
||||
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.
|
||||
*/
|
||||
rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
|
||||
/*
|
||||
* Disable doorbell interrupts
|
||||
*/
|
||||
rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
|
||||
/*
|
||||
* Force the completion of the mask register write before issuing
|
||||
* the interrupt.
|
||||
*/
|
||||
rx_readb (dev, MUnit.OIMR);
|
||||
/*
|
||||
* Signal that there is a new synch command
|
||||
*/
|
||||
rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
|
||||
|
||||
ok = 0;
|
||||
start = jiffies;
|
||||
|
||||
/*
|
||||
* Wait up to 30 seconds
|
||||
*/
|
||||
while (time_before(jiffies, start+30*HZ))
|
||||
{
|
||||
udelay(5); /* Delay 5 microseconds to let Mon960 get info. */
|
||||
/*
|
||||
* Mon960 will set doorbell0 bit when it has completed the command.
|
||||
*/
|
||||
if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
|
||||
/*
|
||||
* Clear the doorbell.
|
||||
*/
|
||||
rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
|
||||
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]);
|
||||
/*
|
||||
* Clear the synch command doorbell.
|
||||
*/
|
||||
rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
|
||||
/*
|
||||
* Restore interrupt mask
|
||||
*/
|
||||
aac_adapter_enable_int(dev);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_interrupt_adapter - interrupt adapter
|
||||
* @dev: Adapter
|
||||
*
|
||||
* Send an interrupt to the i960 and breakpoint it.
|
||||
*/
|
||||
|
||||
static void aac_rx_interrupt_adapter(struct aac_dev *dev)
|
||||
{
|
||||
rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_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_rx_notify_adapter(struct aac_dev *dev, u32 event)
|
||||
{
|
||||
switch (event) {
|
||||
|
||||
case AdapNormCmdQue:
|
||||
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);
|
||||
break;
|
||||
case HostNormRespNotFull:
|
||||
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);
|
||||
break;
|
||||
case AdapNormRespQue:
|
||||
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);
|
||||
break;
|
||||
case HostNormCmdNotFull:
|
||||
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
|
||||
break;
|
||||
case HostShutdown:
|
||||
break;
|
||||
case FastIo:
|
||||
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
|
||||
break;
|
||||
case AdapPrintfDone:
|
||||
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_start_adapter - activate adapter
|
||||
* @dev: Adapter
|
||||
*
|
||||
* Start up processing on an i960 based AAC adapter
|
||||
*/
|
||||
|
||||
static void aac_rx_start_adapter(struct aac_dev *dev)
|
||||
{
|
||||
struct aac_init *init;
|
||||
|
||||
init = dev->init;
|
||||
init->HostElapsedSeconds = cpu_to_le32(get_seconds());
|
||||
// We can only use a 32 bit address here
|
||||
rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa,
|
||||
0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_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_rx_check_health(struct aac_dev *dev)
|
||||
{
|
||||
u32 status = rx_readl(dev, MUnit.OMRx[0]);
|
||||
|
||||
/*
|
||||
* Check to see if the board failed any self tests.
|
||||
*/
|
||||
if (unlikely(status & SELF_TEST_FAILED))
|
||||
return -1;
|
||||
/*
|
||||
* Check to see if the board panic'd.
|
||||
*/
|
||||
if (unlikely(status & KERNEL_PANIC)) {
|
||||
char * buffer;
|
||||
struct POSTSTATUS {
|
||||
__le32 Post_Command;
|
||||
__le32 Post_Address;
|
||||
} * post;
|
||||
dma_addr_t paddr, baddr;
|
||||
int ret;
|
||||
|
||||
if (likely((status & 0xFF000000L) == 0xBC000000L))
|
||||
return (status >> 16) & 0xFF;
|
||||
buffer = pci_alloc_consistent(dev->pdev, 512, &baddr);
|
||||
ret = -2;
|
||||
if (unlikely(buffer == NULL))
|
||||
return ret;
|
||||
post = pci_alloc_consistent(dev->pdev,
|
||||
sizeof(struct POSTSTATUS), &paddr);
|
||||
if (unlikely(post == NULL)) {
|
||||
pci_free_consistent(dev->pdev, 512, buffer, baddr);
|
||||
return ret;
|
||||
}
|
||||
memset(buffer, 0, 512);
|
||||
post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);
|
||||
post->Post_Address = cpu_to_le32(baddr);
|
||||
rx_writel(dev, MUnit.IMRx[0], paddr);
|
||||
rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
|
||||
post, paddr);
|
||||
if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) {
|
||||
ret = (hex_to_bin(buffer[2]) << 4) +
|
||||
hex_to_bin(buffer[3]);
|
||||
}
|
||||
pci_free_consistent(dev->pdev, 512, buffer, baddr);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Wait for the adapter to be up and running.
|
||||
*/
|
||||
if (unlikely(!(status & KERNEL_UP_AND_RUNNING)))
|
||||
return -3;
|
||||
/*
|
||||
* Everything is OK
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_deliver_producer
|
||||
* @fib: fib to issue
|
||||
*
|
||||
* Will send a fib, returning 0 if successful.
|
||||
*/
|
||||
int aac_rx_deliver_producer(struct fib * fib)
|
||||
{
|
||||
struct aac_dev *dev = fib->dev;
|
||||
struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];
|
||||
unsigned long qflags;
|
||||
u32 Index;
|
||||
unsigned long nointr = 0;
|
||||
|
||||
spin_lock_irqsave(q->lock, qflags);
|
||||
aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib_va, 1, fib, &nointr);
|
||||
|
||||
q->numpending++;
|
||||
*(q->headers.producer) = cpu_to_le32(Index + 1);
|
||||
spin_unlock_irqrestore(q->lock, qflags);
|
||||
if (!(nointr & aac_config.irq_mod))
|
||||
aac_adapter_notify(dev, AdapNormCmdQueue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_deliver_message
|
||||
* @fib: fib to issue
|
||||
*
|
||||
* Will send a fib, returning 0 if successful.
|
||||
*/
|
||||
static int aac_rx_deliver_message(struct fib * fib)
|
||||
{
|
||||
struct aac_dev *dev = fib->dev;
|
||||
struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];
|
||||
unsigned long qflags;
|
||||
u32 Index;
|
||||
u64 addr;
|
||||
volatile void __iomem *device;
|
||||
|
||||
unsigned long count = 10000000L; /* 50 seconds */
|
||||
spin_lock_irqsave(q->lock, qflags);
|
||||
q->numpending++;
|
||||
spin_unlock_irqrestore(q->lock, qflags);
|
||||
for(;;) {
|
||||
Index = rx_readl(dev, MUnit.InboundQueue);
|
||||
if (unlikely(Index == 0xFFFFFFFFL))
|
||||
Index = rx_readl(dev, MUnit.InboundQueue);
|
||||
if (likely(Index != 0xFFFFFFFFL))
|
||||
break;
|
||||
if (--count == 0) {
|
||||
spin_lock_irqsave(q->lock, qflags);
|
||||
q->numpending--;
|
||||
spin_unlock_irqrestore(q->lock, qflags);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
device = dev->base + Index;
|
||||
addr = fib->hw_fib_pa;
|
||||
writel((u32)(addr & 0xffffffff), device);
|
||||
device += sizeof(u32);
|
||||
writel((u32)(addr >> 32), device);
|
||||
device += sizeof(u32);
|
||||
writel(le16_to_cpu(fib->hw_fib_va->header.Size), device);
|
||||
rx_writel(dev, MUnit.InboundQueue, Index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_ioremap
|
||||
* @size: mapping resize request
|
||||
*
|
||||
*/
|
||||
static int aac_rx_ioremap(struct aac_dev * dev, u32 size)
|
||||
{
|
||||
if (!size) {
|
||||
iounmap(dev->regs.rx);
|
||||
return 0;
|
||||
}
|
||||
dev->base = dev->regs.rx = ioremap(dev->base_start, size);
|
||||
if (dev->base == NULL)
|
||||
return -1;
|
||||
dev->IndexRegs = &dev->regs.rx->IndexRegs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
|
||||
{
|
||||
u32 var = 0;
|
||||
|
||||
if (!(dev->supplement_adapter_info.SupportedOptions2 &
|
||||
AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) {
|
||||
if (bled)
|
||||
printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
|
||||
dev->name, dev->id, bled);
|
||||
else {
|
||||
bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
|
||||
0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
|
||||
if (!bled && (var != 0x00000001) && (var != 0x3803000F))
|
||||
bled = -EINVAL;
|
||||
}
|
||||
if (bled && (bled != -ETIMEDOUT))
|
||||
bled = aac_adapter_sync_cmd(dev, IOP_RESET,
|
||||
0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (bled && (bled != -ETIMEDOUT))
|
||||
return -EINVAL;
|
||||
}
|
||||
if (bled && (var == 0x3803000F)) { /* USE_OTHER_METHOD */
|
||||
rx_writel(dev, MUnit.reserved2, 3);
|
||||
msleep(5000); /* Delay 5 seconds */
|
||||
var = 0x00000001;
|
||||
}
|
||||
if (bled && (var != 0x00000001))
|
||||
return -EINVAL;
|
||||
ssleep(5);
|
||||
if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
|
||||
return -ENODEV;
|
||||
if (startup_timeout < 300)
|
||||
startup_timeout = 300;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_select_comm - Select communications method
|
||||
* @dev: Adapter
|
||||
* @comm: communications method
|
||||
*/
|
||||
|
||||
int aac_rx_select_comm(struct aac_dev *dev, int comm)
|
||||
{
|
||||
switch (comm) {
|
||||
case AAC_COMM_PRODUCER:
|
||||
dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_producer;
|
||||
dev->a_ops.adapter_intr = aac_rx_intr_producer;
|
||||
dev->a_ops.adapter_deliver = aac_rx_deliver_producer;
|
||||
break;
|
||||
case AAC_COMM_MESSAGE:
|
||||
dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_message;
|
||||
dev->a_ops.adapter_intr = aac_rx_intr_message;
|
||||
dev->a_ops.adapter_deliver = aac_rx_deliver_message;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_rx_init - initialize an i960 based AAC card
|
||||
* @dev: device to configure
|
||||
*
|
||||
* Allocate and set up resources for the i960 based AAC variants. The
|
||||
* device_interface in the commregion will be allocated and linked
|
||||
* to the comm region.
|
||||
*/
|
||||
|
||||
int _aac_rx_init(struct aac_dev *dev)
|
||||
{
|
||||
unsigned long start;
|
||||
unsigned long status;
|
||||
int restart = 0;
|
||||
int instance = dev->id;
|
||||
const char * name = dev->name;
|
||||
|
||||
if (aac_adapter_ioremap(dev, dev->base_size)) {
|
||||
printk(KERN_WARNING "%s: unable to map adapter.\n", name);
|
||||
goto error_iounmap;
|
||||
}
|
||||
|
||||
/* Failure to reset here is an option ... */
|
||||
dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
|
||||
dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt;
|
||||
dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
|
||||
if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) &&
|
||||
!aac_rx_restart_adapter(dev, 0))
|
||||
/* Make sure the Hardware FIFO is empty */
|
||||
while ((++restart < 512) &&
|
||||
(rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL));
|
||||
/*
|
||||
* Check to see if the board panic'd while booting.
|
||||
*/
|
||||
status = rx_readl(dev, MUnit.OMRx[0]);
|
||||
if (status & KERNEL_PANIC) {
|
||||
if (aac_rx_restart_adapter(dev, aac_rx_check_health(dev)))
|
||||
goto error_iounmap;
|
||||
++restart;
|
||||
}
|
||||
/*
|
||||
* Check to see if the board failed any self tests.
|
||||
*/
|
||||
status = rx_readl(dev, MUnit.OMRx[0]);
|
||||
if (status & SELF_TEST_FAILED) {
|
||||
printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
/*
|
||||
* Check to see if the monitor panic'd while booting.
|
||||
*/
|
||||
if (status & MONITOR_PANIC) {
|
||||
printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
start = jiffies;
|
||||
/*
|
||||
* Wait for the adapter to be up and running. Wait up to 3 minutes
|
||||
*/
|
||||
while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))
|
||||
{
|
||||
if ((restart &&
|
||||
(status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
|
||||
time_after(jiffies, start+HZ*startup_timeout)) {
|
||||
printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
|
||||
dev->name, instance, status);
|
||||
goto error_iounmap;
|
||||
}
|
||||
if (!restart &&
|
||||
((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
|
||||
time_after(jiffies, start + HZ *
|
||||
((startup_timeout > 60)
|
||||
? (startup_timeout - 60)
|
||||
: (startup_timeout / 2))))) {
|
||||
if (likely(!aac_rx_restart_adapter(dev, aac_rx_check_health(dev))))
|
||||
start = jiffies;
|
||||
++restart;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
if (restart && aac_commit)
|
||||
aac_commit = 1;
|
||||
/*
|
||||
* Fill in the common function dispatch table.
|
||||
*/
|
||||
dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;
|
||||
dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;
|
||||
dev->a_ops.adapter_notify = aac_rx_notify_adapter;
|
||||
dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
|
||||
dev->a_ops.adapter_check_health = aac_rx_check_health;
|
||||
dev->a_ops.adapter_restart = aac_rx_restart_adapter;
|
||||
|
||||
/*
|
||||
* First clear out all interrupts. Then enable the one's that we
|
||||
* can handle.
|
||||
*/
|
||||
aac_adapter_comm(dev, AAC_COMM_PRODUCER);
|
||||
aac_adapter_disable_int(dev);
|
||||
rx_writel(dev, MUnit.ODR, 0xffffffff);
|
||||
aac_adapter_enable_int(dev);
|
||||
|
||||
if (aac_init_adapter(dev) == NULL)
|
||||
goto error_iounmap;
|
||||
aac_adapter_comm(dev, dev->comm_interface);
|
||||
dev->sync_mode = 0; /* sync. mode not supported */
|
||||
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
|
||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
||||
IRQF_SHARED, "aacraid", dev) < 0) {
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
|
||||
name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
dev->dbg_base = dev->base_start;
|
||||
dev->dbg_base_mapped = dev->base;
|
||||
dev->dbg_size = dev->base_size;
|
||||
|
||||
aac_adapter_enable_int(dev);
|
||||
/*
|
||||
* Tell the adapter that all is configured, and it can
|
||||
* start accepting requests
|
||||
*/
|
||||
aac_rx_start_adapter(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
error_iounmap:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int aac_rx_init(struct aac_dev *dev)
|
||||
{
|
||||
/*
|
||||
* Fill in the function dispatch table.
|
||||
*/
|
||||
dev->a_ops.adapter_ioremap = aac_rx_ioremap;
|
||||
dev->a_ops.adapter_comm = aac_rx_select_comm;
|
||||
|
||||
return _aac_rx_init(dev);
|
||||
}
|
416
drivers/scsi/aacraid/sa.c
Normal file
416
drivers/scsi/aacraid/sa.c
Normal file
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* 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 PMC-Sierra, Inc. (aacraid@pmc-sierra.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
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Module Name:
|
||||
* sa.c
|
||||
*
|
||||
* Abstract: Drawbridge specific support functions
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.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 irqreturn_t aac_sa_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct aac_dev *dev = dev_id;
|
||||
unsigned short intstat, mask;
|
||||
|
||||
intstat = sa_readw(dev, DoorbellReg_p);
|
||||
/*
|
||||
* Read mask and invert because drawbridge is reversed.
|
||||
* This allows us to only service interrupts that have been enabled.
|
||||
*/
|
||||
mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK));
|
||||
|
||||
/* Check to see if this is our interrupt. If it isn't just return */
|
||||
|
||||
if (intstat & mask) {
|
||||
if (intstat & PrintfReady) {
|
||||
aac_printf(dev, sa_readl(dev, Mailbox5));
|
||||
sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */
|
||||
sa_writew(dev, DoorbellReg_s, PrintfDone);
|
||||
} else if (intstat & DOORBELL_1) { // dev -> Host Normal Command Ready
|
||||
sa_writew(dev, DoorbellClrReg_p, DOORBELL_1);
|
||||
aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
|
||||
} else if (intstat & DOORBELL_2) { // dev -> Host Normal Response Ready
|
||||
sa_writew(dev, DoorbellClrReg_p, DOORBELL_2);
|
||||
aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
|
||||
} else if (intstat & DOORBELL_3) { // dev -> Host Normal Command Not Full
|
||||
sa_writew(dev, DoorbellClrReg_p, DOORBELL_3);
|
||||
} else if (intstat & DOORBELL_4) { // dev -> Host Normal Response Not Full
|
||||
sa_writew(dev, DoorbellClrReg_p, DOORBELL_4);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_sa_disable_interrupt - disable interrupt
|
||||
* @dev: Which adapter to enable.
|
||||
*/
|
||||
|
||||
static void aac_sa_disable_interrupt (struct aac_dev *dev)
|
||||
{
|
||||
sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_sa_enable_interrupt - enable interrupt
|
||||
* @dev: Which adapter to enable.
|
||||
*/
|
||||
|
||||
static void aac_sa_enable_interrupt (struct aac_dev *dev)
|
||||
{
|
||||
sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 |
|
||||
DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_sa_notify_adapter - handle adapter notification
|
||||
* @dev: Adapter that notification is for
|
||||
* @event: Event to notidy
|
||||
*
|
||||
* Notify the adapter of an event
|
||||
*/
|
||||
|
||||
static void aac_sa_notify_adapter(struct aac_dev *dev, u32 event)
|
||||
{
|
||||
switch (event) {
|
||||
|
||||
case AdapNormCmdQue:
|
||||
sa_writew(dev, DoorbellReg_s,DOORBELL_1);
|
||||
break;
|
||||
case HostNormRespNotFull:
|
||||
sa_writew(dev, DoorbellReg_s,DOORBELL_4);
|
||||
break;
|
||||
case AdapNormRespQue:
|
||||
sa_writew(dev, DoorbellReg_s,DOORBELL_2);
|
||||
break;
|
||||
case HostNormCmdNotFull:
|
||||
sa_writew(dev, DoorbellReg_s,DOORBELL_3);
|
||||
break;
|
||||
case HostShutdown:
|
||||
/*
|
||||
sa_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
*/
|
||||
break;
|
||||
case FastIo:
|
||||
sa_writew(dev, DoorbellReg_s,DOORBELL_6);
|
||||
break;
|
||||
case AdapPrintfDone:
|
||||
sa_writew(dev, DoorbellReg_s,DOORBELL_5);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sa_sync_cmd - send a command and wait
|
||||
* @dev: Adapter
|
||||
* @command: Command to execute
|
||||
* @p1: first parameter
|
||||
* @ret: adapter status
|
||||
*
|
||||
* This routine will send a synchronous command to the adapter and wait
|
||||
* for its completion.
|
||||
*/
|
||||
|
||||
static int sa_sync_cmd(struct aac_dev *dev, u32 command,
|
||||
u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
|
||||
u32 *ret, u32 *r1, u32 *r2, u32 *r3, u32 *r4)
|
||||
{
|
||||
unsigned long start;
|
||||
int ok;
|
||||
/*
|
||||
* Write the Command into Mailbox 0
|
||||
*/
|
||||
sa_writel(dev, Mailbox0, command);
|
||||
/*
|
||||
* Write the parameters into Mailboxes 1 - 4
|
||||
*/
|
||||
sa_writel(dev, Mailbox1, p1);
|
||||
sa_writel(dev, Mailbox2, p2);
|
||||
sa_writel(dev, Mailbox3, p3);
|
||||
sa_writel(dev, Mailbox4, p4);
|
||||
|
||||
/*
|
||||
* Clear the synch command doorbell to start on a clean slate.
|
||||
*/
|
||||
sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
|
||||
/*
|
||||
* Signal that there is a new synch command
|
||||
*/
|
||||
sa_writew(dev, DoorbellReg_s, DOORBELL_0);
|
||||
|
||||
ok = 0;
|
||||
start = jiffies;
|
||||
|
||||
while(time_before(jiffies, start+30*HZ))
|
||||
{
|
||||
/*
|
||||
* Delay 5uS so that the monitor gets access
|
||||
*/
|
||||
udelay(5);
|
||||
/*
|
||||
* Mon110 will set doorbell0 bit when it has
|
||||
* completed the command.
|
||||
*/
|
||||
if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0) {
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
if (ok != 1)
|
||||
return -ETIMEDOUT;
|
||||
/*
|
||||
* Clear the synch command doorbell.
|
||||
*/
|
||||
sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
|
||||
/*
|
||||
* Pull the synch status from Mailbox 0.
|
||||
*/
|
||||
if (ret)
|
||||
*ret = sa_readl(dev, Mailbox0);
|
||||
if (r1)
|
||||
*r1 = sa_readl(dev, Mailbox1);
|
||||
if (r2)
|
||||
*r2 = sa_readl(dev, Mailbox2);
|
||||
if (r3)
|
||||
*r3 = sa_readl(dev, Mailbox3);
|
||||
if (r4)
|
||||
*r4 = sa_readl(dev, Mailbox4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_sa_interrupt_adapter - interrupt an adapter
|
||||
* @dev: Which adapter to enable.
|
||||
*
|
||||
* Breakpoint an adapter.
|
||||
*/
|
||||
|
||||
static void aac_sa_interrupt_adapter (struct aac_dev *dev)
|
||||
{
|
||||
sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_sa_start_adapter - activate adapter
|
||||
* @dev: Adapter
|
||||
*
|
||||
* Start up processing on an ARM based AAC adapter
|
||||
*/
|
||||
|
||||
static void aac_sa_start_adapter(struct aac_dev *dev)
|
||||
{
|
||||
struct aac_init *init;
|
||||
/*
|
||||
* Fill in the remaining pieces of the init.
|
||||
*/
|
||||
init = dev->init;
|
||||
init->HostElapsedSeconds = cpu_to_le32(get_seconds());
|
||||
/* We can only use a 32 bit address here */
|
||||
sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS,
|
||||
(u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int aac_sa_restart_adapter(struct aac_dev *dev, int bled)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_sa_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_sa_check_health(struct aac_dev *dev)
|
||||
{
|
||||
long status = sa_readl(dev, Mailbox7);
|
||||
|
||||
/*
|
||||
* Check to see if the board failed any self tests.
|
||||
*/
|
||||
if (status & SELF_TEST_FAILED)
|
||||
return -1;
|
||||
/*
|
||||
* Check to see if the board panic'd while booting.
|
||||
*/
|
||||
if (status & KERNEL_PANIC)
|
||||
return -2;
|
||||
/*
|
||||
* Wait for the adapter to be up and running. Wait up to 3 minutes
|
||||
*/
|
||||
if (!(status & KERNEL_UP_AND_RUNNING))
|
||||
return -3;
|
||||
/*
|
||||
* Everything is OK
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_sa_ioremap
|
||||
* @size: mapping resize request
|
||||
*
|
||||
*/
|
||||
static int aac_sa_ioremap(struct aac_dev * dev, u32 size)
|
||||
{
|
||||
if (!size) {
|
||||
iounmap(dev->regs.sa);
|
||||
return 0;
|
||||
}
|
||||
dev->base = dev->regs.sa = ioremap(dev->base_start, size);
|
||||
return (dev->base == NULL) ? -1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_sa_init - initialize an ARM based AAC card
|
||||
* @dev: device to configure
|
||||
*
|
||||
* Allocate and set up resources for the ARM based AAC variants. The
|
||||
* device_interface in the commregion will be allocated and linked
|
||||
* to the comm region.
|
||||
*/
|
||||
|
||||
int aac_sa_init(struct aac_dev *dev)
|
||||
{
|
||||
unsigned long start;
|
||||
unsigned long status;
|
||||
int instance;
|
||||
const char *name;
|
||||
|
||||
instance = dev->id;
|
||||
name = dev->name;
|
||||
|
||||
if (aac_sa_ioremap(dev, dev->base_size)) {
|
||||
printk(KERN_WARNING "%s: unable to map adapter.\n", name);
|
||||
goto error_iounmap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the board failed any self tests.
|
||||
*/
|
||||
if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) {
|
||||
printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
/*
|
||||
* Check to see if the board panic'd while booting.
|
||||
*/
|
||||
if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) {
|
||||
printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
start = jiffies;
|
||||
/*
|
||||
* Wait for the adapter to be up and running. Wait up to 3 minutes.
|
||||
*/
|
||||
while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
|
||||
if (time_after(jiffies, start+startup_timeout*HZ)) {
|
||||
status = sa_readl(dev, Mailbox7);
|
||||
printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %lx.\n",
|
||||
name, instance, status);
|
||||
goto error_iounmap;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the function dispatch table.
|
||||
*/
|
||||
|
||||
dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
|
||||
dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
|
||||
dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;
|
||||
dev->a_ops.adapter_notify = aac_sa_notify_adapter;
|
||||
dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
|
||||
dev->a_ops.adapter_check_health = aac_sa_check_health;
|
||||
dev->a_ops.adapter_restart = aac_sa_restart_adapter;
|
||||
dev->a_ops.adapter_intr = aac_sa_intr;
|
||||
dev->a_ops.adapter_deliver = aac_rx_deliver_producer;
|
||||
dev->a_ops.adapter_ioremap = aac_sa_ioremap;
|
||||
|
||||
/*
|
||||
* First clear out all interrupts. Then enable the one's that
|
||||
* we can handle.
|
||||
*/
|
||||
aac_adapter_disable_int(dev);
|
||||
aac_adapter_enable_int(dev);
|
||||
|
||||
if(aac_init_adapter(dev) == NULL)
|
||||
goto error_irq;
|
||||
dev->sync_mode = 0; /* sync. mode not supported */
|
||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
||||
IRQF_SHARED, "aacraid", (void *)dev) < 0) {
|
||||
printk(KERN_WARNING "%s%d: Interrupt unavailable.\n",
|
||||
name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
dev->dbg_base = dev->base_start;
|
||||
dev->dbg_base_mapped = dev->base;
|
||||
dev->dbg_size = dev->base_size;
|
||||
|
||||
aac_adapter_enable_int(dev);
|
||||
|
||||
/*
|
||||
* Tell the adapter that all is configure, and it can start
|
||||
* accepting requests
|
||||
*/
|
||||
aac_sa_start_adapter(dev);
|
||||
return 0;
|
||||
|
||||
error_irq:
|
||||
aac_sa_disable_interrupt(dev);
|
||||
free_irq(dev->pdev->irq, (void *)dev);
|
||||
|
||||
error_iounmap:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
833
drivers/scsi/aacraid/src.c
Normal file
833
drivers/scsi/aacraid/src.c
Normal file
|
@ -0,0 +1,833 @@
|
|||
/*
|
||||
* 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 PMC-Sierra, Inc. (aacraid@pmc-sierra.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
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* 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 irqreturn_t aac_src_intr_message(int irq, void *dev_id)
|
||||
{
|
||||
struct aac_dev *dev = dev_id;
|
||||
unsigned long bellbits, bellbits_shifted;
|
||||
int our_interrupt = 0;
|
||||
int isFastResponse;
|
||||
u32 index, handle;
|
||||
|
||||
bellbits = src_readl(dev, MUnit.ODR_R);
|
||||
if (bellbits & PmDoorBellResponseSent) {
|
||||
bellbits = PmDoorBellResponseSent;
|
||||
/* handle async. status */
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
our_interrupt = 1;
|
||||
index = dev->host_rrq_idx;
|
||||
for (;;) {
|
||||
isFastResponse = 0;
|
||||
/* remove toggle bit (31) */
|
||||
handle = le32_to_cpu(dev->host_rrq[index]) & 0x7fffffff;
|
||||
/* check fast response bit (30) */
|
||||
if (handle & 0x40000000)
|
||||
isFastResponse = 1;
|
||||
handle &= 0x0000ffff;
|
||||
if (handle == 0)
|
||||
break;
|
||||
|
||||
aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
|
||||
|
||||
dev->host_rrq[index++] = 0;
|
||||
if (index == dev->scsi_host_ptr->can_queue +
|
||||
AAC_NUM_MGT_FIB)
|
||||
index = 0;
|
||||
dev->host_rrq_idx = index;
|
||||
}
|
||||
} else {
|
||||
bellbits_shifted = (bellbits >> SRC_ODR_SHIFT);
|
||||
if (bellbits_shifted & DoorBellAifPending) {
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
our_interrupt = 1;
|
||||
/* handle AIF */
|
||||
aac_intr_normal(dev, 0, 2, 0, NULL);
|
||||
} else if (bellbits_shifted & OUTBOUNDDOORBELL_0) {
|
||||
unsigned long sflags;
|
||||
struct list_head *entry;
|
||||
int send_it = 0;
|
||||
extern int aac_sync_mode;
|
||||
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
|
||||
if (!aac_sync_mode) {
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
our_interrupt = 1;
|
||||
}
|
||||
|
||||
if (dev->sync_fib) {
|
||||
our_interrupt = 1;
|
||||
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--;
|
||||
up(&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 (our_interrupt) {
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
src_writel(dev, MUnit.OIMR, dev->OIMR = 0xfffffff8);
|
||||
}
|
||||
|
||||
/**
|
||||
* src_sync_cmd - send a command and wait
|
||||
* @dev: Adapter
|
||||
* @command: Command to execute
|
||||
* @p1: first parameter
|
||||
* @ret: adapter status
|
||||
*
|
||||
* 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;
|
||||
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.
|
||||
*/
|
||||
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) {
|
||||
ok = 0;
|
||||
start = jiffies;
|
||||
|
||||
/*
|
||||
* Wait up to 5 minutes
|
||||
*/
|
||||
while (time_before(jiffies, start+300*HZ)) {
|
||||
udelay(5); /* Delay 5 microseconds to let Mon960 get info. */
|
||||
/*
|
||||
* Mon960 will set doorbell0 bit when it has completed the command.
|
||||
*/
|
||||
if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) {
|
||||
/*
|
||||
* Clear the doorbell.
|
||||
*/
|
||||
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]);
|
||||
|
||||
/*
|
||||
* Clear the synch command doorbell.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
struct aac_init *init;
|
||||
|
||||
/* reset host_rrq_idx first */
|
||||
dev->host_rrq_idx = 0;
|
||||
|
||||
init = dev->init;
|
||||
init->HostElapsedSeconds = cpu_to_le32(get_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 failed any self tests.
|
||||
*/
|
||||
if (unlikely(status & SELF_TEST_FAILED))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Check to see if the board panic'd.
|
||||
*/
|
||||
if (unlikely(status & KERNEL_PANIC))
|
||||
return (status >> 16) & 0xFF;
|
||||
/*
|
||||
* Wait for the adapter to be up and running.
|
||||
*/
|
||||
if (unlikely(!(status & KERNEL_UP_AND_RUNNING)))
|
||||
return -3;
|
||||
/*
|
||||
* Everything is OK
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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];
|
||||
unsigned long qflags;
|
||||
u32 fibsize;
|
||||
dma_addr_t address;
|
||||
struct aac_fib_xporthdr *pFibX;
|
||||
u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size);
|
||||
|
||||
spin_lock_irqsave(q->lock, qflags);
|
||||
q->numpending++;
|
||||
spin_unlock_irqrestore(q->lock, qflags);
|
||||
|
||||
if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
|
||||
/* Calculate the amount to the fibsize bits */
|
||||
fibsize = (hdr_size + 127) / 128 - 1;
|
||||
if (fibsize > (ALIGN32 - 1))
|
||||
return -EMSGSIZE;
|
||||
/* New FIB header, 32-bit */
|
||||
address = fib->hw_fib_pa;
|
||||
fib->hw_fib_va->header.StructType = FIB_MAGIC2;
|
||||
fib->hw_fib_va->header.SenderFibAddress = (u32)address;
|
||||
fib->hw_fib_va->header.u.TimeStamp = 0;
|
||||
BUG_ON(upper_32_bits(address) != 0L);
|
||||
address |= fibsize;
|
||||
} else {
|
||||
/* Calculate the amount to the fibsize bits */
|
||||
fibsize = (sizeof(struct aac_fib_xporthdr) + hdr_size + 127) / 128 - 1;
|
||||
if (fibsize > (ALIGN32 - 1))
|
||||
return -EMSGSIZE;
|
||||
|
||||
/* Fill XPORT header */
|
||||
pFibX = (void *)fib->hw_fib_va - sizeof(struct aac_fib_xporthdr);
|
||||
pFibX->Handle = cpu_to_le32(fib->hw_fib_va->header.Handle);
|
||||
pFibX->HostAddress = cpu_to_le64(fib->hw_fib_pa);
|
||||
pFibX->Size = cpu_to_le32(hdr_size);
|
||||
|
||||
/*
|
||||
* The xport header has been 32-byte aligned for us so that fibsize
|
||||
* can be masked out of this address by hardware. -- BenC
|
||||
*/
|
||||
address = fib->hw_fib_pa - sizeof(struct aac_fib_xporthdr);
|
||||
if (address & (ALIGN32 - 1))
|
||||
return -EINVAL;
|
||||
address |= fibsize;
|
||||
}
|
||||
|
||||
src_writel(dev, MUnit.IQ_H, upper_32_bits(address) & 0xffffffff);
|
||||
src_writel(dev, MUnit.IQ_L, address & 0xffffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_src_ioremap
|
||||
* @size: mapping resize request
|
||||
*
|
||||
*/
|
||||
static int aac_src_ioremap(struct aac_dev *dev, u32 size)
|
||||
{
|
||||
if (!size) {
|
||||
iounmap(dev->regs.src.bar1);
|
||||
dev->regs.src.bar1 = NULL;
|
||||
iounmap(dev->regs.src.bar0);
|
||||
dev->base = dev->regs.src.bar0 = NULL;
|
||||
return 0;
|
||||
}
|
||||
dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2),
|
||||
AAC_MIN_SRC_BAR1_SIZE);
|
||||
dev->base = NULL;
|
||||
if (dev->regs.src.bar1 == NULL)
|
||||
return -1;
|
||||
dev->base = dev->regs.src.bar0 = ioremap(dev->base_start, size);
|
||||
if (dev->base == NULL) {
|
||||
iounmap(dev->regs.src.bar1);
|
||||
dev->regs.src.bar1 = NULL;
|
||||
return -1;
|
||||
}
|
||||
dev->IndexRegs = &((struct src_registers __iomem *)
|
||||
dev->base)->u.tupelo.IndexRegs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_srcv_ioremap
|
||||
* @size: mapping resize request
|
||||
*
|
||||
*/
|
||||
static int aac_srcv_ioremap(struct aac_dev *dev, u32 size)
|
||||
{
|
||||
if (!size) {
|
||||
iounmap(dev->regs.src.bar0);
|
||||
dev->base = dev->regs.src.bar0 = NULL;
|
||||
return 0;
|
||||
}
|
||||
dev->base = dev->regs.src.bar0 = ioremap(dev->base_start, size);
|
||||
if (dev->base == NULL)
|
||||
return -1;
|
||||
dev->IndexRegs = &((struct src_registers __iomem *)
|
||||
dev->base)->u.denali.IndexRegs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aac_src_restart_adapter(struct aac_dev *dev, int bled)
|
||||
{
|
||||
u32 var, reset_mask;
|
||||
|
||||
if (bled >= 0) {
|
||||
if (bled)
|
||||
printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
|
||||
dev->name, dev->id, bled);
|
||||
bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
|
||||
0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL);
|
||||
if (bled || (var != 0x00000001))
|
||||
return -EINVAL;
|
||||
if (dev->supplement_adapter_info.SupportedOptions2 &
|
||||
AAC_OPTION_DOORBELL_RESET) {
|
||||
src_writel(dev, MUnit.IDR, reset_mask);
|
||||
msleep(5000); /* Delay 5 seconds */
|
||||
}
|
||||
}
|
||||
|
||||
if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC)
|
||||
return -ENODEV;
|
||||
|
||||
if (startup_timeout < 300)
|
||||
startup_timeout = 300;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_src_select_comm - Select communications method
|
||||
* @dev: Adapter
|
||||
* @comm: communications method
|
||||
*/
|
||||
int aac_src_select_comm(struct aac_dev *dev, int comm)
|
||||
{
|
||||
switch (comm) {
|
||||
case AAC_COMM_MESSAGE:
|
||||
dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message;
|
||||
dev->a_ops.adapter_intr = aac_src_intr_message;
|
||||
dev->a_ops.adapter_deliver = aac_src_deliver_message;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_src_init - initialize an Cardinal Frey Bar card
|
||||
* @dev: device to configure
|
||||
*
|
||||
*/
|
||||
|
||||
int aac_src_init(struct aac_dev *dev)
|
||||
{
|
||||
unsigned long start;
|
||||
unsigned long status;
|
||||
int restart = 0;
|
||||
int instance = dev->id;
|
||||
const char *name = dev->name;
|
||||
|
||||
dev->a_ops.adapter_ioremap = aac_src_ioremap;
|
||||
dev->a_ops.adapter_comm = aac_src_select_comm;
|
||||
|
||||
dev->base_size = AAC_MIN_SRC_BAR0_SIZE;
|
||||
if (aac_adapter_ioremap(dev, dev->base_size)) {
|
||||
printk(KERN_WARNING "%s: unable to map adapter.\n", name);
|
||||
goto error_iounmap;
|
||||
}
|
||||
|
||||
/* Failure to reset here is an option ... */
|
||||
dev->a_ops.adapter_sync_cmd = src_sync_cmd;
|
||||
dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
|
||||
if ((aac_reset_devices || reset_devices) &&
|
||||
!aac_src_restart_adapter(dev, 0))
|
||||
++restart;
|
||||
/*
|
||||
* Check to see if the board panic'd while booting.
|
||||
*/
|
||||
status = src_readl(dev, MUnit.OMR);
|
||||
if (status & KERNEL_PANIC) {
|
||||
if (aac_src_restart_adapter(dev, aac_src_check_health(dev)))
|
||||
goto error_iounmap;
|
||||
++restart;
|
||||
}
|
||||
/*
|
||||
* Check to see if the board failed any self tests.
|
||||
*/
|
||||
status = src_readl(dev, MUnit.OMR);
|
||||
if (status & SELF_TEST_FAILED) {
|
||||
printk(KERN_ERR "%s%d: adapter self-test failed.\n",
|
||||
dev->name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
/*
|
||||
* Check to see if the monitor panic'd while booting.
|
||||
*/
|
||||
if (status & MONITOR_PANIC) {
|
||||
printk(KERN_ERR "%s%d: adapter monitor panic.\n",
|
||||
dev->name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
start = jiffies;
|
||||
/*
|
||||
* Wait for the adapter to be up and running. Wait up to 3 minutes
|
||||
*/
|
||||
while (!((status = src_readl(dev, MUnit.OMR)) &
|
||||
KERNEL_UP_AND_RUNNING)) {
|
||||
if ((restart &&
|
||||
(status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
|
||||
time_after(jiffies, start+HZ*startup_timeout)) {
|
||||
printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
|
||||
dev->name, instance, status);
|
||||
goto error_iounmap;
|
||||
}
|
||||
if (!restart &&
|
||||
((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
|
||||
time_after(jiffies, start + HZ *
|
||||
((startup_timeout > 60)
|
||||
? (startup_timeout - 60)
|
||||
: (startup_timeout / 2))))) {
|
||||
if (likely(!aac_src_restart_adapter(dev,
|
||||
aac_src_check_health(dev))))
|
||||
start = jiffies;
|
||||
++restart;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
if (restart && aac_commit)
|
||||
aac_commit = 1;
|
||||
/*
|
||||
* Fill in the common function dispatch table.
|
||||
*/
|
||||
dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter;
|
||||
dev->a_ops.adapter_disable_int = aac_src_disable_interrupt;
|
||||
dev->a_ops.adapter_notify = aac_src_notify_adapter;
|
||||
dev->a_ops.adapter_sync_cmd = src_sync_cmd;
|
||||
dev->a_ops.adapter_check_health = aac_src_check_health;
|
||||
dev->a_ops.adapter_restart = aac_src_restart_adapter;
|
||||
|
||||
/*
|
||||
* First clear out all interrupts. Then enable the one's that we
|
||||
* can handle.
|
||||
*/
|
||||
aac_adapter_comm(dev, AAC_COMM_MESSAGE);
|
||||
aac_adapter_disable_int(dev);
|
||||
src_writel(dev, MUnit.ODR_C, 0xffffffff);
|
||||
aac_adapter_enable_int(dev);
|
||||
|
||||
if (aac_init_adapter(dev) == NULL)
|
||||
goto error_iounmap;
|
||||
if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1)
|
||||
goto error_iounmap;
|
||||
|
||||
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
|
||||
|
||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
||||
IRQF_SHARED, "aacraid", dev) < 0) {
|
||||
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
|
||||
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
|
||||
name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
dev->dbg_base = pci_resource_start(dev->pdev, 2);
|
||||
dev->dbg_base_mapped = dev->regs.src.bar1;
|
||||
dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE;
|
||||
|
||||
aac_adapter_enable_int(dev);
|
||||
|
||||
if (!dev->sync_mode) {
|
||||
/*
|
||||
* Tell the adapter that all is configured, and it can
|
||||
* start accepting requests
|
||||
*/
|
||||
aac_src_start_adapter(dev);
|
||||
}
|
||||
return 0;
|
||||
|
||||
error_iounmap:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_srcv_init - initialize an SRCv card
|
||||
* @dev: device to configure
|
||||
*
|
||||
*/
|
||||
|
||||
int aac_srcv_init(struct aac_dev *dev)
|
||||
{
|
||||
unsigned long start;
|
||||
unsigned long status;
|
||||
int restart = 0;
|
||||
int instance = dev->id;
|
||||
const char *name = dev->name;
|
||||
|
||||
dev->a_ops.adapter_ioremap = aac_srcv_ioremap;
|
||||
dev->a_ops.adapter_comm = aac_src_select_comm;
|
||||
|
||||
dev->base_size = AAC_MIN_SRCV_BAR0_SIZE;
|
||||
if (aac_adapter_ioremap(dev, dev->base_size)) {
|
||||
printk(KERN_WARNING "%s: unable to map adapter.\n", name);
|
||||
goto error_iounmap;
|
||||
}
|
||||
|
||||
/* Failure to reset here is an option ... */
|
||||
dev->a_ops.adapter_sync_cmd = src_sync_cmd;
|
||||
dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
|
||||
if ((aac_reset_devices || reset_devices) &&
|
||||
!aac_src_restart_adapter(dev, 0))
|
||||
++restart;
|
||||
/*
|
||||
* Check to see if flash update is running.
|
||||
* Wait for the adapter to be up and running. Wait up to 5 minutes
|
||||
*/
|
||||
status = src_readl(dev, MUnit.OMR);
|
||||
if (status & FLASH_UPD_PENDING) {
|
||||
start = jiffies;
|
||||
do {
|
||||
status = src_readl(dev, MUnit.OMR);
|
||||
if (time_after(jiffies, start+HZ*FWUPD_TIMEOUT)) {
|
||||
printk(KERN_ERR "%s%d: adapter flash update failed.\n",
|
||||
dev->name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
} while (!(status & FLASH_UPD_SUCCESS) &&
|
||||
!(status & FLASH_UPD_FAILED));
|
||||
/* Delay 10 seconds.
|
||||
* Because right now FW is doing a soft reset,
|
||||
* do not read scratch pad register at this time
|
||||
*/
|
||||
ssleep(10);
|
||||
}
|
||||
/*
|
||||
* Check to see if the board panic'd while booting.
|
||||
*/
|
||||
status = src_readl(dev, MUnit.OMR);
|
||||
if (status & KERNEL_PANIC) {
|
||||
if (aac_src_restart_adapter(dev, aac_src_check_health(dev)))
|
||||
goto error_iounmap;
|
||||
++restart;
|
||||
}
|
||||
/*
|
||||
* Check to see if the board failed any self tests.
|
||||
*/
|
||||
status = src_readl(dev, MUnit.OMR);
|
||||
if (status & SELF_TEST_FAILED) {
|
||||
printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
/*
|
||||
* Check to see if the monitor panic'd while booting.
|
||||
*/
|
||||
if (status & MONITOR_PANIC) {
|
||||
printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
start = jiffies;
|
||||
/*
|
||||
* Wait for the adapter to be up and running. Wait up to 3 minutes
|
||||
*/
|
||||
while (!((status = src_readl(dev, MUnit.OMR)) &
|
||||
KERNEL_UP_AND_RUNNING) ||
|
||||
status == 0xffffffff) {
|
||||
if ((restart &&
|
||||
(status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
|
||||
time_after(jiffies, start+HZ*startup_timeout)) {
|
||||
printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
|
||||
dev->name, instance, status);
|
||||
goto error_iounmap;
|
||||
}
|
||||
if (!restart &&
|
||||
((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
|
||||
time_after(jiffies, start + HZ *
|
||||
((startup_timeout > 60)
|
||||
? (startup_timeout - 60)
|
||||
: (startup_timeout / 2))))) {
|
||||
if (likely(!aac_src_restart_adapter(dev, aac_src_check_health(dev))))
|
||||
start = jiffies;
|
||||
++restart;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
if (restart && aac_commit)
|
||||
aac_commit = 1;
|
||||
/*
|
||||
* Fill in the common function dispatch table.
|
||||
*/
|
||||
dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter;
|
||||
dev->a_ops.adapter_disable_int = aac_src_disable_interrupt;
|
||||
dev->a_ops.adapter_notify = aac_src_notify_adapter;
|
||||
dev->a_ops.adapter_sync_cmd = src_sync_cmd;
|
||||
dev->a_ops.adapter_check_health = aac_src_check_health;
|
||||
dev->a_ops.adapter_restart = aac_src_restart_adapter;
|
||||
|
||||
/*
|
||||
* First clear out all interrupts. Then enable the one's that we
|
||||
* can handle.
|
||||
*/
|
||||
aac_adapter_comm(dev, AAC_COMM_MESSAGE);
|
||||
aac_adapter_disable_int(dev);
|
||||
src_writel(dev, MUnit.ODR_C, 0xffffffff);
|
||||
aac_adapter_enable_int(dev);
|
||||
|
||||
if (aac_init_adapter(dev) == NULL)
|
||||
goto error_iounmap;
|
||||
if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE2)
|
||||
goto error_iounmap;
|
||||
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
|
||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
||||
IRQF_SHARED, "aacraid", dev) < 0) {
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
|
||||
name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
dev->dbg_base = dev->base_start;
|
||||
dev->dbg_base_mapped = dev->base;
|
||||
dev->dbg_size = dev->base_size;
|
||||
|
||||
aac_adapter_enable_int(dev);
|
||||
|
||||
if (!dev->sync_mode) {
|
||||
/*
|
||||
* Tell the adapter that all is configured, and it can
|
||||
* start accepting requests
|
||||
*/
|
||||
aac_src_start_adapter(dev);
|
||||
}
|
||||
return 0;
|
||||
|
||||
error_iounmap:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue