Commit 03f29536 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] aacraid driver for 2.5

Forward port from 2.4
parent c1a178bd
...@@ -51,6 +51,9 @@ fi ...@@ -51,6 +51,9 @@ fi
if [ "$CONFIG_EISA" = "y" ]; then if [ "$CONFIG_EISA" = "y" ]; then
dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
fi fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate 'Adaptec AACRAID support (EXPERIMENTAL)' CONFIG_SCSI_AACRAID $CONFIG_SCSI $CONFIG_PCI
fi
source drivers/scsi/aic7xxx/Config.in source drivers/scsi/aic7xxx/Config.in
if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then
dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI
......
...@@ -58,6 +58,7 @@ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o ...@@ -58,6 +58,7 @@ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o
obj-$(CONFIG_SCSI_AHA1542) += aha1542.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o
obj-$(CONFIG_SCSI_AHA1740) += aha1740.o obj-$(CONFIG_SCSI_AHA1740) += aha1740.o
obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/ obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/
obj-$(CONFIG_SCSI_AACRAID) += aacraid/
obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o
obj-$(CONFIG_SCSI_IPS) += ips.o obj-$(CONFIG_SCSI_IPS) += ips.o
obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o
......
EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi
O_TARGET := aacraid.o
obj-m := $(O_TARGET)
obj-y := linit.o aachba.o commctrl.o comminit.o commsup.o \
dpcsup.o rx.o sa.o
include $(TOPDIR)/Rules.make
AACRAID Driver for Linux (take two)
Introduction
-------------------------
The aacraid driver adds support for Adaptec (http://www.adaptec.com)
RAID controllers. This is a major rewrite from the original
Adaptec supplied driver. It has signficantly cleaned up both the code
and the running binary size (the module is less than half the size of
the original).
Supported Cards/Chipsets
-------------------------
Dell Computer Corporation PERC 2 Quad Channel
Dell Computer Corporation PERC 2/Si
Dell Computer Corporation PERC 3/Si
Dell Computer Corporation PERC 3/Di
HP NetRAID-4M
ADAPTEC 2120S
ADAPTEC 2200S
ADAPTEC 5400S
People
-------------------------
Alan Cox <alan@redhat.com>
Christoph Hellwig <hch@infradead.org> (small cleanups/fixes)
Matt Domsch <matt_domsch@dell.com> (revision ioctl, adapter messages)
Deanna Bonds <deanna_bonds@adaptec.com> (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers
added new ioctls, changed scsi interface to use new error handler,
increased the number of fibs and outstanding commands to a container)
Original Driver
-------------------------
Adaptec Unix OEM Product Group
Mailing List
-------------------------
None currently. Also note this is very different to Brian's original driver
so don't expect him to support it.
Adaptec does support this driver. Contact either tech support or deanna bonds.
Original by Brian Boerner February 2001
Rewritten by Alan Cox, November 2001
o Testing
o More testing
o Feature request: display the firmware/bios/etc revisions in the
/proc info
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc. <alan@redhat.com>
*
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
* Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/blk.h>
#include <linux/completion.h>
#include <asm/semaphore.h>
#include "scsi.h"
#include "hosts.h"
#include "aacraid.h"
struct aac_common aac_config;
static struct aac_dev *devices;
static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign)
{
unsigned char *base;
unsigned long size, align;
unsigned long fibsize = 4096;
unsigned long printfbufsiz = 256;
struct aac_init *init;
dma_addr_t phys;
/* FIXME: Adaptec add 128 bytes to this value - WHY ?? */
size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz;
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;
dev->init = (struct aac_init *)(base + fibsize);
dev->init_pa = phys + fibsize;
/*
* Cache the upper bits of the virtual mapping for 64bit boxes
* FIXME: this crap should be rewritten
*/
#if BITS_PER_LONG >= 64
dev->fib_base_va = ((ulong)base & 0xffffffff00000000);
#endif
init = dev->init;
init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
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
*/
init->AdapterFibsVirtualAddress = cpu_to_le32((u32)base);
init->AdapterFibsPhysicalAddress = cpu_to_le32(phys);
init->AdapterFibsSize = cpu_to_le32(fibsize);
init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
/*
* Increment the base address by the amount already used
*/
base = base + fibsize + sizeof(struct aac_init);
phys = phys + fibsize + sizeof(struct aac_init);
/*
* Align the beginning of Headers to commalign
*/
align = (commalign - ((unsigned long)(base) & (commalign - 1)));
base = base + align;
phys = phys + align;
/*
* Fill in addresses of the Comm Area Headers and Queues
*/
*commaddr = (unsigned long *)base;
init->CommHeaderAddress = cpu_to_le32(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_LIST_HEAD(&q->pendingq);
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 = mem;
q->headers.consumer = 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.
*/
static int aac_send_shutdown(struct aac_dev * dev)
{
struct fib * fibctx;
struct aac_close *cmd;
int status;
fibctx = fib_alloc(dev);
fib_init(fibctx);
cmd = (struct aac_close *) fib_data(fibctx);
cmd->command = cpu_to_le32(VM_CloseAll);
cmd->cid = cpu_to_le32(0xffffffff);
status = fib_send(ContainerCommand,
fibctx,
sizeof(struct aac_close),
FsaNormal,
1, 1,
NULL, NULL);
if (status == 0)
fib_complete(fibctx);
fib_free(fibctx);
return status;
}
/**
* aac_detach - detach adapter
* @detach: adapter to disconnect
*
* Disconnect and shutdown an AAC based adapter, freeing resources
* as we go.
*/
int aac_detach(struct aac_dev *detach)
{
struct aac_dev **dev = &devices;
while(*dev)
{
if(*dev == detach)
{
*dev = detach->next;
aac_send_shutdown(detach);
fib_map_free(detach);
pci_free_consistent(detach->pdev, detach->comm_size, detach->comm_addr, detach->comm_phys);
kfree(detach->queues);
return 1;
}
dev=&((*dev)->next);
}
BUG();
return 0;
}
/**
* aac_comm_init - Initialise FSA data structures
* @dev: Adapter to intialise
*
* 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.
*/
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 contigous 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 *)((unsigned char *)headers + hdrsize);
/* Adapter to Host normal proirity 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)
{
/*
* Ok now init the communication subsystem
*/
dev->queues = (struct aac_queue_block *) kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
if (dev->queues == NULL) {
printk(KERN_ERR "Error could not allocate comm region.\n");
return NULL;
}
memset(dev->queues, 0, sizeof(struct aac_queue_block));
if (aac_comm_init(dev)<0)
return NULL;
/*
* Initialize the list of fibs
*/
if(fib_setup(dev)<0)
return NULL;
INIT_LIST_HEAD(&dev->fib_list);
init_completion(&dev->aif_completion);
/*
* Add this adapter in to our dev List.
*/
dev->next = devices;
devices = dev;
return dev;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment