bitkeeper revision 1.85 (3e56416dqUx5ejRHgvOG3eSEByO2Fg)

Many files:
  new file
  Sync of SMH's new SCSI world with latest repository.
This commit is contained in:
kaf24@labyrinth.cl.cam.ac.uk committed 2003-02-21 15:10:37 +00:00
1 parent 8b154fed7c
commit 566db2a08b
35 files changed
+10476 -1629

No files matched your search

+16
View File
@@ -122,7 +122,21 @@
3ddb79bfJaf0bkE1Y67bnll8-kjEPg xen-2.4.16/drivers/pci/setup-res.c
3ddb79bfIcCWJsBDNcQQE3ok2Azn-Q xen-2.4.16/drivers/pci/syscall.c
3ddb79be3kwzyKagpMHGoXZFdan7dg xen-2.4.16/drivers/scsi/Makefile
3e564137sVLmo7rTnKLNzLSCvuUz8g xen-2.4.16/drivers/scsi/aacraid/Makefile
3e5641379FXvLDjV-0OrRNOBTwL_Lw xen-2.4.16/drivers/scsi/aacraid/README
3e564137MAHzHSRYoWGNmIferNjFVA xen-2.4.16/drivers/scsi/aacraid/TODO
3e564137QLUGVlcwTpnMYATKahDmCg xen-2.4.16/drivers/scsi/aacraid/aachba.c
3e564137Tm_t6rMYyxFtnY9yo_abMg xen-2.4.16/drivers/scsi/aacraid/aacraid.h
3e564137AtfQtRJZiS9B00To0AmKSg xen-2.4.16/drivers/scsi/aacraid/commctrl.c
3e564137a9aOGMOFgQ5CYQJBOD3DvQ xen-2.4.16/drivers/scsi/aacraid/comminit.c
3e564137fw_bPuKcvVi0qwntc_RB-Q xen-2.4.16/drivers/scsi/aacraid/commsup.c
3e564137iEHmY_e6xGZ7TLsjy5yS-g xen-2.4.16/drivers/scsi/aacraid/dpcsup.c
3e564137taxQbEVa39h3mEVLFxRydQ xen-2.4.16/drivers/scsi/aacraid/linit.c
3e564137vmALxpfK7vNINqEklSmQ1A xen-2.4.16/drivers/scsi/aacraid/rx.c
3e564137EuYUJgvqnOunPERWxnp_mw xen-2.4.16/drivers/scsi/aacraid/sa.c
3e56411aOLzeD5CRbuXquOrX0lRijw xen-2.4.16/drivers/scsi/constants.c
3ddb79beXZxwKh7cGyPfr40bhDyRrA xen-2.4.16/drivers/scsi/constants.h
3e564120ZeinH9nf3IVSerB80T7dHg xen-2.4.16/drivers/scsi/hosts.c
3ddb79beGiGljlTNq_kRnCBZECgC9Q xen-2.4.16/drivers/scsi/hosts.h
3ddb79bexarQo1tQ541PPUyK9HXNDA xen-2.4.16/drivers/scsi/scsi.c
3ddb79beBOiYxQUiWTHosepRlJyuGA xen-2.4.16/drivers/scsi/scsi.h
@@ -132,6 +146,7 @@
3ddb79berPStE_-ILQHgcl1BLDLywA xen-2.4.16/drivers/scsi/scsi_lib.c
3ddb79beRXjB7_nNUbJMIRyjDmeByQ xen-2.4.16/drivers/scsi/scsi_merge.c
3ddb79beGNb7Es1bATZAGsPZEu5F2Q xen-2.4.16/drivers/scsi/scsi_module.c
3e56412a_O2cnz-e36volrKvofGe-Q xen-2.4.16/drivers/scsi/scsi_module.c.inc
3ddb79beZ--AZB0twliIm3qmQJO8Zg xen-2.4.16/drivers/scsi/scsi_obsolete.c
3ddb79beQgG_st0eBZUX8AQI7kBkHA xen-2.4.16/drivers/scsi/scsi_obsolete.h
3ddb79beK65cNRldY0CFGXjZ3-A74Q xen-2.4.16/drivers/scsi/scsi_proc.c
@@ -152,6 +167,7 @@
3ddb79c2jFkPAZTDmU35L6IUssYMgQ xen-2.4.16/include/asm-i386/debugreg.h
3ddb79c3r9-31dIsewPV3P3i8HALsQ xen-2.4.16/include/asm-i386/delay.h
3ddb79c34BFiXjBJ_cCKB0aCsV1IDw xen-2.4.16/include/asm-i386/desc.h
3e564149UkU91RX7onzpCAmbj_IFjw xen-2.4.16/include/asm-i386/dma.h
3e20b82fl1jmQiKdLy7fxMcutfpjWA xen-2.4.16/include/asm-i386/domain_page.h
3ddb79c2O729EttZTYu1c8LcsUO_GQ xen-2.4.16/include/asm-i386/elf.h
3ddb79c3NU8Zy40OTrq3D-i30Y3t4A xen-2.4.16/include/asm-i386/fixmap.h
+1
View File
@@ -20,6 +20,7 @@ ALL_OBJS += $(BASEDIR)/drivers/pci/driver.o
ALL_OBJS += $(BASEDIR)/drivers/net/driver.o
ALL_OBJS += $(BASEDIR)/drivers/block/driver.o
ALL_OBJS += $(BASEDIR)/drivers/ide/driver.o
#ALL_OBJS += $(BASEDIR)/drivers/scsi/driver.o
ALL_OBJS += $(BASEDIR)/arch/$(ARCH)/arch.o
HOSTCC = gcc
+2 -2
View File
@@ -5,7 +5,7 @@ default:
$(MAKE) -C net
$(MAKE) -C block
$(MAKE) -C ide
# $(MAKE) -C scsi
$(MAKE) -C scsi
clean:
$(MAKE) -C char clean
@@ -13,4 +13,4 @@ clean:
$(MAKE) -C net clean
$(MAKE) -C block clean
$(MAKE) -C ide clean
# $(MAKE) -C scsi clean
$(MAKE) -C scsi clean
+4 -1
View File
@@ -2,7 +2,10 @@
include $(BASEDIR)/Rules.mk
default: $(OBJS)
$(LD) -r -o driver.o $(OBJS)
$(MAKE) -C aacraid
$(LD) -r -o driver.o $(OBJS) aacraid/aacraid.o
# $(LD) -r -o driver.o $(OBJS)
clean:
$(MAKE) -C aacraid clean
rm -f *.o *~ core
+17
View File
@@ -0,0 +1,17 @@
include $(BASEDIR)/Rules.mk
CFLAGS += -I$(BASEDIR)/drivers/scsi
# -y := linit.o aachba.o commctrl.o comminit.o commsup.o \
# dpcsup.o rx.o sa.o
default: $(OBJS)
$(LD) -r -o aacraid.o $(OBJS)
clean:
rm -f *.o *~ core
+42
View File
@@ -0,0 +1,42 @@
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
+4
View File
@@ -0,0 +1,4 @@
o Testing
o More testing
o Feature request: display the firmware/bios/etc revisions in the
/proc info
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+438
View File
@@ -0,0 +1,438 @@
/*
* 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:
* commctrl.c
*
* Abstract: Contains all routines for control of the AFA comm layer
*
*/
#include <xeno/config.h>
/* #include <xeno/kernel.h> */
#include <xeno/init.h>
#include <xeno/types.h>
#include <xeno/sched.h>
#include <xeno/pci.h>
/* #include <xeno/spinlock.h> */
/* #include <xeno/slab.h> */
/* #include <xeno/completion.h> */
#include <xeno/blk.h>
/* #include <asm/semaphore.h> */
#include <asm/uaccess.h>
#include "scsi.h"
#include "hosts.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.
*/
static int ioctl_send_fib(struct aac_dev * dev, void *arg)
{
struct hw_fib * kfib;
struct fib *fibptr;
fibptr = fib_alloc(dev);
if(fibptr == NULL)
return -ENOMEM;
kfib = fibptr->fib;
/*
* First copy in the header so that we can check the size field.
*/
if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) {
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.
*/
if(le32_to_cpu(kfib->header.Size) > sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) {
fib_free(fibptr);
return -EINVAL;
}
if (copy_from_user((void *) kfib, arg, le32_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr))) {
fib_free(fibptr);
return -EFAULT;
}
if (kfib->header.Command == cpu_to_le32(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 {
if (fib_send(kfib->header.Command, fibptr, le32_to_cpu(kfib->header.Size) , FsaNormal,
1, 1, NULL, NULL) != 0)
{
fib_free(fibptr);
return -EINVAL;
}
if (fib_complete(fibptr) != 0) {
fib_free(fibptr);
return -EINVAL;
}
}
/*
* 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.)
*/
if (copy_to_user(arg, (void *)kfib, kfib->header.Size)) {
fib_free(fibptr);
return -EFAULT;
}
fib_free(fibptr);
return 0;
}
/**
* 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 *arg)
{
struct aac_fib_context * fibctx;
int status;
unsigned long flags;
fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL);
if (fibctx == NULL) {
status = -ENOMEM;
} else {
fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
fibctx->size = sizeof(struct aac_fib_context);
#if 0
/*
* Initialize the mutex used to wait for the next AIF.
*/
init_MUTEX_LOCKED(&fibctx->wait_sem);
#endif
fibctx->wait = 0;
/*
* Initialize the fibs and set the count of fibs on
* the list to 0.
*/
fibctx->count = 0;
INIT_LIST_HEAD(&fibctx->fibs);
fibctx->jiffies = jiffies/HZ;
/*
* Now add this context onto the adapter's
* AdapterFibContext list.
*/
spin_lock_irqsave(&dev->fib_lock, flags);
list_add_tail(&fibctx->next, &dev->fib_list);
spin_unlock_irqrestore(&dev->fib_lock, flags);
if (copy_to_user(arg, &fibctx, sizeof(struct aac_fib_context *))) {
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 *arg)
{
struct fib_ioctl f;
struct aac_fib_context *fibctx, *aifcp;
struct hw_fib * fib;
int status;
struct list_head * entry;
int found;
unsigned long flags;
if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
return -EFAULT;
/*
* Extract the AdapterFibContext from the Input parameters.
*/
fibctx = (struct aac_fib_context *) f.fibctx;
/*
* 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
*/
found = 0;
entry = dev->fib_list.next;
while(entry != &dev->fib_list) {
aifcp = list_entry(entry, struct aac_fib_context, next);
if(fibctx == aifcp) { /* We found a winner */
found = 1;
break;
}
entry = entry->next;
}
if (found == 0)
return -EINVAL;
if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
(fibctx->size != sizeof(struct aac_fib_context)))
return -EINVAL;
status = 0;
spin_lock_irqsave(&dev->fib_lock, flags);
/*
* If there are no fibs to send back, then either wait or return
* -EAGAIN
*/
return_fib:
if (!list_empty(&fibctx->fibs)) {
struct list_head * entry;
/*
* Pull the next fib from the fibs
*/
entry = fibctx->fibs.next;
list_del(entry);
fib = list_entry(entry, struct hw_fib, header.FibLinks);
fibctx->count--;
spin_unlock_irqrestore(&dev->fib_lock, flags);
if (copy_to_user(f.fib, fib, sizeof(struct hw_fib))) {
kfree(fib);
return -EFAULT;
}
/*
* Free the space occupied by this copy of the fib.
*/
kfree(fib);
status = 0;
fibctx->jiffies = jiffies/HZ;
} else {
spin_unlock_irqrestore(&dev->fib_lock, flags);
if (f.wait) {
#if 0
if(down_interruptible(&fibctx->wait_sem) < 0) {
status = -EINTR;
} else {
#else
{
#endif
/* Lock again and retry */
spin_lock_irqsave(&dev->fib_lock, flags);
goto return_fib;
}
} else {
status = -EAGAIN;
}
}
return status;
}
int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
{
struct hw_fib *fib;
/*
* First free any FIBs that have not been consumed.
*/
while (!list_empty(&fibctx->fibs)) {
struct list_head * entry;
/*
* Pull the next fib from the fibs
*/
entry = fibctx->fibs.next;
list_del(entry);
fib = list_entry(entry, struct hw_fib, header.FibLinks);
fibctx->count--;
/*
* Free the space occupied by this copy of the fib.
*/
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 *arg)
{
struct aac_fib_context *fibctx, *aifcp;
int status;
unsigned long flags;
struct list_head * entry;
int found;
/*
* Extract the fibctx from the input parameters
*/
fibctx = arg;
/*
* 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
*/
found = 0;
entry = dev->fib_list.next;
while(entry != &dev->fib_list) {
aifcp = list_entry(entry, struct aac_fib_context, next);
if(fibctx == aifcp) { /* We found a winner */
found = 1;
break;
}
entry = entry->next;
}
if(found == 0)
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 firmware version.
* Under Linux, there have been no version incompatibilities, so this is simple!
*/
static int check_revision(struct aac_dev *dev, void *arg)
{
struct revision response;
response.compat = 1;
response.version = dev->adapter_info.kernelrev;
response.build = dev->adapter_info.kernelbuild;
if (copy_to_user(arg, &response, sizeof(response)))
return -EFAULT;
return 0;
}
struct aac_pci_info {
u32 bus;
u32 slot;
};
int aac_get_pci_info(struct aac_dev* dev, void* 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, (void*)&pci_info, sizeof(struct aac_pci_info)))
return -EFAULT;
return 0;
}
int aac_do_ioctl(struct aac_dev * dev, int cmd, void *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_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_GET_PCI_INFO:
status = aac_get_pci_info(dev,arg);
break;
default:
status = -ENOTTY;
break;
}
return status;
}
+350
View File
@@ -0,0 +1,350 @@
/*
* 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 <xeno/config.h>
/* #include <xeno/kernel.h> */
#include <xeno/init.h>
#include <xeno/types.h>
#include <xeno/sched.h>
#include <xeno/pci.h>
#include <xeno/spinlock.h>
/* #include <xeno/slab.h> */
#include <xeno/blk.h>
/* #include <xeno/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);
#if 0
init_waitqueue_head(&q->cmdready);
#endif
INIT_LIST_HEAD(&q->cmdq);
#if 0
init_waitqueue_head(&q->qfull);
#endif
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));
printk("aac_init_adapater, dev is %p\n", dev);
if (aac_comm_init(dev)<0)
return NULL;
printk("aac_init_adapater, dev->init is %p\n", dev->init);
/*
* Initialize the list of fibs
*/
if(fib_setup(dev)<0)
return NULL;
INIT_LIST_HEAD(&dev->fib_list);
#if 0
init_completion(&dev->aif_completion);
#endif
/*
* Add this adapter in to our dev List.
*/
dev->next = devices;
devices = dev;
return dev;
}
File diff suppressed because it is too large. Load diff
+207
View File
@@ -0,0 +1,207 @@
/*
* 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:
* dpcsup.c
*
* Abstract: All DPC processing routines for the cyclone board occur here.
*
*
*/
#include <xeno/config.h>
/* #include <xeno/kernel.h> */
#include <xeno/init.h>
#include <xeno/types.h>
#include <xeno/sched.h>
#include <xeno/pci.h>
/* #include <xeno/spinlock.h> */
/* #include <xeno/slab.h> */
/* #include <xeno/completion.h> */
#include <xeno/blk.h>
/* #include <asm/semaphore.h> */
#include "scsi.h"
#include "hosts.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;
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;
fast = (int) (entry->addr & 0x01);
hwfib = addr2fib(entry->addr & ~0x01);
aac_consumer_free(dev, q, HostNormRespQueue);
fib = &dev->fibs[hwfib->header.SenderData];
/*
* 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.
*/
if (!(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
list_del(&fib->queue);
dev->queues->queue[AdapNormCmdQueue].numpending--;
} else {
printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
continue;
}
spin_unlock_irqrestore(q->lock, flags);
if (fast) {
/*
* Doctor the fib
*/
*(u32 *)hwfib->data = cpu_to_le32(ST_OK);
hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
}
FIB_COUNTER_INCREMENT(aac_config.FibRecved);
if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
{
u32 *pstatus = (u32 *)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->callback(fib->callback_data, fib);
} else {
#if 0
unsigned long flagv;
spin_lock_irqsave(&fib->event_lock, flagv);
#endif
fib->done = 1;
#if 0
up(&fib->event_wait);
spin_unlock_irqrestore(&fib->event_lock, flagv);
#endif
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
}
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 hw_fib * fib;
fib = addr2fib(entry->addr);
if (dev->aif_thread) {
list_add_tail(&fib->header.FibLinks, &q->cmdq);
aac_consumer_free(dev, q, HostNormCmdQueue);
#if 0
wake_up_interruptible(&q->cmdready);
#endif
} else {
struct fib fibctx;
aac_consumer_free(dev, q, HostNormCmdQueue);
spin_unlock_irqrestore(q->lock, flags);
memset(&fibctx, 0, sizeof(struct fib));
fibctx.type = FSAFS_NTC_FIB_CONTEXT;
fibctx.size = sizeof(struct fib);
fibctx.fib = fib;
fibctx.data = fib->data;
fibctx.dev = dev;
/*
* Set the status of this FIB
*/
*(u32 *)fib->data = cpu_to_le32(ST_OK);
fib_adapter_complete(&fibctx, sizeof(u32));
spin_lock_irqsave(q->lock, flags);
}
}
spin_unlock_irqrestore(q->lock, flags);
return 0;
}
+794
View File
@@ -0,0 +1,794 @@
/*
* 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:
* linit.c
*
* Abstract: Linux Driver entry module for Adaptec RAID Array Controller
*
* Provides the following driver entry points:
* aac_detect()
* aac_release()
* aac_queuecommand()
* aac_resetcommand()
* aac_biosparm()
*
*/
#define AAC_DRIVER_VERSION "0.9.9ac6-TEST"
#define AAC_DRIVER_BUILD_DATE __DATE__
#include <xeno/module.h>
#include <xeno/config.h>
#include <xeno/kernel.h>
#include <xeno/init.h>
#include <xeno/types.h>
#include <xeno/sched.h>
#include <xeno/pci.h>
#include <xeno/spinlock.h>
/* #include <xeno/slab.h> */
/* #include <xeno/completion.h> */
/* #include <asm/semaphore.h> */
#include <xeno/blk.h>
#include "scsi.h"
#include "hosts.h"
#include "aacraid.h"
#include "sd.h"
#define AAC_DRIVERNAME "aacraid"
MODULE_AUTHOR("Red Hat Inc and Adaptec");
MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, PERC 320/DC, Adaptec 2120S, 2200S, 5400S, and HP NetRAID-4M devices. http://domsch.com/xeno/ or http://linux.adaptec.com");
MODULE_LICENSE("GPL");
MODULE_PARM(nondasd, "i");
MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
static int nondasd=-1;
struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS];
static unsigned aac_count = 0;
static int aac_cfg_major = -1;
/*
* Because of the way Linux names scsi devices, the order in this table has
* become important. Check for on-board Raid first, add-in cards second.
*
* dmb - For now we add the number of channels to this structure.
* In the future we should add a fib that reports the number of channels
* for the card. At that time we can remove the channels from here
*/
static struct aac_driver_ident aac_drivers[] = {
{ 0x1028, 0x0001, 0x1028, 0x0001, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* PERC 2/Si */
{ 0x1028, 0x0002, 0x1028, 0x0002, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* PERC 3/Di */
{ 0x1028, 0x0003, 0x1028, 0x0003, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* PERC 3/Si */
{ 0x1028, 0x0004, 0x1028, 0x00d0, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* PERC 3/Si */
{ 0x1028, 0x0002, 0x1028, 0x00d1, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* PERC 3/Di */
{ 0x1028, 0x0002, 0x1028, 0x00d9, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* PERC 3/Di */
{ 0x1028, 0x000a, 0x1028, 0x0106, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* PERC 3/Di */
{ 0x1028, 0x000a, 0x1028, 0x011b, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* PERC 3/Di */
{ 0x1028, 0x000a, 0x1028, 0x0121, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* PERC 3/Di */
{ 0x9005, 0x0283, 0x9005, 0x0283, aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2 }, /* catapult*/
{ 0x9005, 0x0284, 0x9005, 0x0284, aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2 }, /* tomcat*/
{ 0x9005, 0x0285, 0x9005, 0x0286, aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1 }, /* Adaptec 2120S (Crusader)*/
{ 0x9005, 0x0285, 0x9005, 0x0285, aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2 }, /* Adaptec 2200S (Vulcan)*/
{ 0x9005, 0x0285, 0x9005, 0x0287, aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2 }, /* Adaptec 2200S (Vulcan-2m)*/
{ 0x9005, 0x0285, 0x1028, 0x0287, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* Dell PERC 320/DC */
{ 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4 }, /* Adaptec 5400S (Mustang)*/
{ 0x1011, 0x0046, 0x9005, 0x0364, aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4 }, /* Adaptec 5400S (Mustang)*/
{ 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4 }, /* Dell PERC2 "Quad Channel" */
{ 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid", "HP ", "NetRAID-4M ", 4 } /* HP NetRAID-4M */
};
#define NUM_AACTYPES (sizeof(aac_drivers) / sizeof(struct aac_driver_ident))
static int num_aacdrivers = NUM_AACTYPES;
#if 0
static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
static int aac_cfg_open(struct inode * inode, struct file * file);
static int aac_cfg_release(struct inode * inode,struct file * file);
static struct file_operations aac_cfg_fops = {
/* owner: THIS_MODULE, */
ioctl: aac_cfg_ioctl,
open: aac_cfg_open,
release: aac_cfg_release
};
#endif
static int aac_detect(Scsi_Host_Template *);
static int aac_release(struct Scsi_Host *);
static int aac_queuecommand(Scsi_Cmnd *, void (*CompletionRoutine)(Scsi_Cmnd *));
static int aac_biosparm(Scsi_Disk *, kdev_t, int *);
#ifdef CONFIG_PROC_FS
static int aac_procinfo(char *, char **, off_t, int, int, int);
#endif
static int aac_ioctl(Scsi_Device *, int, void *);
static int aac_eh_abort(Scsi_Cmnd * cmd);
static int aac_eh_device_reset(Scsi_Cmnd* cmd);
static int aac_eh_bus_reset(Scsi_Cmnd* cmd);
static int aac_eh_reset(Scsi_Cmnd* cmd);
static void aac_queuedepth(struct Scsi_Host *, Scsi_Device *);
/**
* aac_detect - Probe for aacraid cards
* @template: SCSI driver template
*
* Probe for AAC Host Adapters initialize, register, and report the
* configuration of each AAC Host Adapter found.
* Returns the number of adapters successfully initialized and
* registered.
* Initializes all data necessary for this particular SCSI driver.
* Notes:
* The detect routine must not call any of the mid level functions
* to queue commands because things are not guaranteed to be set
* up yet. The detect routine can send commands to the host adapter
* as long as the program control will not be passed to scsi.c in
* the processing of the command. Note especially that
* scsi_malloc/scsi_free must not be called.
*
*/
static int aac_detect(Scsi_Host_Template *template)
{
int index;
int container;
u16 vendor_id, device_id;
struct Scsi_Host *host_ptr;
struct pci_dev *dev = NULL;
struct aac_dev *aac;
struct fsa_scsi_hba *fsa_dev_ptr;
char *name = NULL;
printk(KERN_INFO "Red Hat/Adaptec aacraid driver, %s\n",
AAC_DRIVER_BUILD_DATE);
/*
** XXX SMH: we need to take interrupts during detect, but the SCSI
** layer is holding this lock with interrupts disabled. I don't
** know how this works on vanilla linux (we 'down' on a semaphone
** at one point during the process -- how do we wake?)
*/
spin_unlock_irq(&io_request_lock);
/* setting up the proc directory structure */
template->proc_name = "aacraid";
for( index = 0; index != num_aacdrivers; index++ )
{
device_id = aac_drivers[index].device;
vendor_id = aac_drivers[index].vendor;
name = aac_drivers[index].name;
dprintk((KERN_DEBUG "Checking %s %x/%x/%x/%x.\n",
name, vendor_id, device_id,
aac_drivers[index].subsystem_vendor,
aac_drivers[index].subsystem_device));
dev = NULL;
while((dev = pci_find_device(vendor_id, device_id, dev))) {
if (pci_enable_device(dev))
continue;
pci_set_master(dev);
pci_set_dma_mask(dev, 0xFFFFFFFFULL);
if((dev->subsystem_vendor != aac_drivers[index].subsystem_vendor) ||
(dev->subsystem_device != aac_drivers[index].subsystem_device))
continue;
dprintk((KERN_DEBUG "%s device detected.\n", name));
dprintk((KERN_DEBUG "%x/%x/%x/%x.\n", vendor_id, device_id,
aac_drivers[index].subsystem_vendor,
aac_drivers[index].subsystem_device));
/* Increment the host adapter count */
aac_count++;
/*
* scsi_register() allocates memory for a Scsi_Hosts
* structure and links it into the linked list of host
* adapters. This linked list contains the data for all
* possible <supported> scsi hosts. This is similar to
* the Scsi_Host_Template, except that we have one entry
* for each actual physical host adapter on the system,
* stored as a linked list. If there are two AAC boards,
* then we will need to make two Scsi_Host entries, but
* there will be only one Scsi_Host_Template entry. The
* second argument to scsi_register() specifies the size
* of the extra memory we want to hold any device specific
* information. */
host_ptr = scsi_register( template, sizeof(struct aac_dev) );
/*
* These three parameters can be used to allow for wide SCSI
* and for host adapters that support multiple buses.
*/
host_ptr->max_id = 17;
host_ptr->max_lun = 8;
host_ptr->max_channel = 1;
host_ptr->irq = dev->irq; /* Adapter IRQ number */
/* host_ptr->base = ( char * )(dev->resource[0].start & ~0xff); */
host_ptr->base = dev->resource[0].start;
scsi_set_pci_device(host_ptr, dev);
dprintk((KERN_DEBUG "Device base address = 0x%lx [0x%lx].\n",
host_ptr->base, dev->resource[0].start));
dprintk((KERN_DEBUG "Device irq = 0x%x.\n", dev->irq));
/*
* The unique_id field is a unique identifier that must
* be assigned so that we have some way of identifying
* each host adapter properly and uniquely. For hosts
* that do not support more than one card in the
* system, this does not need to be set. It is
* initialized to zero in scsi_register(). This is the
* value returned as aac->id.
*/
host_ptr->unique_id = aac_count - 1;
/*
* This function is called after the device list has
* been built to find the tagged queueing depth
* supported for each device.
*/
host_ptr->select_queue_depths = aac_queuedepth;
aac = (struct aac_dev *)host_ptr->hostdata;
/* attach a pointer back to Scsi_Host */
aac->scsi_host_ptr = host_ptr;
aac->pdev = dev;
aac->cardtype = index;
aac->name = aac->scsi_host_ptr->hostt->name;
aac->id = aac->scsi_host_ptr->unique_id;
/* Initialize the ordinal number of the device to -1 */
fsa_dev_ptr = &(aac->fsa_dev);
for( container=0; container < MAXIMUM_NUM_CONTAINERS; container++)
fsa_dev_ptr->devno[container] = -1;
dprintk((KERN_DEBUG "Initializing Hardware...\n"));
if((*aac_drivers[index].init)(aac , host_ptr->unique_id) != 0)
{
/* device initialization failed */
printk(KERN_WARNING
"aacraid: device initialization failed.\n");
scsi_unregister(host_ptr);
aac_count--;
continue;
}
dprintk((KERN_DEBUG "%s:%d device initialization successful.\n",
name, host_ptr->unique_id));
aac_get_adapter_info(aac);
dprintk((KERN_DEBUG "%s got adapter info.\n", name));
if(nondasd != -1)
{
/* someone told us how to set this on the cmdline */
aac->nondasd_support = (nondasd!=0);
}
if(aac->nondasd_support != 0){
printk(KERN_INFO "%s%d: Non-DASD support enabled\n",
aac->name, aac->id);
}
dprintk((KERN_DEBUG "%s:%d options flag %04x.\n", name,
host_ptr->unique_id, aac->adapter_info.options));
if(aac->nondasd_support == 1)
{
/*
* max channel will be the physical
* channels plus 1 virtual channel all
* containers are on the virtual
* channel 0 physical channels are
* address by their actual physical
* number+1 */
host_ptr->max_channel = aac_drivers[index].channels+1;
} else {
host_ptr->max_channel = 1;
}
dprintk((KERN_DEBUG "Device has %d logical channels\n",
host_ptr->max_channel));
aac_get_containers(aac);
aac_devices[aac_count-1] = aac;
/*
* dmb - we may need to move these 3 parms somewhere else once
* we get a fib that can report the actual numbers
*/
host_ptr->max_id = AAC_MAX_TARGET;
host_ptr->max_lun = AAC_MAX_LUN;
/*
* If we are PAE capable then our future DMA mappings
* (for read/write commands) are 64bit clean and don't
* need bouncing. This assumes we do no other 32bit only
* allocations (eg fib table expands) after this point.
*/
if(aac->pae_support)
pci_set_dma_mask(dev, 0xFFFFFFFFFFFFFFFFUL);
}
}
/* XXX SMH: restore lock and IPL for SCSI layer */
spin_lock_irq(&io_request_lock);
#if 0
if( aac_count ){
if((aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops))<0)
printk(KERN_WARNING "aacraid: unable to register 'aac' device.\n");
}
#endif
template->present = aac_count; /* # of cards of this type found */
printk(KERN_DEBUG "aac_detect: returning %d\n", aac_count);
return aac_count;
}
/**
* aac_release - release SCSI host resources
* @host_ptr: SCSI host to clean up
*
* Release all resources previously acquired to support a specific Host
* Adapter and unregister the AAC Host Adapter.
*
* BUGS: Does not wait for the thread it kills to die.
*/
static int aac_release(struct Scsi_Host *host_ptr)
{
struct aac_dev *dev;
dprintk((KERN_DEBUG "aac_release.\n"));
dev = (struct aac_dev *)host_ptr->hostdata;
#if 0
/*
* kill any threads we started
*/
kill_proc(dev->thread_pid, SIGKILL, 0);
wait_for_completion(&dev->aif_completion);
#endif
/*
* Call the comm layer to detach from this adapter
*/
aac_detach(dev);
/* Check free orderings... */
/* remove interrupt binding */
free_irq(host_ptr->irq, dev);
iounmap((void * )dev->regs.sa);
/* unregister adapter */
scsi_unregister(host_ptr);
/*
* FIXME: This assumes no hot plugging is going on...
*/
if( aac_cfg_major >= 0 )
{
#if 0
unregister_chrdev(aac_cfg_major, "aac");
#endif
aac_cfg_major = -1;
}
return 0;
}
/**
* aac_queuecommand - queue a SCSI command
* @scsi_cmnd_ptr: SCSI command to queue
* @CompletionRoutine: Function to call on command completion
*
* Queues a command for execution by the associated Host Adapter.
*/
static int aac_queuecommand(Scsi_Cmnd *scsi_cmnd_ptr, void (*complete)(Scsi_Cmnd *))
{
int ret;
scsi_cmnd_ptr->scsi_done = complete;
/*
* aac_scsi_cmd() handles command processing, setting the
* result code and calling completion routine.
*/
if((ret = aac_scsi_cmd(scsi_cmnd_ptr)) != 0)
dprintk((KERN_DEBUG "aac_scsi_cmd failed.\n"));
return ret;
}
/**
* aac_driverinfo - Returns the host adapter name
* @host_ptr: Scsi host to report on
*
* Returns a static string describing the device in question
*/
const char *aac_driverinfo(struct Scsi_Host *host_ptr)
{
struct aac_dev *dev = (struct aac_dev *)host_ptr->hostdata;
return aac_drivers[dev->cardtype].name;
}
/**
* aac_get_driver_ident
* @devtype: index into lookup table
*
* Returns a pointer to the entry in the driver lookup table.
*/
struct aac_driver_ident* aac_get_driver_ident(int devtype)
{
return &aac_drivers[devtype];
}
/**
* aac_biosparm - return BIOS parameters for disk
* @disk: SCSI disk object to process
* @device: kdev_t of the disk in question
* @geom: geometry block to fill in
*
* Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.
* The default disk geometry is 64 heads, 32 sectors, and the appropriate
* number of cylinders so as not to exceed drive capacity. In order for
* disks equal to or larger than 1 GB to be addressable by the BIOS
* without exceeding the BIOS limitation of 1024 cylinders, Extended
* Translation should be enabled. With Extended Translation enabled,
* drives between 1 GB inclusive and 2 GB exclusive are given a disk
* geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive
* are given a disk geometry of 255 heads and 63 sectors. However, if
* the BIOS detects that the Extended Translation setting does not match
* the geometry in the partition table, then the translation inferred
* from the partition table will be used by the BIOS, and a warning may
* be displayed.
*/
static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom)
{
struct diskparm *param = (struct diskparm *)geom;
struct buffer_head * buf;
dprintk((KERN_DEBUG "aac_biosparm.\n"));
/*
* Assuming extended translation is enabled - #REVISIT#
*/
if( disk->capacity >= 2 * 1024 * 1024 ) /* 1 GB in 512 byte sectors */
{
if( disk->capacity >= 4 * 1024 * 1024 ) /* 2 GB in 512 byte sectors */
{
param->heads = 255;
param->sectors = 63;
}
else
{
param->heads = 128;
param->sectors = 32;
}
}
else
{
param->heads = 64;
param->sectors = 32;
}
param->cylinders = disk->capacity/(param->heads * param->sectors);
#if 0
/*
* Read the first 1024 bytes from the disk device
*/
buf = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev));
if(buf == NULL)
return 0;
/*
* If the boot sector partition table is valid, search for a partition
* table entry whose end_head matches one of the standard geometry
* translations ( 64/32, 128/32, 255/63 ).
*/
#endif
if(*(unsigned short *)(buf->b_data + 0x1fe) == cpu_to_le16(0xaa55))
{
struct partition *first = (struct partition * )(buf->b_data + 0x1be);
struct partition *entry = first;
int saved_cylinders = param->cylinders;
int num;
unsigned char end_head, end_sec;
for(num = 0; num < 4; num++)
{
end_head = entry->end_head;
end_sec = entry->end_sector & 0x3f;
if(end_head == 63)
{
param->heads = 64;
param->sectors = 32;
break;
}
else if(end_head == 127)
{
param->heads = 128;
param->sectors = 32;
break;
}
else if(end_head == 254)
{
param->heads = 255;
param->sectors = 63;
break;
}
entry++;
}
if(num == 4)
{
end_head = first->end_head;
end_sec = first->end_sector & 0x3f;
}
param->cylinders = disk->capacity / (param->heads * param->sectors);
if(num < 4 && end_sec == param->sectors)
{
if(param->cylinders != saved_cylinders)
dprintk((KERN_DEBUG "Adopting geometry: heads=%d, "
"sectors=%d from partition table %d.\n",
param->heads, param->sectors, num));
}
else if(end_head > 0 || end_sec > 0)
{
dprintk((KERN_DEBUG "Strange geometry: heads=%d, "
"sectors=%d in partition table %d.\n",
end_head + 1, end_sec, num));
dprintk((KERN_DEBUG "Using geometry: heads=%d, sectors=%d.\n",
param->heads, param->sectors));
}
}
#if 0
brelse(buf);
#endif
return 0;
}
/**
* aac_queuedepth - compute queue depths
* @host: SCSI host in question
* @dev: SCSI device we are considering
*
* Selects queue depths for each target device based on the host adapter's
* total capacity and the queue depth supported by the target device.
* A queue depth of one automatically disables tagged queueing.
*/
static void aac_queuedepth(struct Scsi_Host * host, Scsi_Device * dev )
{
Scsi_Device * dptr;
dprintk((KERN_DEBUG "aac_queuedepth.\n"));
dprintk((KERN_DEBUG "Device # Q Depth Online\n"));
dprintk((KERN_DEBUG "---------------------------\n"));
for(dptr = dev; dptr != NULL; dptr = dptr->next)
{
if(dptr->host == host)
{
dptr->queue_depth = 10;
dprintk((KERN_DEBUG " %2d %d %d\n",
dptr->id, dptr->queue_depth, dptr->online));
}
}
}
/**
* aac_eh_abort - Abort command if possible.
* @cmd: SCSI command block to abort
*
* Called when the midlayer wishes to abort a command. We don't support
* this facility, and our firmware looks after life for us. We just
* report this as failing
*/
static int aac_eh_abort(Scsi_Cmnd *cmd)
{
return FAILED;
}
/**
* aac_eh_device_reset - Reset command handling
* @cmd: SCSI command block causing the reset
*
* Issue a reset of a SCSI device. We are ourselves not truely a SCSI
* controller and our firmware will do the work for us anyway. Thus this
* is a no-op. We just return FAILED.
*/
static int aac_eh_device_reset(Scsi_Cmnd *cmd)
{
return FAILED;
}
/**
* aac_eh_bus_reset - Reset command handling
* @scsi_cmd: SCSI command block causing the reset
*
* Issue a reset of a SCSI bus. We are ourselves not truely a SCSI
* controller and our firmware will do the work for us anyway. Thus this
* is a no-op. We just return FAILED.
*/
static int aac_eh_bus_reset(Scsi_Cmnd* cmd)
{
return FAILED;
}
/**
* aac_eh_hba_reset - Reset command handling
* @scsi_cmd: SCSI command block causing the reset
*
* Issue a reset of a SCSI host. If things get this bad then arguably we should
* go take a look at what the host adapter is doing and see if something really
* broke (as can occur at least on my Dell QC card if a drive keeps failing spinup)
*/
static int aac_eh_reset(Scsi_Cmnd* cmd)
{
printk(KERN_ERR "aacraid: Host adapter reset request. SCSI hang ?\n");
return FAILED;
}
/**
* aac_ioctl - Handle SCSI ioctls
* @scsi_dev_ptr: scsi device to operate upon
* @cmd: ioctl command to use issue
* @arg: ioctl data pointer
*
* Issue an ioctl on an aacraid device. Returns a standard unix error code or
* zero for success
*/
static int aac_ioctl(Scsi_Device * scsi_dev_ptr, int cmd, void * arg)
{
struct aac_dev *dev;
dprintk((KERN_DEBUG "aac_ioctl.\n"));
dev = (struct aac_dev *)scsi_dev_ptr->host->hostdata;
return aac_do_ioctl(dev, cmd, arg);
}
/**
* aac_cfg_open - open a configuration file
* @inode: inode being opened
* @file: file handle attached
*
* Called when the configuration device is opened. Does the needed
* set up on the handle and then returns
*
* Bugs: This needs extending to check a given adapter is present
* so we can support hot plugging, and to ref count adapters.
*/
static int aac_cfg_open(struct inode * inode, struct file * file )
{
unsigned minor_number = MINOR(inode->i_rdev);
if(minor_number >= aac_count)
return -ENODEV;
return 0;
}
/**
* aac_cfg_release - close down an AAC config device
* @inode: inode of configuration file
* @file: file handle of configuration file
*
* Called when the last close of the configuration file handle
* is performed.
*/
static int aac_cfg_release(struct inode * inode, struct file * file )
{
return 0;
}
/**
* aac_cfg_ioctl - AAC configuration request
* @inode: inode of device
* @file: file handle
* @cmd: ioctl command code
* @arg: argument
*
* Handles a configuration ioctl. Currently this involves wrapping it
* up and feeding it into the nasty windowsalike glue layer.
*
* Bugs: Needs locking against parallel ioctls lower down
* Bugs: Needs to handle hot plugging
*/
static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg )
{
struct aac_dev *dev = aac_devices[MINOR(inode->i_rdev)];
return aac_do_ioctl(dev, cmd, (void *)arg);
}
/*
* To use the low level SCSI driver support using the linux kernel loadable
* module interface we should initialize the global variable driver_interface
* (datatype Scsi_Host_Template) and then include the file scsi_module.c.
*/
static Scsi_Host_Template driver_template = {
/* module: THIS_MODULE, */
name: "AAC",
/* proc_info: aac_procinfo, */
detect: aac_detect,
release: aac_release,
info: aac_driverinfo,
ioctl: aac_ioctl,
queuecommand: aac_queuecommand,
bios_param: aac_biosparm,
can_queue: AAC_NUM_IO_FIB,
this_id: 16,
sg_tablesize: 16,
max_sectors: 128,
cmd_per_lun: AAC_NUM_IO_FIB,
eh_abort_handler: aac_eh_abort,
eh_device_reset_handler:aac_eh_device_reset,
eh_bus_reset_handler: aac_eh_bus_reset,
eh_host_reset_handler: aac_eh_reset,
use_new_eh_code: 1,
use_clustering: ENABLE_CLUSTERING,
};
#include "../scsi_module.c.inc"
#ifdef CONFIG_PROC_FS
/**
* aac_procinfo - Implement /proc/scsi/<drivername>/<n>
* @proc_buffer: memory buffer for I/O
* @start_ptr: pointer to first valid data
* @offset: offset into file
* @bytes_available: space left
* @host_no: scsi host ident
* @write: direction of I/O
*
* Used to export driver statistics and other infos to the world outside
* the kernel using the proc file system. Also provides an interface to
* feed the driver with information.
*
* For reads
* - if offset > 0 return 0
* - if offset == 0 write data to proc_buffer and set the start_ptr to
* beginning of proc_buffer, return the number of characters written.
* For writes
* - writes currently not supported, return 0
*
* Bugs: Only offset zero is handled
*/
static int aac_procinfo(char *proc_buffer, char **start_ptr,off_t offset,
int bytes_available, int host_no, int write)
{
if(write || offset > 0)
return 0;
*start_ptr = proc_buffer;
return sprintf(proc_buffer, "%s %d\n",
"Raid Controller, scsi hba number", host_no);
}
#endif
EXPORT_NO_SYMBOLS;
+457
View File
@@ -0,0 +1,457 @@
/*
* 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:
* rx.c
*
* Abstract: Hardware miniport for Drawbridge specific hardware functions.
*
*/
#include <xeno/config.h>
#include <xeno/kernel.h>
#include <xeno/init.h>
#include <xeno/types.h>
#include <xeno/sched.h>
#include <xeno/pci.h>
/* #include <xeno/spinlock.h> */
/* #include <xeno/slab.h> */
#include <xeno/blk.h>
#include <xeno/delay.h>
/* #include <xeno/completion.h> */
/* #include <asm/semaphore.h> */
#include "scsi.h"
#include "hosts.h"
#include "aacraid.h"
static void aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
{
struct aac_dev *dev = dev_id;
unsigned long bellbits;
u8 intstat, mask;
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.
*/
mask = ~(rx_readb(dev, MUnit.OIMR));
/* Check to see if this is our interrupt. If it isn't just return */
if (intstat & mask)
{
bellbits = rx_readl(dev, OutboundDoorbellReg);
if (bellbits & DoorBellPrintfReady) {
aac_printf(dev, le32_to_cpu(rx_readl (dev, IndexRegs.Mailbox[5])));
rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
}
else if (bellbits & DoorBellAdapterNormCmdReady) {
aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
}
else if (bellbits & DoorBellAdapterNormRespReady) {
aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
}
else if (bellbits & DoorBellAdapterNormCmdNotFull) {
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
}
else if (bellbits & DoorBellAdapterNormRespNotFull) {
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
}
}
}
/**
* aac_rx_enable_interrupt - Enable event reporting
* @dev: Adapter
* @event: Event to enable
*
* Enable event reporting from the i960 for a given event.
*/
static void aac_rx_enable_interrupt(struct aac_dev * dev, u32 event)
{
switch (event) {
case HostNormCmdQue:
dev->irq_mask &= ~(OUTBOUNDDOORBELL_1);
break;
case HostNormRespQue:
dev->irq_mask &= ~(OUTBOUNDDOORBELL_2);
break;
case AdapNormCmdNotFull:
dev->irq_mask &= ~(OUTBOUNDDOORBELL_3);
break;
case AdapNormRespNotFull:
dev->irq_mask &= ~(OUTBOUNDDOORBELL_4);
break;
}
}
/**
* aac_rx_disable_interrupt - Disable event reporting
* @dev: Adapter
* @event: Event to enable
*
* Disable event reporting from the i960 for a given event.
*/
static void aac_rx_disable_interrupt(struct aac_dev *dev, u32 event)
{
switch (event) {
case HostNormCmdQue:
dev->irq_mask |= (OUTBOUNDDOORBELL_1);
break;
case HostNormRespQue:
dev->irq_mask |= (OUTBOUNDDOORBELL_2);
break;
case AdapNormCmdNotFull:
dev->irq_mask |= (OUTBOUNDDOORBELL_3);
break;
case AdapNormRespNotFull:
dev->irq_mask |= (OUTBOUNDDOORBELL_4);
break;
}
}
/**
* 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 comamnd to the adapter and wait
* for its completion.
*/
static int rx_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status)
{
unsigned long start;
int ok;
/*
* Write the command into Mailbox 0
*/
rx_writel(dev, InboundMailbox0, cpu_to_le32(command));
/*
* Write the parameters into Mailboxes 1 - 4
*/
rx_writel(dev, InboundMailbox1, cpu_to_le32(p1));
rx_writel(dev, InboundMailbox2, 0);
rx_writel(dev, InboundMailbox3, 0);
rx_writel(dev, InboundMailbox4, 0);
/*
* 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, rx_readb(dev, MUnit.OIMR) | 0x04);
/*
* 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))
{
/* Delay 5 microseconds to let Mon960 get info. */
udelay(5);
/*
* Mon960 will set doorbell0 bit when its completed the command.
*/
if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
/*
* Clear the doorbell.
*/
rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
ok = 1;
break;
}
#if 0
/*
* Yield the processor in case we are slow
*/
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
#else
/* XXX SMH: not in xen we don't */
mdelay(50);
#endif
}
if (ok != 1) {
/*
* Restore interrupt mask even though we timed out
*/
rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb);
return -ETIMEDOUT;
}
/*
* Pull the synch status from Mailbox 0.
*/
*status = le32_to_cpu(rx_readl(dev, IndexRegs.Mailbox[0]));
/*
* Clear the synch command doorbell.
*/
rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
/*
* Restore interrupt mask
*/
rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb);
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)
{
u32 ret;
rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
}
/**
* 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:
// rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, &ret);
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)
{
u32 status;
struct aac_init *init;
init = dev->init;
printk("aac_rx_start: dev is %p, init is %p\n", dev, init);
init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ);
/*
* Tell the adapter we are back and up and running so it will scan
* its command queues and enable our interrupts
*/
dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 |
OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 |
OUTBOUNDDOORBELL_4);
/*
* First clear out all interrupts. Then enable the one's that we
* can handle.
*/
rx_writeb(dev, MUnit.OIMR, 0xff);
rx_writel(dev, MUnit.ODR, 0xffffffff);
// rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK);
rx_writeb(dev, MUnit.OIMR, 0xfb);
// We can only use a 32 bit address here
rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS,
(u32)(ulong)dev->init_pa, &status);
}
/**
* aac_rx_init - initialize an i960 based AAC card
* @dev: device to configure
* @devnum: adapter number
*
* 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 num)
{
unsigned long start;
unsigned long status;
int instance;
const char * name;
dev->devnum = num;
instance = dev->id;
name = dev->name;
dprintk((KERN_ERR "aac_rx_init called, num %ld, scsi host ptr = %p\n",
num, (void *)(dev->scsi_host_ptr)));
dprintk((KERN_ERR "scsi_host_ptr->base is %p\n",
(void *)dev->scsi_host_ptr->base));
/*
* Map in the registers from the adapter.
*/
if((dev->regs.rx = (struct rx_registers *)
ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
{
printk(KERN_WARNING "aacraid: unable to map i960.\n" );
return -1;
}
// dprintk((KERN_ERR "aac_rx_init: AAA\n"));
/*
* Check to see if the board failed any self tests.
*/
if (rx_readl(dev, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) {
printk(KERN_ERR "%s%d: adapter self-test failed.\n",
dev->name, instance);
return -1;
}
// dprintk((KERN_ERR "aac_rx_init: BBB\n"));
/*
* Check to see if the board panic'd while booting.
*/
if (rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_PANIC) {
printk(KERN_ERR "%s%d: adapter kernel panic'd.\n",
dev->name, instance);
return -1;
}
start = jiffies;
// dprintk((KERN_ERR "aac_rx_init: DDD\n"));
/*
* Wait for the adapter to be up and running. Wait up to 3 minutes
*/
while (!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING))
{
if(time_after(jiffies, start+180*HZ))
{
status = rx_readl(dev, IndexRegs.Mailbox[7]) >> 16;
printk(KERN_ERR "%s%d: adapter kernel failed to start,"
"init status = %ld.\n", dev->name,
instance, status);
return -1;
}
// dprintk((KERN_ERR "aac_rx_init: XXX\n"));
#if 0
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
#else
/* XXX SMH: no sleeping for us (we're the xen idle task) */
mdelay(50);
#endif
}
// dprintk((KERN_ERR "aac_rx_init: ZZZ!\n"));
if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr,
SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev) < 0)
{
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
name, instance);
return -1;
}
/*
* Fill in the function dispatch table.
*/
dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;
dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt;
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;
if (aac_init_adapter(dev) == NULL)
return -1;
#if 0
/*
* Start any kernel threads needed
*/
dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread,
dev, 0);
#else
/* XXX SMH: just put in a softirq handler instead... */
open_softirq(SCSI_LOW_SOFTIRQ, aac_command_thread, dev);
#endif
/*
* Tell the adapter that all is configured, and it can start
* accepting requests
*/
aac_rx_start_adapter(dev);
return 0;
}
+406
View File
@@ -0,0 +1,406 @@
/*
* 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:
* sa.c
*
* Abstract: Drawbridge specific support functions
*
*/
#include <xeno/config.h>
#include <xeno/kernel.h>
#include <xeno/init.h>
#include <xeno/types.h>
#include <xeno/sched.h>
/* #include <xeno/pci.h> */
/* #include <xeno/spinlock.h> */
/* #include <xeno/slab.h> */
#include <xeno/blk.h>
#include <xeno/delay.h>
/* #include <xeno/completion.h> */
/* #include <asm/semaphore.h> */
#include "scsi.h"
#include "hosts.h"
#include "aacraid.h"
static void aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs)
{
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, le32_to_cpu(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
aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
sa_writew(dev, DoorbellClrReg_p, DOORBELL_1);
} else if (intstat & DOORBELL_2) { // dev -> Host Normal Response Ready
aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
sa_writew(dev, DoorbellClrReg_p, DOORBELL_2);
} 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);
}
}
}
/**
* aac_sa_enable_interrupt - enable an interrupt event
* @dev: Which adapter to enable.
* @event: Which adapter event.
*
* This routine will enable the corresponding adapter event to cause an interrupt on
* the host.
*/
void aac_sa_enable_interrupt(struct aac_dev *dev, u32 event)
{
switch (event) {
case HostNormCmdQue:
sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_1);
break;
case HostNormRespQue:
sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_2);
break;
case AdapNormCmdNotFull:
sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_3);
break;
case AdapNormRespNotFull:
sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_4);
break;
}
}
/**
* aac_sa_disable_interrupt - disable an interrupt event
* @dev: Which adapter to enable.
* @event: Which adapter event.
*
* This routine will enable the corresponding adapter event to cause an interrupt on
* the host.
*/
void aac_sa_disable_interrupt (struct aac_dev *dev, u32 event)
{
switch (event) {
case HostNormCmdQue:
sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_1);
break;
case HostNormRespQue:
sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_2);
break;
case AdapNormCmdNotFull:
sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_3);
break;
case AdapNormRespNotFull:
sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_4);
break;
}
}
/**
* aac_sa_notify_adapter - handle adapter notification
* @dev: Adapter that notification is for
* @event: Event to notidy
*
* Notify the adapter of an event
*/
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, &ret);
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 comamnd to the adapter and wait
* for its completion.
*/
static int sa_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *ret)
{
unsigned long start;
int ok;
/*
* Write the Command into Mailbox 0
*/
sa_writel(dev, Mailbox0, cpu_to_le32(command));
/*
* Write the parameters into Mailboxes 1 - 4
*/
sa_writel(dev, Mailbox1, cpu_to_le32(p1));
sa_writel(dev, Mailbox2, 0);
sa_writel(dev, Mailbox3, 0);
sa_writel(dev, Mailbox4, 0);
/*
* 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;
}
#if 0
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
#endif
mdelay(100);
}
if (ok != 1)
return -ETIMEDOUT;
/*
* Clear the synch command doorbell.
*/
sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
/*
* Pull the synch status from Mailbox 0.
*/
*ret = le32_to_cpu(sa_readl(dev, Mailbox0));
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)
{
u32 ret;
sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
}
/**
* 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)
{
u32 ret;
struct aac_init *init;
/*
* Fill in the remaining pieces of the init.
*/
init = dev->init;
init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ);
dprintk(("INIT\n"));
/*
* Tell the adapter we are back and up and running so it will scan its command
* queues and enable our interrupts
*/
dev->irq_mask = (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4);
/*
* First clear out all interrupts. Then enable the one's that
* we can handle.
*/
dprintk(("MASK\n"));
sa_writew(dev, SaDbCSR.PRISETIRQMASK, cpu_to_le16(0xffff));
sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
dprintk(("SYNCCMD\n"));
/* We can only use a 32 bit address here */
sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &ret);
}
/**
* aac_sa_init - initialize an ARM based AAC card
* @dev: device to configure
* @devnum: adapter number
*
* 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 devnum)
{
unsigned long start;
unsigned long status;
int instance;
const char *name;
dev->devnum = devnum;
dprintk(("PREINST\n"));
instance = dev->id;
name = dev->name;
/*
* Map in the registers from the adapter.
*/
dprintk(("PREMAP\n"));
if((dev->regs.sa = (struct sa_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
{
printk(KERN_WARNING "aacraid: unable to map ARM.\n" );
return -1;
}
/*
* 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);
return -1;
}
/*
* 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);
return -1;
}
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(start+180*HZ, jiffies)) {
status = sa_readl(dev, Mailbox7) >> 16;
printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %d.\n", name, instance, le32_to_cpu(status));
return -1;
}
#if 0
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
#endif
mdelay(100);
}
dprintk(("ATIRQ\n"));
if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) {
printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance);
return -1;
}
/*
* Fill in the function dispatch table.
*/
dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;
dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
dev->a_ops.adapter_notify = aac_sa_notify_adapter;
dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
dprintk(("FUNCDONE\n"));
if(aac_init_adapter(dev) == NULL)
return -1;
dprintk(("NEWADAPTDONE\n"));
#if 0
/*
* Start any kernel threads needed
*/
dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
#endif
/*
* Tell the adapter that all is configure, and it can start
* accepting requests
*/
dprintk(("STARTING\n"));
aac_sa_start_adapter(dev);
dprintk(("STARTED\n"));
return 0;
}
File diff suppressed because it is too large. Load diff
+316
View File
@@ -0,0 +1,316 @@
/*
* hosts.c Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994, 1995 Eric Youngdale
*
* mid to lowlevel SCSI driver interface
* Initial versions: Drew Eckhardt
* Subsequent revisions: Eric Youngdale
*
* <drew@colorado.edu>
*
* Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
* Added QLOGIC QLA1280 SCSI controller kernel host support.
* August 4, 1999 Fred Lewis, Intel DuPont
*
* Updated to reflect the new initialization scheme for the higher
* level of scsi drivers (sd/sr/st)
* September 17, 2000 Torben Mathiasen <tmm@image.dk>
*/
/*
* This file contains the medium level SCSI
* host interface initialization, as well as the scsi_hosts array of SCSI
* hosts currently present in the system.
*/
#define __NO_VERSION__
#include <xeno/module.h>
#include <xeno/blk.h>
/* #include <xeno/kernel.h> */
/* #include <xeno/string.h> */
/* #include <xeno/mm.h> */
/* #include <xeno/proc_fs.h> */
#include <xeno/init.h>
#define __KERNEL_SYSCALLS__
/* #include <xeno/unistd.h> */
#include "scsi.h"
#include "hosts.h"
/*
static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.20 1996/12/12 19:18:32 davem Exp $";
*/
/*
* The scsi host entries should be in the order you wish the
* cards to be detected. A driver may appear more than once IFF
* it can deal with being detected (and therefore initialized)
* with more than one simultaneous host number, can handle being
* reentrant, etc.
*
* They may appear in any order, as each SCSI host is told which host
* number it is during detection.
*/
/* This is a placeholder for controllers that are not configured into
* the system - we do this to ensure that the controller numbering is
* always consistent, no matter how the kernel is configured. */
#define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
NULL, NULL, 0, 0, 0, 0, 0, 0}
/*
* When figure is run, we don't want to link to any object code. Since
* the macro for each host will contain function pointers, we cannot
* use it and instead must use a "blank" that does no such
* idiocy.
*/
Scsi_Host_Template * scsi_hosts;
/*
* Our semaphores and timeout counters, where size depends on
* MAX_SCSI_HOSTS here.
*/
Scsi_Host_Name * scsi_host_no_list;
struct Scsi_Host * scsi_hostlist;
struct Scsi_Device_Template * scsi_devicelist;
int max_scsi_hosts;
int next_scsi_host;
void
scsi_unregister(struct Scsi_Host * sh){
struct Scsi_Host * shpnt;
Scsi_Host_Name *shn;
if(scsi_hostlist == sh)
scsi_hostlist = sh->next;
else {
shpnt = scsi_hostlist;
while(shpnt->next != sh) shpnt = shpnt->next;
shpnt->next = shpnt->next->next;
}
/*
* We have to unregister the host from the scsi_host_no_list as well.
* Decide by the host_no not by the name because most host drivers are
* able to handle more than one adapters from the same kind (or family).
*/
for ( shn=scsi_host_no_list; shn && (sh->host_no != shn->host_no);
shn=shn->next);
if (shn) shn->host_registered = 0;
/* else {} : This should not happen, we should panic here... */
/* If we are removing the last host registered, it is safe to reuse
* its host number (this avoids "holes" at boot time) (DB)
* It is also safe to reuse those of numbers directly below which have
* been released earlier (to avoid some holes in numbering).
*/
if(sh->host_no == max_scsi_hosts - 1) {
while(--max_scsi_hosts >= next_scsi_host) {
shpnt = scsi_hostlist;
while(shpnt && shpnt->host_no != max_scsi_hosts - 1)
shpnt = shpnt->next;
if(shpnt)
break;
}
}
next_scsi_host--;
kfree((char *) sh);
}
/* We call this when we come across a new host adapter. We only do this
* once we are 100% sure that we want to use this host adapter - it is a
* pain to reverse this, so we try to avoid it
*/
struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
struct Scsi_Host * retval, *shpnt, *o_shp;
Scsi_Host_Name *shn, *shn2;
int flag_new = 1;
const char * hname;
size_t hname_len;
retval = (struct Scsi_Host *)kmalloc(sizeof(struct Scsi_Host) + j,
(tpnt->unchecked_isa_dma && j ?
GFP_DMA : 0) | GFP_ATOMIC);
if(retval == NULL)
{
printk("scsi: out of memory in scsi_register.\n");
return NULL;
}
memset(retval, 0, sizeof(struct Scsi_Host) + j);
/* trying to find a reserved entry (host_no) */
hname = (tpnt->proc_name) ? tpnt->proc_name : "";
hname_len = strlen(hname);
for (shn = scsi_host_no_list;shn;shn = shn->next) {
if (!(shn->host_registered) &&
(hname_len > 0) && (0 == strncmp(hname, shn->name, hname_len))) {
flag_new = 0;
retval->host_no = shn->host_no;
shn->host_registered = 1;
shn->loaded_as_module = 1;
break;
}
}
atomic_set(&retval->host_active,0);
retval->host_busy = 0;
retval->host_failed = 0;
if(j > 0xffff) panic("Too many extra bytes requested\n");
retval->extra_bytes = j;
retval->loaded_as_module = 1;
if (flag_new) {
shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC);
if (!shn) {
kfree(retval);
printk(KERN_ERR "scsi: out of memory(2) in scsi_register.\n");
return NULL;
}
shn->name = kmalloc(hname_len + 1, GFP_ATOMIC);
if (hname_len > 0)
strncpy(shn->name, hname, hname_len);
shn->name[hname_len] = 0;
shn->host_no = max_scsi_hosts++;
shn->host_registered = 1;
shn->loaded_as_module = 1;
shn->next = NULL;
if (scsi_host_no_list) {
for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
;
shn2->next = shn;
}
else
scsi_host_no_list = shn;
retval->host_no = shn->host_no;
}
next_scsi_host++;
retval->host_queue = NULL;
#if 0
init_waitqueue_head(&retval->host_wait);
#endif
retval->resetting = 0;
retval->last_reset = 0;
retval->irq = 0;
retval->dma_channel = 0xff;
/* These three are default values which can be overridden */
retval->max_channel = 0;
retval->max_id = 8;
retval->max_lun = 8;
/*
* All drivers right now should be able to handle 12 byte commands.
* Every so often there are requests for 16 byte commands, but individual
* low-level drivers need to certify that they actually do something
* sensible with such commands.
*/
retval->max_cmd_len = 12;
retval->unique_id = 0;
retval->io_port = 0;
retval->hostt = tpnt;
retval->next = NULL;
retval->in_recovery = 0;
retval->ehandler = NULL; /* Initial value until the thing starts up. */
retval->eh_notify = NULL; /* Who we notify when we exit. */
retval->host_blocked = FALSE;
retval->host_self_blocked = FALSE;
#ifdef DEBUG
printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
#endif
/* The next six are the default values which can be overridden
* if need be */
retval->this_id = tpnt->this_id;
retval->can_queue = tpnt->can_queue;
retval->sg_tablesize = tpnt->sg_tablesize;
retval->cmd_per_lun = tpnt->cmd_per_lun;
retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
retval->use_clustering = tpnt->use_clustering;
retval->select_queue_depths = tpnt->select_queue_depths;
retval->max_sectors = tpnt->max_sectors;
if(!scsi_hostlist)
scsi_hostlist = retval;
else {
shpnt = scsi_hostlist;
if (retval->host_no < shpnt->host_no) {
retval->next = shpnt;
wmb(); /* want all to see these writes in this order */
scsi_hostlist = retval;
}
else {
for (o_shp = shpnt, shpnt = shpnt->next; shpnt;
o_shp = shpnt, shpnt = shpnt->next) {
if (retval->host_no < shpnt->host_no) {
retval->next = shpnt;
wmb();
o_shp->next = retval;
break;
}
}
if (! shpnt)
o_shp->next = retval;
}
}
return retval;
}
int
scsi_register_device(struct Scsi_Device_Template * sdpnt)
{
if(sdpnt->next) panic("Device already registered");
sdpnt->next = scsi_devicelist;
scsi_devicelist = sdpnt;
return 0;
}
void
scsi_deregister_device(struct Scsi_Device_Template * tpnt)
{
struct Scsi_Device_Template *spnt;
struct Scsi_Device_Template *prev_spnt;
spnt = scsi_devicelist;
prev_spnt = NULL;
while (spnt != tpnt) {
prev_spnt = spnt;
spnt = spnt->next;
}
if (prev_spnt == NULL)
scsi_devicelist = tpnt->next;
else
prev_spnt->next = spnt->next;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
* indent-tabs-mode: nil
* tab-width: 8
* End:
*/
+6
View File
@@ -64,6 +64,7 @@ typedef struct SHT
/* Used with loadable modules so that we know when it is safe to unload */
struct module * module;
#ifdef CONFIG_PROC_FS
/* The pointer to the /proc/scsi directory entry */
struct proc_dir_entry *proc_dir;
@@ -73,6 +74,7 @@ typedef struct SHT
* to feed the driver with information. Check eata_dma_proc.c for reference
*/
int (*proc_info)(char *, char **, off_t, int, int, int);
#endif
/*
* The name pointer is a pointer to the name of the SCSI
@@ -326,7 +328,9 @@ struct Scsi_Host
host. */
unsigned int eh_active:1; /* Indicates the eh thread is awake and active if
this is true. */
#if 0
wait_queue_head_t host_wait;
#endif
Scsi_Host_Template * hostt;
atomic_t host_active; /* commands checked out */
volatile unsigned short host_busy; /* commands actually active on low-level */
@@ -528,9 +532,11 @@ void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt);
int scsi_register_device(struct Scsi_Device_Template * sdpnt);
void scsi_deregister_device(struct Scsi_Device_Template * tpnt);
#if 0
/* These are used by loadable modules */
extern int scsi_register_module(int, void *);
extern int scsi_unregister_module(int, void *);
#endif
/* The different types of modules that we can load and unload */
#define MODULE_SCSI_HA 1
File diff suppressed because it is too large. Load diff
+37 -22
View File
@@ -558,8 +558,11 @@ struct scsi_device {
*/
struct scsi_device *next; /* Used for linked list */
struct scsi_device *prev; /* Used for linked list */
#if 0
wait_queue_head_t scpnt_wait; /* Used to wait if
device is busy */
#endif
struct Scsi_Host *host;
request_queue_t request_queue;
atomic_t device_active; /* commands checked out for device */
@@ -580,7 +583,9 @@ struct scsi_device {
int access_count; /* Count of open channels/mounts */
void *hostdata; /* available to low-level driver */
#if 0
devfs_handle_t de; /* directory for the device */
#endif
char type;
char scsi_level;
char vendor[8], model[16], rev[4];
@@ -650,29 +655,32 @@ typedef struct scsi_pointer {
* of the queue and being sent to the driver.
*/
struct scsi_request {
int sr_magic;
int sr_result; /* Status code from lower level driver */
unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE
* when CHECK CONDITION is
* received on original command
* (auto-sense) */
struct Scsi_Host *sr_host;
Scsi_Device *sr_device;
Scsi_Cmnd *sr_command;
struct request sr_request; /* A copy of the command we are
int sr_magic;
int sr_result; /* Status code from lower level driver */
unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE];
/* obtained by REQUEST SENSE when CHECK CONDITION is received
on original command (auto-sense) */
struct Scsi_Host *sr_host;
Scsi_Device *sr_device;
Scsi_Cmnd *sr_command;
#define SMHHACK
#ifdef SMHHACK
void *freeaddr;
#endif
struct request sr_request; /* A copy of the command we are
working on */
unsigned sr_bufflen; /* Size of data buffer */
void *sr_buffer; /* Data buffer */
int sr_allowed;
unsigned char sr_data_direction;
unsigned char sr_cmd_len;
unsigned char sr_cmnd[MAX_COMMAND_SIZE];
void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */
int sr_timeout_per_command;
unsigned short sr_use_sg; /* Number of pieces of scatter-gather */
unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */
unsigned sr_underflow; /* Return error if less than
unsigned sr_bufflen; /* Size of data buffer */
void *sr_buffer; /* Data buffer */
int sr_allowed;
unsigned char sr_data_direction;
unsigned char sr_cmd_len;
unsigned char sr_cmnd[MAX_COMMAND_SIZE];
void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */
int sr_timeout_per_command;
unsigned short sr_use_sg; /* Number of pieces of scatter-gather */
unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */
unsigned sr_underflow; /* Return error if less than
this amount is transferred */
};
@@ -830,6 +838,7 @@ struct scsi_cmnd {
#define SCSI_MLQUEUE_HOST_BUSY 0x1055
#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
#if 0
#define SCSI_SLEEP(QUEUE, CONDITION) { \
if (CONDITION) { \
DECLARE_WAITQUEUE(wait, current); \
@@ -848,6 +857,12 @@ struct scsi_cmnd {
remove_wait_queue(QUEUE, &wait);\
current->state = TASK_RUNNING; \
}; }
#else
#define SCSI_SLEEP(QUEUE, CONDITION) { printk("SCSI_SLEEP!\n"); BUG(); }
#endif
/*
* old style reset request from external source
+8 -4
View File
@@ -6,9 +6,9 @@
*/
#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/blk.h>
#include <xeno/config.h>
#include <xeno/module.h>
#include <xeno/blk.h>
#include "scsi.h"
@@ -165,6 +165,7 @@ int scsi_free(void *obj, unsigned int len)
}
}
panic("scsi_free:Bad offset");
return -1;
}
@@ -206,7 +207,8 @@ void scsi_resize_dma_pool(void)
* Free up the DMA pool.
*/
if (scsi_dma_free_sectors != dma_sectors)
panic("SCSI DMA pool memory leak %d %d\n", scsi_dma_free_sectors, dma_sectors);
panic("SCSI DMA pool memory leak %d %d\n",
scsi_dma_free_sectors, dma_sectors);
for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++)
free_pages((unsigned long) dma_malloc_pages[i], 0);
@@ -225,9 +227,11 @@ void scsi_resize_dma_pool(void)
new_dma_sectors = 2 * SECTORS_PER_PAGE; /* Base value we use */
#if 0
if (__pa(high_memory) - 1 > ISA_DMA_THRESHOLD)
need_isa_bounce_buffers = 1;
else
#endif
need_isa_bounce_buffers = 0;
if (scsi_devicelist)
+51 -15
View File
@@ -9,23 +9,23 @@
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <xeno/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/blk.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/smp_lock.h>
#include <xeno/sched.h>
#include <xeno/timer.h>
/*#include <xeno/string.h>*/
#include <xeno/slab.h>
#include <xeno/ioport.h>
#include <xeno/kernel.h>
/*#include <xeno/stat.h>*/
#include <xeno/blk.h>
#include <xeno/interrupt.h>
#include <xeno/delay.h>
/*#include <xeno/smp_lock.h>*/
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
/*#include <xeno/unistd.h>*/
#include <asm/system.h>
#include <asm/irq.h>
@@ -226,6 +226,7 @@ void scsi_times_out(Scsi_Cmnd * SCpnt)
SCpnt->host->host_busy,
SCpnt->host->host_failed));
#if 0
/*
* If the host is having troubles, then look to see if this was the last
* command that might have failed. If so, wake up the error handler.
@@ -237,6 +238,7 @@ void scsi_times_out(Scsi_Cmnd * SCpnt)
if (SCpnt->host->host_busy == SCpnt->host->host_failed) {
up(SCpnt->host->eh_wait);
}
#endif
}
/*
@@ -283,9 +285,11 @@ void scsi_eh_times_out(Scsi_Cmnd * SCpnt)
SCpnt->eh_state = SCSI_STATE_TIMEOUT;
SCSI_LOG_ERROR_RECOVERY(5, printk("In scsi_eh_times_out %p\n", SCpnt));
#if 0
if (SCpnt->host->eh_action != NULL)
up(SCpnt->host->eh_action);
else
#endif
printk("Missing scsi error handler thread\n");
}
@@ -329,8 +333,10 @@ void scsi_eh_done(Scsi_Cmnd * SCpnt)
SCSI_LOG_ERROR_RECOVERY(5, printk("In eh_done %p result:%x\n", SCpnt,
SCpnt->result));
#if 0
if (SCpnt->host->eh_action != NULL)
up(SCpnt->host->eh_action);
#endif
}
/*
@@ -352,9 +358,10 @@ void scsi_eh_action_done(Scsi_Cmnd * SCpnt, int answer)
SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
SCpnt->eh_state = (answer ? SUCCESS : FAILED);
#if 0
if (SCpnt->host->eh_action != NULL)
up(SCpnt->host->eh_action);
#endif
}
/*
@@ -548,18 +555,26 @@ STATIC int scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
STATIC
void scsi_sleep_done(struct semaphore *sem)
{
#if 0
if (sem != NULL) {
up(sem);
}
#endif
}
void scsi_sleep(int timeout)
{
#if 0
DECLARE_MUTEX_LOCKED(sem);
#endif
struct timer_list timer;
init_timer(&timer);
#if 0
timer.data = (unsigned long) &sem;
#else
timer.data = 0xDEADBEEF;
#endif
timer.expires = jiffies + timeout;
timer.function = (void (*)(unsigned long)) scsi_sleep_done;
@@ -567,7 +582,9 @@ void scsi_sleep(int timeout)
add_timer(&timer);
#if 0
down(&sem);
#endif
del_timer(&timer);
}
@@ -597,23 +614,29 @@ STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout)
SCpnt->owner = SCSI_OWNER_LOWLEVEL;
if (host->can_queue) {
#if 0
DECLARE_MUTEX_LOCKED(sem);
#endif
SCpnt->eh_state = SCSI_STATE_QUEUED;
scsi_add_timer(SCpnt, timeout, scsi_eh_times_out);
#if 0
/*
* Set up the semaphore so we wait for the command to complete.
*/
SCpnt->host->eh_action = &sem;
#endif
SCpnt->request.rq_status = RQ_SCSI_BUSY;
spin_lock_irqsave(&io_request_lock, flags);
host->hostt->queuecommand(SCpnt, scsi_eh_done);
spin_unlock_irqrestore(&io_request_lock, flags);
#if 0
down(&sem);
#endif
SCpnt->host->eh_action = NULL;
@@ -1246,8 +1269,9 @@ STATIC void scsi_restart_operations(struct Scsi_Host *host)
* block devices.
*/
SCSI_LOG_ERROR_RECOVERY(5, printk("scsi_error.c: Waking up host to restart\n"));
#if 0
wake_up(&host->host_wait);
#endif
/*
* Finally we need to re-initiate requests that may be pending. We will
@@ -1848,6 +1872,7 @@ void scsi_error_handler(void *data)
{
struct Scsi_Host *host = (struct Scsi_Host *) data;
int rtn;
#if 0
DECLARE_MUTEX_LOCKED(sem);
/*
@@ -1877,16 +1902,23 @@ void scsi_error_handler(void *data)
sprintf(current->comm, "scsi_eh_%d", host->host_no);
host->eh_wait = &sem;
#else
host->eh_wait = (void *)0xDEADBEEF;
#endif
host->ehandler = current;
#if 0
unlock_kernel();
#endif
/*
* Wake up the thread that created us.
*/
SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", host->eh_notify->count.counter));
#if 0
up(host->eh_notify);
#endif
while (1) {
/*
@@ -1896,6 +1928,7 @@ void scsi_error_handler(void *data)
*/
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler sleeping\n"));
#if 0
/*
* Note - we always use down_interruptible with the semaphore
* even if the module was loaded as part of the kernel. The
@@ -1906,6 +1939,7 @@ void scsi_error_handler(void *data)
* semaphores isn't unreasonable.
*/
down_interruptible(&sem);
#endif
if( host->loaded_as_module ) {
if (signal_pending(current))
break;
@@ -1956,6 +1990,7 @@ void scsi_error_handler(void *data)
host->eh_active = 0;
host->ehandler = NULL;
#if 0
/*
* If anyone is waiting for us to exit (i.e. someone trying to unload
* a driver), then wake up that process to let them know we are on
@@ -1966,6 +2001,7 @@ void scsi_error_handler(void *data)
*/
if (host->eh_notify != NULL)
up(host->eh_notify);
#endif
}
/*
+8 -8
View File
@@ -5,21 +5,21 @@
* for the ones that remain
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <xeno/module.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/string.h>
/* #include <linux/interrupt.h> */
/* #include <linux/errno.h> */
/* #include <linux/kernel.h> */
#include <xeno/sched.h>
/* #include <linux/mm.h> */
/* #include <linux/string.h> */
#include <linux/blk.h>
#include <xeno/blk.h>
#include "scsi.h"
#include "hosts.h"
#include <scsi/scsi_ioctl.h>
+167 -163
View File
@@ -18,25 +18,25 @@
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <xeno/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/blk.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <xeno/sched.h>
#include <xeno/timer.h>
/* #include <xeno/string.h> */
/* #include <xeno/slab.h> */
/* #include <xeno/ioport.h> */
/* #include <xeno/kernel.h> */
/* #include <xeno/stat.h> */
#include <xeno/blk.h>
/* #include <xeno/interrupt.h> */
/* #include <xeno/delay.h> */
/* #include <xeno/smp_lock.h> */
/* #include <xeno/completion.h> */
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
/* #include <xeno/unistd.h> */
#include <asm/system.h>
#include <asm/irq.h>
@@ -47,6 +47,8 @@
#include "constants.h"
#include <scsi/scsi_ioctl.h>
#define SPECIAL XEN_BLOCK_SPECIAL
/*
* This entire source file deals with the new queueing code.
*/
@@ -68,31 +70,31 @@
static void __scsi_insert_special(request_queue_t *q, struct request *rq,
void *data, int at_head)
{
unsigned long flags;
ASSERT_LOCK(&io_request_lock, 0);
rq->cmd = SPECIAL;
rq->special = data;
rq->q = NULL;
rq->nr_segments = 0;
rq->elevator_sequence = 0;
/*
* We have the option of inserting the head or the tail of the queue.
* Typically we use the tail for new ioctls and so forth. We use the
* head of the queue for things like a QUEUE_FULL message from a
* device, or a host that is unable to accept a particular command.
*/
spin_lock_irqsave(&io_request_lock, flags);
if (at_head)
list_add(&rq->queue, &q->queue_head);
else
list_add_tail(&rq->queue, &q->queue_head);
q->request_fn(q);
spin_unlock_irqrestore(&io_request_lock, flags);
unsigned long flags;
ASSERT_LOCK(&io_request_lock, 0);
rq->cmd = SPECIAL;
rq->special = data;
rq->q = NULL;
rq->nr_segments = 0;
rq->elevator_sequence = 0;
/*
* We have the option of inserting the head or the tail of the queue.
* Typically we use the tail for new ioctls and so forth. We use the
* head of the queue for things like a QUEUE_FULL message from a
* device, or a host that is unable to accept a particular command.
*/
spin_lock_irqsave(&io_request_lock, flags);
if (at_head)
list_add(&rq->queue, &q->queue_head);
else
list_add_tail(&rq->queue, &q->queue_head);
q->request_fn(q);
spin_unlock_irqrestore(&io_request_lock, flags);
}
@@ -118,10 +120,10 @@ static void __scsi_insert_special(request_queue_t *q, struct request *rq,
*/
int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head)
{
request_queue_t *q = &SCpnt->device->request_queue;
__scsi_insert_special(q, &SCpnt->request, SCpnt, at_head);
return 0;
request_queue_t *q = &SCpnt->device->request_queue;
__scsi_insert_special(q, &SCpnt->request, SCpnt, at_head);
return 0;
}
/*
@@ -146,10 +148,10 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head)
*/
int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head)
{
request_queue_t *q = &SRpnt->sr_device->request_queue;
__scsi_insert_special(q, &SRpnt->sr_request, SRpnt, at_head);
return 0;
request_queue_t *q = &SRpnt->sr_device->request_queue;
__scsi_insert_special(q, &SRpnt->sr_request, SRpnt, at_head);
return 0;
}
/*
@@ -167,44 +169,44 @@ int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head)
*/
int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
{
ASSERT_LOCK(&io_request_lock, 0);
ASSERT_LOCK(&io_request_lock, 0);
SCpnt->owner = SCSI_OWNER_MIDLEVEL;
SCpnt->reset_chain = NULL;
SCpnt->serial_number = 0;
SCpnt->serial_number_at_timeout = 0;
SCpnt->flags = 0;
SCpnt->retries = 0;
SCpnt->owner = SCSI_OWNER_MIDLEVEL;
SCpnt->reset_chain = NULL;
SCpnt->serial_number = 0;
SCpnt->serial_number_at_timeout = 0;
SCpnt->flags = 0;
SCpnt->retries = 0;
SCpnt->abort_reason = 0;
memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
if (SCpnt->cmd_len == 0)
SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
/*
* We need saved copies of a number of fields - this is because
* error handling may need to overwrite these with different values
* to run different commands, and once error handling is complete,
* we will need to restore these values prior to running the actual
* command.
*/
SCpnt->old_use_sg = SCpnt->use_sg;
SCpnt->old_cmd_len = SCpnt->cmd_len;
SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
SCpnt->old_underflow = SCpnt->underflow;
memcpy((void *) SCpnt->data_cmnd,
(const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd));
SCpnt->buffer = SCpnt->request_buffer;
SCpnt->bufflen = SCpnt->request_bufflen;
SCpnt->reset_chain = NULL;
SCpnt->internal_timeout = NORMAL_TIMEOUT;
SCpnt->abort_reason = 0;
SCpnt->abort_reason = 0;
memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
if (SCpnt->cmd_len == 0)
SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
/*
* We need saved copies of a number of fields - this is because
* error handling may need to overwrite these with different values
* to run different commands, and once error handling is complete,
* we will need to restore these values prior to running the actual
* command.
*/
SCpnt->old_use_sg = SCpnt->use_sg;
SCpnt->old_cmd_len = SCpnt->cmd_len;
SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
SCpnt->old_underflow = SCpnt->underflow;
memcpy((void *) SCpnt->data_cmnd,
(const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd));
SCpnt->buffer = SCpnt->request_buffer;
SCpnt->bufflen = SCpnt->request_bufflen;
SCpnt->reset_chain = NULL;
SCpnt->internal_timeout = NORMAL_TIMEOUT;
SCpnt->abort_reason = 0;
return 1;
return 1;
}
/*
@@ -245,90 +247,90 @@ int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
*/
void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
{
int all_clear;
unsigned long flags;
Scsi_Device *SDpnt;
struct Scsi_Host *SHpnt;
ASSERT_LOCK(&io_request_lock, 0);
spin_lock_irqsave(&io_request_lock, flags);
if (SCpnt != NULL) {
/*
* For some reason, we are not done with this request.
* This happens for I/O errors in the middle of the request,
* in which case we need to request the blocks that come after
* the bad sector.
*/
SCpnt->request.special = (void *) SCpnt;
list_add(&SCpnt->request.queue, &q->queue_head);
}
int all_clear;
unsigned long flags;
Scsi_Device *SDpnt;
struct Scsi_Host *SHpnt;
ASSERT_LOCK(&io_request_lock, 0);
spin_lock_irqsave(&io_request_lock, flags);
if (SCpnt != NULL) {
/*
* Just hit the requeue function for the queue.
* For some reason, we are not done with this request.
* This happens for I/O errors in the middle of the request,
* in which case we need to request the blocks that come after
* the bad sector.
*/
q->request_fn(q);
SDpnt = (Scsi_Device *) q->queuedata;
SHpnt = SDpnt->host;
/*
* If this is a single-lun device, and we are currently finished
* with this device, then see if we need to get another device
* started. FIXME(eric) - if this function gets too cluttered
* with special case code, then spin off separate versions and
* use function pointers to pick the right one.
*/
if (SDpnt->single_lun
&& list_empty(&q->queue_head)
&& SDpnt->device_busy == 0) {
request_queue_t *q;
for (SDpnt = SHpnt->host_queue;
SDpnt;
SDpnt = SDpnt->next) {
if (((SHpnt->can_queue > 0)
&& (SHpnt->host_busy >= SHpnt->can_queue))
|| (SHpnt->host_blocked)
|| (SHpnt->host_self_blocked)
|| (SDpnt->device_blocked)) {
break;
}
q = &SDpnt->request_queue;
q->request_fn(q);
}
SCpnt->request.special = (void *) SCpnt;
list_add(&SCpnt->request.queue, &q->queue_head);
}
/*
* Just hit the requeue function for the queue.
*/
q->request_fn(q);
SDpnt = (Scsi_Device *) q->queuedata;
SHpnt = SDpnt->host;
/*
* If this is a single-lun device, and we are currently finished
* with this device, then see if we need to get another device
* started. FIXME(eric) - if this function gets too cluttered
* with special case code, then spin off separate versions and
* use function pointers to pick the right one.
*/
if (SDpnt->single_lun
&& list_empty(&q->queue_head)
&& SDpnt->device_busy == 0) {
request_queue_t *q;
for (SDpnt = SHpnt->host_queue;
SDpnt;
SDpnt = SDpnt->next) {
if (((SHpnt->can_queue > 0)
&& (SHpnt->host_busy >= SHpnt->can_queue))
|| (SHpnt->host_blocked)
|| (SHpnt->host_self_blocked)
|| (SDpnt->device_blocked)) {
break;
}
q = &SDpnt->request_queue;
q->request_fn(q);
}
/*
* Now see whether there are other devices on the bus which
* might be starved. If so, hit the request function. If we
* don't find any, then it is safe to reset the flag. If we
* find any device that it is starved, it isn't safe to reset the
* flag as the queue function releases the lock and thus some
* other device might have become starved along the way.
*/
all_clear = 1;
if (SHpnt->some_device_starved) {
for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
request_queue_t *q;
if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
|| (SHpnt->host_blocked)
|| (SHpnt->host_self_blocked)) {
break;
}
if (SDpnt->device_blocked || !SDpnt->starved) {
continue;
}
q = &SDpnt->request_queue;
q->request_fn(q);
all_clear = 0;
}
if (SDpnt == NULL && all_clear) {
SHpnt->some_device_starved = 0;
}
}
/*
* Now see whether there are other devices on the bus which
* might be starved. If so, hit the request function. If we
* don't find any, then it is safe to reset the flag. If we
* find any device that it is starved, it isn't safe to reset the
* flag as the queue function releases the lock and thus some
* other device might have become starved along the way.
*/
all_clear = 1;
if (SHpnt->some_device_starved) {
for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
request_queue_t *q;
if ((SHpnt->can_queue > 0 &&(SHpnt->host_busy >= SHpnt->can_queue))
|| (SHpnt->host_blocked)
|| (SHpnt->host_self_blocked)) {
break;
}
if (SDpnt->device_blocked || !SDpnt->starved) {
continue;
}
q = &SDpnt->request_queue;
q->request_fn(q);
all_clear = 0;
}
spin_unlock_irqrestore(&io_request_lock, flags);
if (SDpnt == NULL && all_clear) {
SHpnt->some_device_starved = 0;
}
}
spin_unlock_irqrestore(&io_request_lock, flags);
}
/*
@@ -418,6 +420,7 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt,
scsi_queue_next_request(q, SCpnt);
return SCpnt;
}
#if 0
/*
* This request is done. If there is someone blocked waiting for this
* request, wake them up. Typically used to wake up processes trying
@@ -426,6 +429,7 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt,
if (req->waiting != NULL) {
complete(req->waiting);
}
#endif
req_finished_io(req);
add_blkdev_randomness(MAJOR(req->rq_dev));
+14 -14
View File
@@ -33,25 +33,25 @@
*/
#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
#include <xeno/config.h>
#include <xeno/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/blk.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/smp_lock.h>
#include <xeno/sched.h>
#include <xeno/timer.h>
/* #include <xeno/string.h> */
/* #include <xeno/slab.h> */
/* #include <xeno/ioport.h> */
/* #include <xeno/kernel.h> */
/* #include <xeno/stat.h> */
#include <xeno/blk.h>
/* #include <xeno/interrupt.h> */
/* #include <xeno/delay.h> */
/* #include <xeno/smp_lock.h> */
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
/* #include <xeno/unistd.h> */
#include <asm/system.h>
#include <asm/irq.h>
+71
View File
@@ -0,0 +1,71 @@
/*
* scsi_module.c Copyright (1994, 1995) Eric Youngdale.
*
* Support for loading low-level scsi drivers using the linux kernel loadable
* module interface.
*
* To use, the host adapter should first define and initialize the variable
* driver_template (datatype Scsi_Host_Template), and then include this file.
* This should also be wrapped in a #ifdef MODULE/#endif.
*
* The low -level driver must also define a release function which will
* free any irq assignments, release any dma channels, release any I/O
* address space that might be reserved, and otherwise clean up after itself.
* The idea is that the same driver should be able to be reloaded without
* any difficulty. This makes debugging new drivers easier, as you should
* be able to load the driver, test it, unload, modify and reload.
*
* One *very* important caveat. If the driver may need to do DMA on the
* ISA bus, you must have unchecked_isa_dma set in the device template,
* even if this might be changed during the detect routine. This is
* because the shpnt structure will be allocated in a special way so that
* it will be below the appropriate DMA limit - thus if your driver uses
* the hostdata field of shpnt, and the board must be able to access this
* via DMA, the shpnt structure must be in a DMA accessible region of
* memory. This comment would be relevant for something like the buslogic
* driver where there are many boards, only some of which do DMA onto the
* ISA bus. There is no convenient way of specifying whether the host
* needs to be in a ISA DMA accessible region of memory when you call
* scsi_register.
*/
#include <xeno/module.h>
#include <linux/init.h>
static int __init init_this_scsi_driver(void)
{
driver_template.module = THIS_MODULE;
scsi_register_module(MODULE_SCSI_HA, &driver_template);
if (driver_template.present)
return 0;
scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
return -ENODEV;
}
static void __exit exit_this_scsi_driver(void)
{
scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
}
module_init(init_this_scsi_driver);
module_exit(exit_this_scsi_driver);
/*
* Overrides for Emacs so that we almost follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
* indent-tabs-mode: nil
* tab-width: 8
* End:
*/
+9 -9
View File
@@ -16,17 +16,17 @@
* Michael A. Griffith <grif@acm.org>
*/
#include <linux/config.h> /* for CONFIG_PROC_FS */
#include <xeno/config.h> /* for CONFIG_PROC_FS */
#define __NO_VERSION__
#include <linux/module.h>
#include <xeno/module.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/blk.h>
/* #include <xeno/string.h> */
/* #include <xeno/mm.h> */
/* #include <xeno/slab.h> */
/* #include <xeno/proc_fs.h> */
/* #include <xeno/errno.h> */
/* #include <xeno/stat.h> */
#include <xeno/blk.h>
#include <asm/uaccess.h>
+13 -13
View File
@@ -11,23 +11,23 @@
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <xeno/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/blk.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/smp_lock.h>
#include <xeno/sched.h>
#include <xeno/timer.h>
/* #include <xeno/string.h> */
/* #include <xeno/slab.h> */
/* #include <xeno/ioport.h> */
/* #include <xeno/kernel.h> */
/* #include <xeno/stat.h> */
#include <xeno/blk.h>
/* #include <xeno/interrupt.h> */
/* #include <xeno/delay.h> */
/* #include <xeno/smp_lock.h> */
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
/*#include <xeno/unistd.h>*/
#include <asm/system.h>
#include <asm/irq.h>
+16 -4
View File
@@ -9,11 +9,11 @@
*/
#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <xeno/config.h>
#include <xeno/module.h>
#include <xeno/init.h>
#include <linux/blk.h>
#include <xeno/blk.h>
#include "scsi.h"
#include "hosts.h"
@@ -205,6 +205,7 @@ MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)"
static int __init scsi_luns_setup(char *str)
{
#if 0
unsigned int tmp;
if (get_option(&str, &tmp) == 1) {
@@ -215,6 +216,9 @@ static int __init scsi_luns_setup(char *str)
"(n should be between 1 and 2^32-1)\n");
return 0;
}
#else
return 0;
#endif
}
__setup("max_scsi_luns=", scsi_luns_setup);
@@ -343,10 +347,12 @@ void scan_scsis(struct Scsi_Host *shpnt,
initialize_merge_fn(SDpnt);
#if 0
/*
* Initialize the object that we will use to wait for command blocks.
*/
init_waitqueue_head(&SDpnt->scpnt_wait);
#endif
/*
* Next, hook the device to the host in question.
@@ -525,7 +531,9 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
Scsi_Device *SDtail, *SDpnt = *SDpnt2;
Scsi_Request * SRpnt;
int bflags, type = -1;
#ifdef DEVFS_MUST_DIE
extern devfs_handle_t scsi_devfs_handle;
#endif
int scsi_level;
SDpnt->host = shpnt;
@@ -686,8 +694,10 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
sprintf (devname, "host%d/bus%d/target%d/lun%d",
SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
#ifdef DEVFS_MUST_DIE
if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname);
else SDpnt->de = devfs_mk_dir (scsi_devfs_handle, devname, NULL);
#endif
for (sdtpnt = scsi_devicelist; sdtpnt;
sdtpnt = sdtpnt->next)
@@ -796,10 +806,12 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
*/
SDpnt->online = TRUE;
#if 0
/*
* Initialize the object that we will use to wait for command blocks.
*/
init_waitqueue_head(&SDpnt->scpnt_wait);
#endif
/*
* Since we just found one device, there had damn well better be one in the list
+10 -10
View File
@@ -3,17 +3,17 @@
* a module.
*/
#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
#include <xeno/config.h>
#include <xeno/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/blk.h>
#include <linux/fs.h>
#include <xeno/sched.h>
#include <xeno/timer.h>
/* #include <xeno/string.h> */
/* #include <xeno/slab.h> */
/* #include <xeno/ioport.h> */
/* #include <xeno/kernel.h> */
#include <xeno/blk.h>
/* #include <xeno/fs.h> */
#include <asm/system.h>
#include <asm/irq.h>
+16 -5
View File
@@ -11,12 +11,15 @@
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/kernel.h>
#include <linux/blk.h>
#include <xeno/config.h>
#include <xeno/module.h>
/*#include <linux/fs.h>*/
/*#include <linux/genhd.h>*/
#include <xeno/blk.h>
/*#include <linux/kernel.h>*/
#include <asm/unaligned.h>
#include "scsi.h"
#include "hosts.h"
@@ -47,13 +50,21 @@ int scsicam_bios_param(Disk * disk, /* SCSI disk */
int size = disk->capacity;
unsigned long temp_cyl;
#if 0
if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
return -1;
#else
bh = NULL;
printk("scsicam_bios_param: bread not avail!\n");
BUG();
#endif
/* try to infer mapping from partition table */
ret_code = scsi_partsize(bh, (unsigned long) size, (unsigned int *) ip + 2,
(unsigned int *) ip + 0, (unsigned int *) ip + 1);
#if 0
brelse(bh);
#endif
if (ret_code == -1) {
/* pick some standard mapping with at most 1024 cylinders,
+1053 -1003
View File
File diff suppressed because it is too large. Load diff
+301
View File
@@ -0,0 +1,301 @@
/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $
* linux/include/asm/dma.h: Defines for using and allocating dma channels.
* Written by Hennus Bergman, 1992.
* High DMA channel support & info by Hannu Savolainen
* and John Boyd, Nov. 1992.
*/
#ifndef _ASM_DMA_H
#define _ASM_DMA_H
#include <linux/config.h>
#include <linux/spinlock.h> /* And spinlocks */
#include <asm/io.h> /* need byte IO */
#include <linux/delay.h>
#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
#define dma_outb outb_p
#else
#define dma_outb outb
#endif
#define dma_inb inb
/*
* NOTES about DMA transfers:
*
* controller 1: channels 0-3, byte operations, ports 00-1F
* controller 2: channels 4-7, word operations, ports C0-DF
*
* - ALL registers are 8 bits only, regardless of transfer size
* - channel 4 is not used - cascades 1 into 2.
* - channels 0-3 are byte - addresses/counts are for physical bytes
* - channels 5-7 are word - addresses/counts are for physical words
* - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
* - transfer count loaded to registers is 1 less than actual count
* - controller 2 offsets are all even (2x offsets for controller 1)
* - page registers for 5-7 don't use data bit 0, represent 128K pages
* - page registers for 0-3 use bit 0, represent 64K pages
*
* DMA transfers are limited to the lower 16MB of _physical_ memory.
* Note that addresses loaded into registers must be _physical_ addresses,
* not logical addresses (which may differ if paging is active).
*
* Address mapping for channels 0-3:
*
* A23 ... A16 A15 ... A8 A7 ... A0 (Physical addresses)
* | ... | | ... | | ... |
* | ... | | ... | | ... |
* | ... | | ... | | ... |
* P7 ... P0 A7 ... A0 A7 ... A0
* | Page | Addr MSB | Addr LSB | (DMA registers)
*
* Address mapping for channels 5-7:
*
* A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0 (Physical addresses)
* | ... | \ \ ... \ \ \ ... \ \
* | ... | \ \ ... \ \ \ ... \ (not used)
* | ... | \ \ ... \ \ \ ... \
* P7 ... P1 (0) A7 A6 ... A0 A7 A6 ... A0
* | Page | Addr MSB | Addr LSB | (DMA registers)
*
* Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
* and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
* the hardware level, so odd-byte transfers aren't possible).
*
* Transfer count (_not # bytes_) is limited to 64K, represented as actual
* count - 1 : 64K => 0xFFFF, 1 => 0x0000. Thus, count is always 1 or more,
* and up to 128K bytes may be transferred on channels 5-7 in one operation.
*
*/
#define MAX_DMA_CHANNELS 8
#if 0
/* The maximum address that we can perform a DMA transfer to on this platform */
#define MAX_DMA_ADDRESS (PAGE_OFFSET+0x1000000)
#endif
/* 8237 DMA controllers */
#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
/* DMA controller registers */
#define DMA1_CMD_REG 0x08 /* command register (w) */
#define DMA1_STAT_REG 0x08 /* status register (r) */
#define DMA1_REQ_REG 0x09 /* request register (w) */
#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
#define DMA1_MODE_REG 0x0B /* mode register (w) */
#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */
#define DMA2_CMD_REG 0xD0 /* command register (w) */
#define DMA2_STAT_REG 0xD0 /* status register (r) */
#define DMA2_REQ_REG 0xD2 /* request register (w) */
#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
#define DMA2_MODE_REG 0xD6 /* mode register (w) */
#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
#define DMA_ADDR_0 0x00 /* DMA address registers */
#define DMA_ADDR_1 0x02
#define DMA_ADDR_2 0x04
#define DMA_ADDR_3 0x06
#define DMA_ADDR_4 0xC0
#define DMA_ADDR_5 0xC4
#define DMA_ADDR_6 0xC8
#define DMA_ADDR_7 0xCC
#define DMA_CNT_0 0x01 /* DMA count registers */
#define DMA_CNT_1 0x03
#define DMA_CNT_2 0x05
#define DMA_CNT_3 0x07
#define DMA_CNT_4 0xC2
#define DMA_CNT_5 0xC6
#define DMA_CNT_6 0xCA
#define DMA_CNT_7 0xCE
#define DMA_PAGE_0 0x87 /* DMA page registers */
#define DMA_PAGE_1 0x83
#define DMA_PAGE_2 0x81
#define DMA_PAGE_3 0x82
#define DMA_PAGE_5 0x8B
#define DMA_PAGE_6 0x89
#define DMA_PAGE_7 0x8A
#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */
#define DMA_AUTOINIT 0x10
extern spinlock_t dma_spin_lock;
static __inline__ unsigned long claim_dma_lock(void)
{
unsigned long flags;
spin_lock_irqsave(&dma_spin_lock, flags);
return flags;
}
static __inline__ void release_dma_lock(unsigned long flags)
{
spin_unlock_irqrestore(&dma_spin_lock, flags);
}
/* enable/disable a specific DMA channel */
static __inline__ void enable_dma(unsigned int dmanr)
{
if (dmanr<=3)
dma_outb(dmanr, DMA1_MASK_REG);
else
dma_outb(dmanr & 3, DMA2_MASK_REG);
}
static __inline__ void disable_dma(unsigned int dmanr)
{
if (dmanr<=3)
dma_outb(dmanr | 4, DMA1_MASK_REG);
else
dma_outb((dmanr & 3) | 4, DMA2_MASK_REG);
}
/* Clear the 'DMA Pointer Flip Flop'.
* Write 0 for LSB/MSB, 1 for MSB/LSB access.
* Use this once to initialize the FF to a known state.
* After that, keep track of it. :-)
* --- In order to do that, the DMA routines below should ---
* --- only be used while holding the DMA lock ! ---
*/
static __inline__ void clear_dma_ff(unsigned int dmanr)
{
if (dmanr<=3)
dma_outb(0, DMA1_CLEAR_FF_REG);
else
dma_outb(0, DMA2_CLEAR_FF_REG);
}
/* set mode (above) for a specific DMA channel */
static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
{
if (dmanr<=3)
dma_outb(mode | dmanr, DMA1_MODE_REG);
else
dma_outb(mode | (dmanr&3), DMA2_MODE_REG);
}
/* Set only the page register bits of the transfer address.
* This is used for successive transfers when we know the contents of
* the lower 16 bits of the DMA current address register, but a 64k boundary
* may have been crossed.
*/
static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
{
switch(dmanr) {
case 0:
dma_outb(pagenr, DMA_PAGE_0);
break;
case 1:
dma_outb(pagenr, DMA_PAGE_1);
break;
case 2:
dma_outb(pagenr, DMA_PAGE_2);
break;
case 3:
dma_outb(pagenr, DMA_PAGE_3);
break;
case 5:
dma_outb(pagenr & 0xfe, DMA_PAGE_5);
break;
case 6:
dma_outb(pagenr & 0xfe, DMA_PAGE_6);
break;
case 7:
dma_outb(pagenr & 0xfe, DMA_PAGE_7);
break;
}
}
/* Set transfer address & page bits for specific DMA channel.
* Assumes dma flipflop is clear.
*/
static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
{
set_dma_page(dmanr, a>>16);
if (dmanr <= 3) {
dma_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
dma_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
} else {
dma_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
dma_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
}
}
/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
* a specific DMA channel.
* You must ensure the parameters are valid.
* NOTE: from a manual: "the number of transfers is one more
* than the initial word count"! This is taken into account.
* Assumes dma flip-flop is clear.
* NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
*/
static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
{
count--;
if (dmanr <= 3) {
dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
} else {
dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
}
}
/* Get DMA residue count. After a DMA transfer, this
* should return zero. Reading this while a DMA transfer is
* still in progress will return unpredictable results.
* If called before the channel has been used, it may return 1.
* Otherwise, it returns the number of _bytes_ left to transfer.
*
* Assumes DMA flip-flop is clear.
*/
static __inline__ int get_dma_residue(unsigned int dmanr)
{
unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
: ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
/* using short to get 16-bit wrap around */
unsigned short count;
count = 1 + dma_inb(io_port);
count += dma_inb(io_port) << 8;
return (dmanr<=3)? count : (count<<1);
}
/* These are in kernel/dma.c: */
extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */
extern void free_dma(unsigned int dmanr); /* release it again */
/* From PCI */
#ifdef CONFIG_PCI
extern int isa_dma_bridge_buggy;
#else
#define isa_dma_bridge_buggy (0)
#endif
#endif /* _ASM_DMA_H */
+2 -1
View File
@@ -58,7 +58,8 @@ enum
HI_SOFTIRQ=0,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
TASKLET_SOFTIRQ
TASKLET_SOFTIRQ,
SCSI_LOW_SOFTIRQ,
};
/* softirq mask and active fields moved to irq_cpustat_t in
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.