/*+M*************************************************************************
* Adaptec AIC7xxx device driver for Linux.
*
* Copyright (c) 1994 John Aycock
* The University of Calgary Department of Computer Science.
*
* 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.
*
* Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F
* driver (ultrastor.c), various Linux kernel source, the Adaptec EISA
* config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide,
* the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux,
* the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file
* (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual,
* the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
* ANSI SCSI-2 specification (draft 10c), ...
*
* --------------------------------------------------------------------------
*
* Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
*
* Substantially modified to include support for wide and twin bus
* adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
* SCB paging, and other rework of the code.
*
* Parts of this driver were also based on the FreeBSD driver by
* Justin T. Gibbs. His copyright follows:
*
* --------------------------------------------------------------------------
* Copyright (c) 1994-1997 Justin Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Where this Software is combined with software released under the terms of
* the GNU General Public License ("GPL") and the terms of the GPL would require the
* combined work to also be released under the terms of the GPL, the terms
* and conditions of this License will apply in addition to those of the
* GPL with the exception of any terms or conditions of this License that
* conflict with, or are expressly prohibited by, the GPL.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $
*---------------------------------------------------------------------------
*
* Thanks also go to (in alphabetical order) the following:
*
* Rory Bolt - Sequencer bug fixes
* Jay Estabrook - Initial DEC Alpha support
* Doug Ledford - Much needed abort/reset bug fixes
* Kai Makisara - DMAing of SCBs
*
* A Boot time option was also added for not resetting the scsi bus.
*
* Form: aic7xxx=extended
* aic7xxx=no_reset
* aic7xxx=ultra
* aic7xxx=irq_trigger:[0,1] # 0 edge, 1 level
* aic7xxx=verbose
*
* Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
*
* $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
*-M*************************************************************************/
/*+M**************************************************************************
*
* Further driver modifications made by Doug Ledford <dledford@redhat.com>
*
* Copyright (c) 1997-1999 Doug Ledford
*
* These changes are released under the same licensing terms as the FreeBSD
* driver written by Justin Gibbs. Please see his Copyright notice above
* for the exact terms and conditions covering my changes as well as the
* warranty statement.
*
* Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
* but are not limited to:
*
* 1: Import of the latest FreeBSD sequencer code for this driver
* 2: Modification of kernel code to accommodate different sequencer semantics
* 3: Extensive changes throughout kernel portion of driver to improve
* abort/reset processing and error hanndling
* 4: Other work contributed by various people on the Internet
* 5: Changes to printk information and verbosity selection code
* 6: General reliability related changes, especially in IRQ management
* 7: Modifications to the default probe/attach order for supported cards
* 8: SMP friendliness has been improved
*
* Overall, this driver represents a significant departure from the official
* aic7xxx driver released by Dan Eischen in two ways. First, in the code
* itself. A diff between the two version of the driver is now a several
* thousand line diff. Second, in approach to solving the same problem. The
* problem is importing the FreeBSD aic7xxx driver code to linux can be a
* difficult and time consuming process, that also can be error prone. Dan
* Eischen's official driver uses the approach that the linux and FreeBSD
* drivers should be as identical as possible. To that end, his next version
* of this driver will be using a mid-layer code library that he is developing
* to moderate communications between the linux mid-level SCSI code and the
* low level FreeBSD driver. He intends to be able to essentially drop the
* FreeBSD driver into the linux kernel with only a few minor tweaks to some
* include files and the like and get things working, making for fast easy
* imports of the FreeBSD code into linux.
*
* I disagree with Dan's approach. Not that I don't think his way of doing
* things would be nice, easy to maintain, and create a more uniform driver
* between FreeBSD and Linux. I have no objection to those issues. My
* disagreement is on the needed functionality. There simply are certain
* things that are done differently in FreeBSD than linux that will cause
* problems for this driver regardless of any middle ware Dan implements.
* The biggest example of this at the moment is interrupt semantics. Linux
* doesn't provide the same protection techniques as FreeBSD does, nor can
* they be easily implemented in any middle ware code since they would truly
* belong in the kernel proper and would effect all drivers. For the time
* being, I see issues such as these as major stumbling blocks to the
* reliability of code based upon such middle ware. Therefore, I choose to
* use a different approach to importing the FreeBSD code that doesn't
* involve any middle ware type code. My approach is to import the sequencer
* code from FreeBSD wholesale. Then, to only make changes in the kernel
* portion of the driver as they are needed for the new sequencer semantics.
* In this way, the portion of the driver that speaks to the rest of the
* linux kernel is fairly static and can be changed/modified to solve
* any problems one might encounter without concern for the FreeBSD driver.
*
* Note: If time and experience should prove me wrong that the middle ware
* code Dan writes is reliable in its operation, then I'll retract my above
* statements. But, for those that don't know, I'm from Missouri (in the US)
* and our state motto is "The Show-Me State". Well, before I will put
* faith into it, you'll have to show me that it works :)
*
*_M*************************************************************************/
/*
* The next three defines are user configurable. These should be the only
* defines a user might need to get in here and change. There are other
* defines buried deeper in the code, but those really shouldn't need touched
* under normal conditions.
*/
/*
* AIC7XXX_STRICT_PCI_SETUP
* Should we assume the PCI config options on our controllers are set with
* sane and proper values, or should we be anal about our PCI config
* registers and force them to what we want? The main advantage to
* defining this option is on non-Intel hardware where the BIOS may not
* have been run to set things up, or if you have one of the BIOSless
* Adaptec controllers, such as a 2910, that don't get set up by the
* BIOS. However, keep in mind that we really do set the most important
* items in the driver regardless of this setting, this only controls some
* of the more esoteric PCI options on these cards. In that sense, I
* would default to leaving this off. However, if people wish to try
* things both ways, that would also help me to know if there are some
* machines where it works one way but not another.
*
* -- July 7, 17:09
* OK...I need this on my machine for testing, so the default is to
* leave it defined.
*
* -- July 7, 18:49
* I needed it for testing, but it didn't make any difference, so back
* off she goes.
*
* -- July 16, 23:04
* I turned it back on to try and compensate for the 2.1.x PCI code
* which no longer relies solely on the BIOS and now tries to set
* things itself.
*/
#define AIC7XXX_STRICT_PCI_SETUP
/*
* AIC7XXX_VERBOSE_DEBUGGING
* This option enables a lot of extra printk();s in the code, surrounded
* by if (aic7xxx_verbose ...) statements. Executing all of those if
* statements and the extra checks can get to where it actually does have
* an impact on CPU usage and such, as well as code size. Disabling this
* define will keep some of those from becoming part of the code.
*
* NOTE: Currently, this option has no real effect, I will be adding the
* various #ifdef's in the code later when I've decided a section is
* complete and no longer needs debugging. OK...a lot of things are now
* surrounded by this define, so turning this off does have an impact.
*/
/*
* #define AIC7XXX_VERBOSE_DEBUGGING
*/
#include <linux/module.h>
#include <stdarg.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
#include "aic7xxx_old/aic7xxx.h"
#include "aic7xxx_old/sequencer.h"
#include "aic7xxx_old/scsi_message.h"
#include "aic7xxx_old/aic7xxx_reg.h"
#include <scsi/scsicam.h>
#include <linux/stat.h>
#include <linux/slab.h> /* for kmalloc() */
#define AIC7XXX_C_VERSION "5.2.6"
#define ALL_TARGETS -1
#define ALL_CHANNELS -1
#define ALL_LUNS -1
#define MAX_TARGETS 16
#define MAX_LUNS 8
#ifndef TRUE
# define TRUE 1
#endif
#ifndef FALSE
# define FALSE 0
#endif
#if defined(__powerpc__) || defined(__i386__) || defined(__x86_64__)
# define MMAPIO
#endif
/*
* You can try raising me for better performance or lowering me if you have
* flaky devices that go off the scsi bus when hit with too many tagged
* commands (like some IBM SCSI-3 LVD drives).
*/
#define AIC7XXX_CMDS_PER_DEVICE 32
typedef struct
{
unsigned char tag_commands[16]; /* Allow for wide/twin adapters. */
} adapter_tag_info_t;
/*
* Make a define that will tell the driver not to the default tag depth
* everywhere.
*/
#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
0, 0, 0, 0, 0, 0, 0, 0}
/*
* Modify this as you see fit for your system. By setting tag_commands
* to 0, the driver will use it's own algorithm for determining the
* number of commands to use (see above). When 255, the driver will
* not enable tagged queueing for that particular device. When positive
* (> 0) and (< 255) the values in the array are used for the queue_depth.
* Note that the maximum value for an entry is 254, but you're insane if
* you try to use that many commands on one device.
*
* In this example, the first line will disable tagged queueing for all
* the devices on the first probed aic7xxx adapter.
*
* The second line enables tagged queueing with 4 commands/LUN for IDs
* (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
* driver to use its own algorithm for ID 1.
*
* The third line is the same as the first line.
*
* The fourth line disables tagged queueing for devices 0 and 3. It
* enables tagged queueing for the other IDs, with 16 commands/LUN
* for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
* IDs 2, 5-7, and 9-15.
*/
/*
* NOTE: The below structure is for reference only, the actual structure
* to modify in order to change things is found after this fake one.
*
adapter_tag_info_t aic7xxx_tag_info[] =
{
{DEFAULT_TAG_COMMANDS},
{{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}},
{DEFAULT_TAG_COMMANDS},
{{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
};
*/
static adapter_tag_info_t aic7xxx_tag_info[] =
{
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS},
{DEFAULT_TAG_COMMANDS}
};
/*
* Define an array of board names that can be indexed by aha_type.
* Don't forget to change this when changing the types!
*/
static const char *board_names[] = {
"AIC-7xxx Unknown", /* AIC_NONE */
"Adaptec AIC-7810 Hardware RAID Controller", /* AIC_7810 */
"Adaptec AIC-7770 SCSI host adapter", /* AIC_7770 */
"Adaptec AHA-274X SCSI host adapter", /* AIC_7771 */
"Adaptec AHA-284X SCSI host adapter", /* AIC_284x */
"Adaptec AIC-7850 SCSI host adapter", /* AIC_7850 */
"Adaptec AIC-7855 SCSI host adapter", /* AIC_7855 */
"Adaptec AIC-7860 Ultra SCSI host adapter", /* AIC_7860 */
"Adaptec AHA-2940A Ultra SCSI host adapter", /* AIC_7861 */
"Adaptec AIC-7870 SCSI host adapter", /* AIC_7870 */
"Adaptec AHA-294X SCSI host adapter", /* AIC_7871 */
"Adaptec AHA-394X SCSI host adapter", /* AIC_7872 */
"Adaptec AHA-398X SCSI host adapter", /* AIC_7873 */
"Adaptec AHA-2944 SCSI host adapter", /* AIC_7874 */
"Adaptec AIC-7880 Ultra SCSI host adapter", /* AIC_7880 */
"Adaptec AHA-294X Ultra SCSI host adapter", /* AIC_7881 */
"Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */
"Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */
"Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */
"Adaptec AHA-2940UW Pro Ultra SCSI host adapter", /* AIC_7887 */
"Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */
"Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */
"Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */
"Adaptec AHA-294X Ultra2 SCSI host adapter", /* AIC_7890 */
"Adaptec AIC-7896/7 Ultra2 SCSI host adapter", /* AIC_7896 */
"Adaptec AHA-394X Ultra2 SCSI host adapter", /* AIC_7897 */
"Adaptec AHA-395X Ultra2 SCSI host adapter", /* AIC_7897 */
"Adaptec PCMCIA SCSI controller", /* card bus stuff */
"Adaptec AIC-7892 Ultra 160/m SCSI host adapter", /* AIC_7892 */
"Adaptec AIC-7899 Ultra 160/m SCSI host adapter", /* AIC_7899 */
};
/*
* There should be a specific return value for this in scsi.h, but
* it seems that most drivers ignore it.
*/
#define DID_UNDERFLOW DID_ERROR
/*
* What we want to do is have the higher level scsi driver requeue
* the command to us. There is no specific driver status for this
* condition, but the higher level scsi driver will requeue the
* command on a DID_BUS_BUSY error.
*
* Upon further inspection and testing, it seems that DID_BUS_BUSY
* will *always* retry the command. We can get into an infinite loop
* if this happens when we really want some sort of counter that
* will automatically abort/reset the command after so many retries.
* Using DID_ERROR will do just that. (Made by a suggestion by
* Doug Ledford 8/1/96)
*/
#define DID_RETRY_COMMAND DID_ERROR
#define HSCSIID 0x07
#define SCSI_RESET 0x040
/*
* EISA/VL-bus stuff
*/
#define MINSLOT 1
#define MAXSLOT 15
#define SLOTBASE(x) ((x) << 12)
#define BASE_TO_SLOT(x) ((x) >> 12)
/*
* Standard EISA Host ID regs (Offset from slot base)
*/
#define AHC_HID0 0x80 /* 0,1: msb of ID2, 2-7: ID1 */
#define AHC_HID1 0x81 /* 0-4: ID3, 5-7: LSB ID2 */
#define AHC_HID2 0x82 /* product */
#define AHC_HID3 0x83 /* firmware revision */
/*
* AIC-7770 I/O range to reserve for a card
*/
#define MINREG 0xC00
#define MAXREG 0xCFF
#define INTDEF 0x5C /* Interrupt Definition Register */
/*
* AIC-78X0 PCI registers
*/
#define CLASS_PROGIF_REVID 0x08
#define DEVREVID 0x000000FFul
#define PROGINFC 0x0000FF00ul
#define SUBCLASS 0x00FF0000ul
#define BASECLASS 0xFF000000ul
#define CSIZE_LATTIME 0x0C
#define CACHESIZE 0x0000003Ful /* only 5 bits */
#define LATTIME 0x0000FF00ul
#define DEVCONFIG 0x40
#define SCBSIZE32 0x00010000ul /* aic789X only */
#define MPORTMODE 0x00000400ul /* aic7870 only */
#define RAMPSM 0x00000200ul /* aic7870 only */
#define RAMPSM_ULTRA2 0x00000004
#define VOLSENSE 0x00000100ul
#define SCBRAMSEL 0x00000080ul
#define SCBRAMSEL_ULTRA2 0x00000008
#define MRDCEN 0x00000040ul
#define EXTSCBTIME 0x00000020ul /* aic7870 only */
#define EXTSCBPEN 0x00000010ul /* aic7870 only */
#define BERREN 0x00000008ul
#define DACEN 0x00000004ul
#define STPWLEVEL 0x00000002ul
#define DIFACTNEGEN 0x00000001ul /* aic7870 only */
#define SCAMCTL 0x1a /* Ultra2 only */
#define CCSCBBADDR 0xf0 /* aic7895/6/7 */
/*
* Define the different types of SEEPROMs on aic7xxx adapters
* and make it also represent the address size used in accessing
* its registers. The 93C46 chips have 1024 bits organized into
* 64 16-bit words, while the 93C56 chips have 2048 bits organized
* into 128 16-bit words. The C46 chips use 6 bits to address
* each word, while the C56 and C66 (4096 bits) use 8 bits to
* address each word.
*/
typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type;
/*
*
* Define the format of the SEEPROM registers (16 bits).
*
*/
struct seeprom_config {
/*
* SCSI ID Configuration Flags
*/
#define CFXFER 0x0007 /* synchronous transfer rate */
#define CFSYNCH 0x0008 /* enable synchronous transfer */
#define CFDISC 0x0010 /* enable disconnection */
#define CFWIDEB 0x0020 /* wide bus device (wide card) */
#define CFSYNCHISULTRA 0x0040 /* CFSYNC is an ultra offset */
#define CFNEWULTRAFORMAT 0x0080 /* Use the Ultra2 SEEPROM format */
#define CFSTART 0x0100 /* send start unit SCSI command */
#define CFINCBIOS 0x0200 /* include in BIOS scan */
#define CFRNFOUND 0x0400 /* report even if not found */
#define CFMULTILUN 0x0800 /* probe mult luns in BIOS scan */
#define CFWBCACHEYES 0x4000 /* Enable W-Behind Cache on drive */
#define CFWBCACHENC 0xc000 /* Don't change W-Behind Cache */
/* UNUSED 0x3000 */
unsigned short device_flags[16]; /* words 0-15 */
/*
* BIOS Control Bits
*/
#define CFSUPREM 0x0001 /* support all removable drives */
#define CFSUPREMB 0x0002 /* support removable drives for boot only */
#define CFBIOSEN 0x0004 /* BIOS enabled */
/* UNUSED 0x0008 */
#define CFSM2DRV 0x0010 /* support more than two drives */
#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */
/* UNUSED 0x0040 */
#define CFEXTEND 0x0080 /* extended translation enabled */
/* UNUSED 0xFF00 */
unsigned short bios_control; /* word 16 */
/*
* Host Adapter Control Bits
*/
#define CFAUTOTERM 0x0001 /* Perform Auto termination */
#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */
#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */
#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */
#define CFSTERM 0x0004 /* SCSI low byte termination */
#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
#define CFSPARITY 0x0010 /* SCSI parity */
#define CF284XSTERM 0x0020 /* SCSI low byte termination (284x cards) */
#define CFRESETB 0x0040 /* reset SCSI bus at boot */
#define CFBPRIMARY 0x0100 /* Channel B primary on 7895 chipsets */
#define CFSEAUTOTERM 0x0400 /* aic7890 Perform SE Auto Term */
#define CFLVDSTERM 0x0800 /* aic7890 LVD Termination */
/* UNUSED 0xF280 */
unsigned short adapter_control; /* word 17 */
/*
* Bus Release, Host Adapter ID
*/
#define CFSCSIID 0x000F /* host adapter SCSI ID */
/* UNUSED 0x00F0 */
#define CFBRTIME 0xFF00 /* bus release time */
unsigned short brtime_id; /* word 18 */
/*
* Maximum targets
*/
#define CFMAXTARG 0x00FF /* maximum targets */
/* UNUSED 0xFF00 */
unsigned short max_targets; /* word 19 */
unsigned short res_1[11]; /* words 20-30 */
unsigned short checksum; /* word 31 */
};
#define SELBUS_MASK 0x0a
#define SELNARROW 0x00
#define SELBUSB 0x08
#define SINGLE_BUS 0x00
#define SCB_TARGET(scb) \
(((scb)->hscb->target_channel_lun & TID) >> 4)
#define SCB_LUN(scb) \
((scb)->hscb->target_channel_lun & LID)
#define SCB_IS_SCSIBUS_B(scb) \
(((scb)->hscb->target_channel_lun & SELBUSB) != 0)
/*
* If an error occurs during a data transfer phase, run the command
* to completion - it's easier that way - making a note of the error
* condition in this location. This then will modify a DID_OK status
* into an appropriate error for the higher-level SCSI code.
*/
#define aic7xxx_error(cmd) ((cmd)->SCp.Status)
/*
* Keep track of the targets returned status.
*/
#define aic7xxx_status(cmd) ((cmd)->SCp.sent_command)
/*
* The position of the SCSI commands scb within the scb array.
*/
#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in)
/*
* The stored DMA mapping for single-buffer data transfers.
*/
#define aic7xxx_mapping(cmd) ((cmd)->SCp.phase)
/*
|