mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
bitkeeper revision 1.85 (3e56416dqUx5ejRHgvOG3eSEByO2Fg)
Many files: new file Sync of SMH's new SCSI world with latest repository.
This commit is contained in:
1 parent
8b154fed7c
commit
566db2a08b
35 files changed
+10476
-1629
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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:
|
||||
*/
|
||||
@@ -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
|
||||
|
||||
+509
-355
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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 */
|
||||
@@ -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
|
||||
|
||||