[SCSI] aic94xx: new driver
James Bottomley [Tue, 29 Aug 2006 14:22:51 +0000 (09:22 -0500)]
This is the end point of the separate aic94xx driver based on the
original driver and transport class from Luben Tuikov
<ltuikov@yahoo.com>

The log of the separate development is:

Alexis Bruemmer:
  o aic94xx: fix hotplug/unplug for expanderless systems
  o aic94xx: disable split completion timer/setting by default
  o aic94xx: wide port off expander support
  o aic94xx: remove various inline functions
  o aic94xx: use bitops
  o aic94xx: remove queue comment
  o aic94xx: remove sas_common.c
  o aic94xx: sas remove depot's
  o aic94xx: use available list_for_each_entry_safe_reverse()
  o aic94xx: sas header file merge

James Bottomley:
  o aic94xx: fix TF_TMF_NO_CTX processing
  o aic94xx: convert to request_firmware interface
  o aic94xx: fix hotplug/unplug
  o aic94xx: add link error counts to the expander phys
  o aic94xx: add transport class phy reset capability
  o aic94xx: remove local_attached flag
  o Remove README
  o Fixup Makefile variable for libsas rename
  o Rename sas->libsas
  o aic94xx: correct return code for sas_discover_event
  o aic94xx: use parent backlink port
  o aic94xx: remove channel abstraction
  o aic94xx: fix routing algorithms
  o aic94xx: add backlink port
  o aic94xx: fix cascaded expander properties
  o aic94xx: fix sleep under lock
  o aic94xx: fix panic on module removal in complex topology
  o aic94xx: make use of the new sas_port
  o rename sas_port to asd_sas_port
  o Fix for eh_strategy_handler move
  o aic94xx: move entirely over to correct transport class formulation
  o remove last vestages of sas_rphy_alloc()
  o update for eh_timed_out move
  o Preliminary expander support for aic94xx
  o sas: remove event thread
  o minor warning cleanups
  o remove last vestiges of id mapping arrays
  o Further updates
  o Convert aic94xx over entirely to the transport class end device and
  o update aic94xx/sas to use the new sas transport class end device
  o [PATCH] aic94xx: attaching to the sas transport class
  o Add missing completion removal from prior patch
  o [PATCH] aic94xx: attaching to the sas transport class
  o Build fixes from akpm

Jeff Garzik:
  o [scsi aic94xx] Remove ->owner from PCI info table

Luben Tuikov:
  o initial aic94xx driver

Mike Anderson:
  o aic94xx: fix panic on module insertion
  o aic94xx: stub out SATA_DEV case
  o aic94xx: compile warning cleanups
  o aic94xx: sas_alloc_task
  o aic94xx: ref count update
  o aic94xx nexus loss time value
  o [PATCH] aic94xx: driver assertion in non-x86 BIOS env

Randy Dunlap:
  o libsas: externs not needed

Robert Tarte:
  o aic94xx: sequence patch - fixes SATA support

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

37 files changed:
Documentation/scsi/libsas.txt [new file with mode: 0644]
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/aic94xx/Kconfig [new file with mode: 0644]
drivers/scsi/aic94xx/Makefile [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx.h [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_dev.c [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_dump.c [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_dump.h [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_hwi.c [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_hwi.h [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_init.c [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_reg.c [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_reg.h [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_reg_def.h [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_sas.h [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_scb.c [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_sds.c [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_seq.c [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_seq.h [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_task.c [new file with mode: 0644]
drivers/scsi/aic94xx/aic94xx_tmf.c [new file with mode: 0644]
drivers/scsi/libsas/Kconfig [new file with mode: 0644]
drivers/scsi/libsas/Makefile [new file with mode: 0644]
drivers/scsi/libsas/sas_discover.c [new file with mode: 0644]
drivers/scsi/libsas/sas_dump.c [new file with mode: 0644]
drivers/scsi/libsas/sas_dump.h [new file with mode: 0644]
drivers/scsi/libsas/sas_event.c [new file with mode: 0644]
drivers/scsi/libsas/sas_expander.c [new file with mode: 0644]
drivers/scsi/libsas/sas_init.c [new file with mode: 0644]
drivers/scsi/libsas/sas_internal.h [new file with mode: 0644]
drivers/scsi/libsas/sas_phy.c [new file with mode: 0644]
drivers/scsi/libsas/sas_port.c [new file with mode: 0644]
drivers/scsi/libsas/sas_scsi_host.c [new file with mode: 0644]
include/scsi/libsas.h [new file with mode: 0644]
include/scsi/sas.h [new file with mode: 0644]
include/scsi/scsi.h

diff --git a/Documentation/scsi/libsas.txt b/Documentation/scsi/libsas.txt
new file mode 100644 (file)
index 0000000..9e2078b
--- /dev/null
@@ -0,0 +1,484 @@
+SAS Layer
+---------
+
+The SAS Layer is a management infrastructure which manages
+SAS LLDDs.  It sits between SCSI Core and SAS LLDDs.  The
+layout is as follows: while SCSI Core is concerned with
+SAM/SPC issues, and a SAS LLDD+sequencer is concerned with
+phy/OOB/link management, the SAS layer is concerned with:
+
+      * SAS Phy/Port/HA event management (LLDD generates,
+        SAS Layer processes),
+      * SAS Port management (creation/destruction),
+      * SAS Domain discovery and revalidation,
+      * SAS Domain device management,
+      * SCSI Host registration/unregistration,
+      * Device registration with SCSI Core (SAS) or libata
+        (SATA), and
+      * Expander management and exporting expander control
+        to user space.
+
+A SAS LLDD is a PCI device driver.  It is concerned with
+phy/OOB management, and vendor specific tasks and generates
+events to the SAS layer.
+
+The SAS Layer does most SAS tasks as outlined in the SAS 1.1
+spec.
+
+The sas_ha_struct describes the SAS LLDD to the SAS layer.
+Most of it is used by the SAS Layer but a few fields need to
+be initialized by the LLDDs.
+
+After initializing your hardware, from the probe() function
+you call sas_register_ha(). It will register your LLDD with
+the SCSI subsystem, creating a SCSI host and it will
+register your SAS driver with the sysfs SAS tree it creates.
+It will then return.  Then you enable your phys to actually
+start OOB (at which point your driver will start calling the
+notify_* event callbacks).
+
+Structure descriptions:
+
+struct sas_phy --------------------
+Normally this is statically embedded to your driver's
+phy structure:
+       struct my_phy {
+              blah;
+              struct sas_phy sas_phy;
+              bleh;
+       };
+And then all the phys are an array of my_phy in your HA
+struct (shown below).
+
+Then as you go along and initialize your phys you also
+initialize the sas_phy struct, along with your own
+phy structure.
+
+In general, the phys are managed by the LLDD and the ports
+are managed by the SAS layer.  So the phys are initialized
+and updated by the LLDD and the ports are initialized and
+updated by the SAS layer.
+
+There is a scheme where the LLDD can RW certain fields,
+and the SAS layer can only read such ones, and vice versa.
+The idea is to avoid unnecessary locking.
+
+enabled -- must be set (0/1)
+id -- must be set [0,MAX_PHYS)
+class, proto, type, role, oob_mode, linkrate -- must be set
+oob_mode --  you set this when OOB has finished and then notify
+the SAS Layer.
+
+sas_addr -- this normally points to an array holding the sas
+address of the phy, possibly somewhere in your my_phy
+struct.
+
+attached_sas_addr -- set this when you (LLDD) receive an
+IDENTIFY frame or a FIS frame, _before_ notifying the SAS
+layer.  The idea is that sometimes the LLDD may want to fake
+or provide a different SAS address on that phy/port and this
+allows it to do this.  At best you should copy the sas
+address from the IDENTIFY frame or maybe generate a SAS
+address for SATA directly attached devices.  The Discover
+process may later change this.
+
+frame_rcvd -- this is where you copy the IDENTIFY/FIS frame
+when you get it; you lock, copy, set frame_rcvd_size and
+unlock the lock, and then call the event.  It is a pointer
+since there's no way to know your hw frame size _exactly_,
+so you define the actual array in your phy struct and let
+this pointer point to it.  You copy the frame from your
+DMAable memory to that area holding the lock.
+
+sas_prim -- this is where primitives go when they're
+received.  See sas.h. Grab the lock, set the primitive,
+release the lock, notify.
+
+port -- this points to the sas_port if the phy belongs
+to a port -- the LLDD only reads this. It points to the
+sas_port this phy is part of.  Set by the SAS Layer.
+
+ha -- may be set; the SAS layer sets it anyway.
+
+lldd_phy -- you should set this to point to your phy so you
+can find your way around faster when the SAS layer calls one
+of your callbacks and passes you a phy.  If the sas_phy is
+embedded you can also use container_of -- whatever you
+prefer.
+
+
+struct sas_port --------------------
+The LLDD doesn't set any fields of this struct -- it only
+reads them.  They should be self explanatory.
+
+phy_mask is 32 bit, this should be enough for now, as I
+haven't heard of a HA having more than 8 phys.
+
+lldd_port -- I haven't found use for that -- maybe other
+LLDD who wish to have internal port representation can make
+use of this.
+
+
+struct sas_ha_struct --------------------
+It normally is statically declared in your own LLDD
+structure describing your adapter:
+struct my_sas_ha {
+       blah;
+       struct sas_ha_struct sas_ha;
+       struct my_phy phys[MAX_PHYS];
+       struct sas_port sas_ports[MAX_PHYS]; /* (1) */
+       bleh;
+};
+
+(1) If your LLDD doesn't have its own port representation.
+
+What needs to be initialized (sample function given below).
+
+pcidev
+sas_addr -- since the SAS layer doesn't want to mess with
+        memory allocation, etc, this points to statically
+        allocated array somewhere (say in your host adapter
+        structure) and holds the SAS address of the host
+        adapter as given by you or the manufacturer, etc.
+sas_port
+sas_phy -- an array of pointers to structures. (see
+       note above on sas_addr).
+       These must be set.  See more notes below.
+num_phys -- the number of phys present in the sas_phy array,
+        and the number of ports present in the sas_port
+        array.  There can be a maximum num_phys ports (one per
+        port) so we drop the num_ports, and only use
+        num_phys.
+
+The event interface:
+
+       /* LLDD calls these to notify the class of an event. */
+       void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
+       void (*notify_port_event)(struct sas_phy *, enum port_event);
+       void (*notify_phy_event)(struct sas_phy *, enum phy_event);
+
+When sas_register_ha() returns, those are set and can be
+called by the LLDD to notify the SAS layer of such events
+the SAS layer.
+
+The port notification:
+
+       /* The class calls these to notify the LLDD of an event. */
+       void (*lldd_port_formed)(struct sas_phy *);
+       void (*lldd_port_deformed)(struct sas_phy *);
+
+If the LLDD wants notification when a port has been formed
+or deformed it sets those to a function satisfying the type.
+
+A SAS LLDD should also implement at least one of the Task
+Management Functions (TMFs) described in SAM:
+
+       /* Task Management Functions. Must be called from process context. */
+       int (*lldd_abort_task)(struct sas_task *);
+       int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
+       int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
+       int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
+       int (*lldd_I_T_nexus_reset)(struct domain_device *);
+       int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
+       int (*lldd_query_task)(struct sas_task *);
+
+For more information please read SAM from T10.org.
+
+Port and Adapter management:
+
+       /* Port and Adapter management */
+       int (*lldd_clear_nexus_port)(struct sas_port *);
+       int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
+
+A SAS LLDD should implement at least one of those.
+
+Phy management:
+
+       /* Phy management */
+       int (*lldd_control_phy)(struct sas_phy *, enum phy_func);
+
+lldd_ha -- set this to point to your HA struct. You can also
+use container_of if you embedded it as shown above.
+
+A sample initialization and registration function
+can look like this (called last thing from probe())
+*but* before you enable the phys to do OOB:
+
+static int register_sas_ha(struct my_sas_ha *my_ha)
+{
+       int i;
+       static struct sas_phy   *sas_phys[MAX_PHYS];
+       static struct sas_port  *sas_ports[MAX_PHYS];
+
+       my_ha->sas_ha.sas_addr = &my_ha->sas_addr[0];
+
+       for (i = 0; i < MAX_PHYS; i++) {
+               sas_phys[i] = &my_ha->phys[i].sas_phy;
+               sas_ports[i] = &my_ha->sas_ports[i];
+       }
+
+       my_ha->sas_ha.sas_phy  = sas_phys;
+       my_ha->sas_ha.sas_port = sas_ports;
+       my_ha->sas_ha.num_phys = MAX_PHYS;
+
+       my_ha->sas_ha.lldd_port_formed = my_port_formed;
+
+       my_ha->sas_ha.lldd_dev_found = my_dev_found;
+       my_ha->sas_ha.lldd_dev_gone = my_dev_gone;
+
+       my_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; (1)
+
+       my_ha->sas_ha.lldd_queue_size = ha_can_queue;
+       my_ha->sas_ha.lldd_execute_task = my_execute_task;
+
+       my_ha->sas_ha.lldd_abort_task     = my_abort_task;
+       my_ha->sas_ha.lldd_abort_task_set = my_abort_task_set;
+       my_ha->sas_ha.lldd_clear_aca      = my_clear_aca;
+       my_ha->sas_ha.lldd_clear_task_set = my_clear_task_set;
+       my_ha->sas_ha.lldd_I_T_nexus_reset= NULL; (2)
+       my_ha->sas_ha.lldd_lu_reset       = my_lu_reset;
+       my_ha->sas_ha.lldd_query_task     = my_query_task;
+
+       my_ha->sas_ha.lldd_clear_nexus_port = my_clear_nexus_port;
+       my_ha->sas_ha.lldd_clear_nexus_ha = my_clear_nexus_ha;
+
+       my_ha->sas_ha.lldd_control_phy = my_control_phy;
+
+       return sas_register_ha(&my_ha->sas_ha);
+}
+
+(1) This is normally a LLDD parameter, something of the
+lines of a task collector.  What it tells the SAS Layer is
+whether the SAS layer should run in Direct Mode (default:
+value 0 or 1) or Task Collector Mode (value greater than 1).
+
+In Direct Mode, the SAS Layer calls Execute Task as soon as
+it has a command to send to the SDS, _and_ this is a single
+command, i.e. not linked.
+
+Some hardware (e.g. aic94xx) has the capability to DMA more
+than one task at a time (interrupt) from host memory.  Task
+Collector Mode is an optional feature for HAs which support
+this in their hardware.  (Again, it is completely optional
+even if your hardware supports it.)
+
+In Task Collector Mode, the SAS Layer would do _natural_
+coalescing of tasks and at the appropriate moment it would
+call your driver to DMA more than one task in a single HA
+interrupt. DMBS may want to use this by insmod/modprobe
+setting the lldd_max_execute_num to something greater than
+1.
+
+(2) SAS 1.1 does not define I_T Nexus Reset TMF.
+
+Events
+------
+
+Events are _the only way_ a SAS LLDD notifies the SAS layer
+of anything.  There is no other method or way a LLDD to tell
+the SAS layer of anything happening internally or in the SAS
+domain.
+
+Phy events:
+       PHYE_LOSS_OF_SIGNAL, (C)
+       PHYE_OOB_DONE,
+       PHYE_OOB_ERROR,      (C)
+       PHYE_SPINUP_HOLD.
+
+Port events, passed on a _phy_:
+       PORTE_BYTES_DMAED,      (M)
+       PORTE_BROADCAST_RCVD,   (E)
+       PORTE_LINK_RESET_ERR,   (C)
+       PORTE_TIMER_EVENT,      (C)
+       PORTE_HARD_RESET.
+
+Host Adapter event:
+       HAE_RESET
+
+A SAS LLDD should be able to generate
+       - at least one event from group C (choice),
+       - events marked M (mandatory) are mandatory (only one),
+       - events marked E (expander) if it wants the SAS layer
+         to handle domain revalidation (only one such).
+       - Unmarked events are optional.
+
+Meaning:
+
+HAE_RESET -- when your HA got internal error and was reset.
+
+PORTE_BYTES_DMAED -- on receiving an IDENTIFY/FIS frame
+PORTE_BROADCAST_RCVD -- on receiving a primitive
+PORTE_LINK_RESET_ERR -- timer expired, loss of signal, loss
+of DWS, etc. (*)
+PORTE_TIMER_EVENT -- DWS reset timeout timer expired (*)
+PORTE_HARD_RESET -- Hard Reset primitive received.
+
+PHYE_LOSS_OF_SIGNAL -- the device is gone (*)
+PHYE_OOB_DONE -- OOB went fine and oob_mode is valid
+PHYE_OOB_ERROR -- Error while doing OOB, the device probably
+got disconnected. (*)
+PHYE_SPINUP_HOLD -- SATA is present, COMWAKE not sent.
+
+(*) should set/clear the appropriate fields in the phy,
+    or alternatively call the inlined sas_phy_disconnected()
+    which is just a helper, from their tasklet.
+
+The Execute Command SCSI RPC:
+
+       int (*lldd_execute_task)(struct sas_task *, int num,
+                                unsigned long gfp_flags);
+
+Used to queue a task to the SAS LLDD.  @task is the tasks to
+be executed.  @num should be the number of tasks being
+queued at this function call (they are linked listed via
+task::list), @gfp_mask should be the gfp_mask defining the
+context of the caller.
+
+This function should implement the Execute Command SCSI RPC,
+or if you're sending a SCSI Task as linked commands, you
+should also use this function.
+
+That is, when lldd_execute_task() is called, the command(s)
+go out on the transport *immediately*.  There is *no*
+queuing of any sort and at any level in a SAS LLDD.
+
+The use of task::list is two-fold, one for linked commands,
+the other discussed below.
+
+It is possible to queue up more than one task at a time, by
+initializing the list element of struct sas_task, and
+passing the number of tasks enlisted in this manner in num.
+
+Returns: -SAS_QUEUE_FULL, -ENOMEM, nothing was queued;
+        0, the task(s) were queued.
+
+If you want to pass num > 1, then either
+A) you're the only caller of this function and keep track
+   of what you've queued to the LLDD, or
+B) you know what you're doing and have a strategy of
+   retrying.
+
+As opposed to queuing one task at a time (function call),
+batch queuing of tasks, by having num > 1, greatly
+simplifies LLDD code, sequencer code, and _hardware design_,
+and has some performance advantages in certain situations
+(DBMS).
+
+The LLDD advertises if it can take more than one command at
+a time at lldd_execute_task(), by setting the
+lldd_max_execute_num parameter (controlled by "collector"
+module parameter in aic94xx SAS LLDD).
+
+You should leave this to the default 1, unless you know what
+you're doing.
+
+This is a function of the LLDD, to which the SAS layer can
+cater to.
+
+int lldd_queue_size
+       The host adapter's queue size.  This is the maximum
+number of commands the lldd can have pending to domain
+devices on behalf of all upper layers submitting through
+lldd_execute_task().
+
+You really want to set this to something (much) larger than
+1.
+
+This _really_ has absolutely nothing to do with queuing.
+There is no queuing in SAS LLDDs.
+
+struct sas_task {
+       dev -- the device this task is destined to
+       list -- must be initialized (INIT_LIST_HEAD)
+       task_proto -- _one_ of enum sas_proto
+       scatter -- pointer to scatter gather list array
+       num_scatter -- number of elements in scatter
+       total_xfer_len -- total number of bytes expected to be transfered
+       data_dir -- PCI_DMA_...
+       task_done -- callback when the task has finished execution
+};
+
+When an external entity, entity other than the LLDD or the
+SAS Layer, wants to work with a struct domain_device, it
+_must_ call kobject_get() when getting a handle on the
+device and kobject_put() when it is done with the device.
+
+This does two things:
+     A) implements proper kfree() for the device;
+     B) increments/decrements the kref for all players:
+     domain_device
+       all domain_device's ... (if past an expander)
+           port
+               host adapter
+                    pci device
+                        and up the ladder, etc.
+
+DISCOVERY
+---------
+
+The sysfs tree has the following purposes:
+    a) It shows you the physical layout of the SAS domain at
+       the current time, i.e. how the domain looks in the
+       physical world right now.
+    b) Shows some device parameters _at_discovery_time_.
+
+This is a link to the tree(1) program, very useful in
+viewing the SAS domain:
+ftp://mama.indstate.edu/linux/tree/
+I expect user space applications to actually create a
+graphical interface of this.
+
+That is, the sysfs domain tree doesn't show or keep state if
+you e.g., change the meaning of the READY LED MEANING
+setting, but it does show you the current connection status
+of the domain device.
+
+Keeping internal device state changes is responsibility of
+upper layers (Command set drivers) and user space.
+
+When a device or devices are unplugged from the domain, this
+is reflected in the sysfs tree immediately, and the device(s)
+removed from the system.
+
+The structure domain_device describes any device in the SAS
+domain.  It is completely managed by the SAS layer.  A task
+points to a domain device, this is how the SAS LLDD knows
+where to send the task(s) to.  A SAS LLDD only reads the
+contents of the domain_device structure, but it never creates
+or destroys one.
+
+Expander management from User Space
+-----------------------------------
+
+In each expander directory in sysfs, there is a file called
+"smp_portal".  It is a binary sysfs attribute file, which
+implements an SMP portal (Note: this is *NOT* an SMP port),
+to which user space applications can send SMP requests and
+receive SMP responses.
+
+Functionality is deceptively simple:
+
+1. Build the SMP frame you want to send. The format and layout
+   is described in the SAS spec.  Leave the CRC field equal 0.
+open(2)
+2. Open the expander's SMP portal sysfs file in RW mode.
+write(2)
+3. Write the frame you built in 1.
+read(2)
+4. Read the amount of data you expect to receive for the frame you built.
+   If you receive different amount of data you expected to receive,
+   then there was some kind of error.
+close(2)
+All this process is shown in detail in the function do_smp_func()
+and its callers, in the file "expander_conf.c".
+
+The kernel functionality is implemented in the file
+"sas_expander.c".
+
+The program "expander_conf.c" implements this. It takes one
+argument, the sysfs file name of the SMP portal to the
+expander, and gives expander information, including routing
+tables.
+
+The SMP portal gives you complete control of the expander,
+so please be careful.
index d61662c..7de5fdf 100644 (file)
@@ -209,7 +209,7 @@ config SCSI_LOGGING
          there should be no noticeable performance impact as long as you have
          logging turned off.
 
-menu "SCSI Transport Attributes"
+menu "SCSI Transports"
        depends on SCSI
 
 config SCSI_SPI_ATTRS
@@ -242,6 +242,8 @@ config SCSI_SAS_ATTRS
          If you wish to export transport-specific information about
          each attached SAS device to sysfs, say Y.
 
+source "drivers/scsi/libsas/Kconfig"
+
 endmenu
 
 menu "SCSI low-level drivers"
@@ -431,6 +433,7 @@ config SCSI_AIC7XXX_OLD
          module will be called aic7xxx_old.
 
 source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
+source "drivers/scsi/aic94xx/Kconfig"
 
 # All the I2O code and drivers do not seem to be 64bit safe.
 config SCSI_DPT_I2O
index b2de9bf..83da70d 100644 (file)
@@ -32,6 +32,7 @@ obj-$(CONFIG_SCSI_SPI_ATTRS)  += scsi_transport_spi.o
 obj-$(CONFIG_SCSI_FC_ATTRS)    += scsi_transport_fc.o
 obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
 obj-$(CONFIG_SCSI_SAS_ATTRS)   += scsi_transport_sas.o
+obj-$(CONFIG_SCSI_SAS_LIBSAS)  += libsas/
 
 obj-$(CONFIG_ISCSI_TCP)        += libiscsi.o   iscsi_tcp.o
 obj-$(CONFIG_INFINIBAND_ISER)  += libiscsi.o
@@ -68,6 +69,7 @@ obj-$(CONFIG_SCSI_AIC7XXX)    += aic7xxx/
 obj-$(CONFIG_SCSI_AIC79XX)     += aic7xxx/
 obj-$(CONFIG_SCSI_AACRAID)     += aacraid/
 obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o
+obj-$(CONFIG_SCSI_AIC94XX)     += aic94xx/
 obj-$(CONFIG_SCSI_IPS)         += ips.o
 obj-$(CONFIG_SCSI_FD_MCS)      += fd_mcs.o
 obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig
new file mode 100644 (file)
index 0000000..0ed391d
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# Kernel configuration file for aic94xx SAS/SATA driver.
+#
+# Copyright (c) 2005 Adaptec, Inc.  All rights reserved.
+# Copyright (c) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# This file is part of the aic94xx driver.
+#
+# The aic94xx driver 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; version 2 of the
+# License.
+#
+# The aic94xx driver 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 Aic94xx Driver; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#
+
+config SCSI_AIC94XX
+       tristate "Adaptec AIC94xx SAS/SATA support"
+       depends on PCI
+       select SCSI_SAS_LIBSAS
+       help
+               This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X
+               AIC94xx chip based host adapters.
+
+config AIC94XX_DEBUG
+       bool "Compile in debug mode"
+       default y
+       depends on SCSI_AIC94XX
+       help
+               Compiles the aic94xx driver in debug mode.  In debug mode,
+               the driver prints some messages to the console.
diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile
new file mode 100644 (file)
index 0000000..e6b7012
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Makefile for Adaptec aic94xx SAS/SATA driver.
+#
+# Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# This file is part of the the aic94xx driver.
+#
+# The aic94xx driver 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; version 2 of the
+# License.
+#
+# The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+ifeq ($(CONFIG_AIC94XX_DEBUG),y)
+       EXTRA_CFLAGS += -DASD_DEBUG -DASD_ENTER_EXIT
+endif
+
+obj-$(CONFIG_SCSI_AIC94XX) += aic94xx.o
+aic94xx-y += aic94xx_init.o \
+            aic94xx_hwi.o  \
+            aic94xx_reg.o  \
+            aic94xx_sds.o  \
+            aic94xx_seq.o  \
+            aic94xx_dump.o \
+            aic94xx_scb.o  \
+            aic94xx_dev.o  \
+            aic94xx_tmf.o  \
+            aic94xx_task.o
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
new file mode 100644 (file)
index 0000000..cb7caf1
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Aic94xx SAS/SATA driver header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx.h#31 $
+ */
+
+#ifndef _AIC94XX_H_
+#define _AIC94XX_H_
+
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <scsi/libsas.h>
+
+#define ASD_DRIVER_NAME                "aic94xx"
+#define ASD_DRIVER_DESCRIPTION "Adaptec aic94xx SAS/SATA driver"
+
+#define asd_printk(fmt, ...)   printk(KERN_NOTICE ASD_DRIVER_NAME ": " fmt, ## __VA_ARGS__)
+
+#ifdef ASD_ENTER_EXIT
+#define ENTER  printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
+               __FUNCTION__)
+#define EXIT   printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
+               __FUNCTION__)
+#else
+#define ENTER
+#define EXIT
+#endif
+
+#ifdef ASD_DEBUG
+#define ASD_DPRINTK asd_printk
+#else
+#define ASD_DPRINTK(fmt, ...)
+#endif
+
+/* 2*ITNL timeout + 1 second */
+#define AIC94XX_SCB_TIMEOUT  (5*HZ)
+
+extern kmem_cache_t *asd_dma_token_cache;
+extern kmem_cache_t *asd_ascb_cache;
+extern char sas_addr_str[2*SAS_ADDR_SIZE + 1];
+
+static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr)
+{
+       int i;
+       for (i = 0; i < SAS_ADDR_SIZE; i++, p += 2)
+               snprintf(p, 3, "%02X", sas_addr[i]);
+       *p = '\0';
+}
+
+static inline void asd_destringify_sas_addr(u8 *sas_addr, const char *p)
+{
+       int i;
+       for (i = 0; i < SAS_ADDR_SIZE; i++) {
+               u8 h, l;
+               if (!*p)
+                       break;
+               h = isdigit(*p) ? *p-'0' : *p-'A'+10;
+               p++;
+               l = isdigit(*p) ? *p-'0' : *p-'A'+10;
+               p++;
+               sas_addr[i] = (h<<4) | l;
+       }
+}
+
+struct asd_ha_struct;
+struct asd_ascb;
+
+int  asd_read_ocm(struct asd_ha_struct *asd_ha);
+int  asd_read_flash(struct asd_ha_struct *asd_ha);
+
+int  asd_dev_found(struct domain_device *dev);
+void asd_dev_gone(struct domain_device *dev);
+
+void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id);
+
+int  asd_execute_task(struct sas_task *, int num, unsigned long gfp_flags);
+
+/* ---------- TMFs ---------- */
+int  asd_abort_task(struct sas_task *);
+int  asd_abort_task_set(struct domain_device *, u8 *lun);
+int  asd_clear_aca(struct domain_device *, u8 *lun);
+int  asd_clear_task_set(struct domain_device *, u8 *lun);
+int  asd_lu_reset(struct domain_device *, u8 *lun);
+int  asd_query_task(struct sas_task *);
+
+/* ---------- Adapter and Port management ---------- */
+int  asd_clear_nexus_port(struct asd_sas_port *port);
+int  asd_clear_nexus_ha(struct sas_ha_struct *sas_ha);
+
+/* ---------- Phy Management ---------- */
+int  asd_control_phy(struct asd_sas_phy *phy, enum phy_func func);
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
new file mode 100644 (file)
index 0000000..6f8901b
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Aic94xx SAS/SATA DDB management
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_dev.c#21 $
+ */
+
+#include "aic94xx.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_sas.h"
+
+#define FIND_FREE_DDB(_ha) find_first_zero_bit((_ha)->hw_prof.ddb_bitmap, \
+                                              (_ha)->hw_prof.max_ddbs)
+#define SET_DDB(_ddb, _ha) set_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
+#define CLEAR_DDB(_ddb, _ha) clear_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
+
+static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
+{
+       unsigned long flags;
+       int ddb, i;
+
+       spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
+       ddb = FIND_FREE_DDB(asd_ha);
+       if (ddb >= asd_ha->hw_prof.max_ddbs) {
+               ddb = -ENOMEM;
+               spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+               goto out;
+       }
+       SET_DDB(ddb, asd_ha);
+       spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+
+       for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
+               asd_ddbsite_write_dword(asd_ha, ddb, i, 0);
+out:
+       return ddb;
+}
+
+#define INIT_CONN_TAG   offsetof(struct asd_ddb_ssp_smp_target_port, init_conn_tag)
+#define DEST_SAS_ADDR   offsetof(struct asd_ddb_ssp_smp_target_port, dest_sas_addr)
+#define SEND_QUEUE_HEAD offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_head)
+#define DDB_TYPE        offsetof(struct asd_ddb_ssp_smp_target_port, ddb_type)
+#define CONN_MASK       offsetof(struct asd_ddb_ssp_smp_target_port, conn_mask)
+#define DDB_TARG_FLAGS  offsetof(struct asd_ddb_ssp_smp_target_port, flags)
+#define DDB_TARG_FLAGS2 offsetof(struct asd_ddb_stp_sata_target_port, flags2)
+#define EXEC_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, exec_queue_tail)
+#define SEND_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_tail)
+#define SISTER_DDB      offsetof(struct asd_ddb_ssp_smp_target_port, sister_ddb)
+#define MAX_CCONN       offsetof(struct asd_ddb_ssp_smp_target_port, max_concurrent_conn)
+#define NUM_CTX         offsetof(struct asd_ddb_ssp_smp_target_port, num_contexts)
+#define ATA_CMD_SCBPTR  offsetof(struct asd_ddb_stp_sata_target_port, ata_cmd_scbptr)
+#define SATA_TAG_ALLOC_MASK offsetof(struct asd_ddb_stp_sata_target_port, sata_tag_alloc_mask)
+#define NUM_SATA_TAGS   offsetof(struct asd_ddb_stp_sata_target_port, num_sata_tags)
+#define SATA_STATUS     offsetof(struct asd_ddb_stp_sata_target_port, sata_status)
+#define NCQ_DATA_SCB_PTR offsetof(struct asd_ddb_stp_sata_target_port, ncq_data_scb_ptr)
+#define ITNL_TIMEOUT    offsetof(struct asd_ddb_ssp_smp_target_port, itnl_timeout)
+
+static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb)
+{
+       unsigned long flags;
+
+       if (!ddb || ddb >= 0xFFFF)
+               return;
+       asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED);
+       spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
+       CLEAR_DDB(ddb, asd_ha);
+       spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+}
+
+static inline void asd_set_ddb_type(struct domain_device *dev)
+{
+       struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+       int ddb = (int) (unsigned long) dev->lldd_dev;
+
+       if (dev->dev_type == SATA_PM_PORT)
+               asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_PM_PORT);
+       else if (dev->tproto)
+               asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_TARGET);
+       else
+               asd_ddbsite_write_byte(asd_ha,ddb,DDB_TYPE,DDB_TYPE_INITIATOR);
+}
+
+static int asd_init_sata_tag_ddb(struct domain_device *dev)
+{
+       struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+       int ddb, i;
+
+       ddb = asd_get_ddb(asd_ha);
+       if (ddb < 0)
+               return ddb;
+
+       for (i = 0; i < sizeof(struct asd_ddb_sata_tag); i += 2)
+               asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
+
+       asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
+                              SISTER_DDB, ddb);
+       return 0;
+}
+
+static inline int asd_init_sata(struct domain_device *dev)
+{
+       struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+       int ddb = (int) (unsigned long) dev->lldd_dev;
+       u32 qdepth = 0;
+       int res = 0;
+
+       asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
+       if ((dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) &&
+           dev->sata_dev.identify_device &&
+           dev->sata_dev.identify_device[10] != 0) {
+               u16 w75 = le16_to_cpu(dev->sata_dev.identify_device[75]);
+               u16 w76 = le16_to_cpu(dev->sata_dev.identify_device[76]);
+
+               if (w76 & 0x100) /* NCQ? */
+                       qdepth = (w75 & 0x1F) + 1;
+               asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
+                                       (1<<qdepth)-1);
+               asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
+       }
+       if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
+           dev->dev_type == SATA_PM_PORT) {
+               struct dev_to_host_fis *fis = (struct dev_to_host_fis *)
+                       dev->frame_rcvd;
+               asd_ddbsite_write_byte(asd_ha, ddb, SATA_STATUS, fis->status);
+       }
+       asd_ddbsite_write_word(asd_ha, ddb, NCQ_DATA_SCB_PTR, 0xFFFF);
+       if (qdepth > 0)
+               res = asd_init_sata_tag_ddb(dev);
+       return res;
+}
+
+static int asd_init_target_ddb(struct domain_device *dev)
+{
+       int ddb, i;
+       struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+       u8 flags = 0;
+
+       ddb = asd_get_ddb(asd_ha);
+       if (ddb < 0)
+               return ddb;
+
+       dev->lldd_dev = (void *) (unsigned long) ddb;
+
+       asd_ddbsite_write_byte(asd_ha, ddb, 0, DDB_TP_CONN_TYPE);
+       asd_ddbsite_write_byte(asd_ha, ddb, 1, 0);
+       asd_ddbsite_write_word(asd_ha, ddb, INIT_CONN_TAG, 0xFFFF);
+       for (i = 0; i < SAS_ADDR_SIZE; i++)
+               asd_ddbsite_write_byte(asd_ha, ddb, DEST_SAS_ADDR+i,
+                                      dev->sas_addr[i]);
+       asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_HEAD, 0xFFFF);
+       asd_set_ddb_type(dev);
+       asd_ddbsite_write_byte(asd_ha, ddb, CONN_MASK, dev->port->phy_mask);
+       if (dev->port->oob_mode != SATA_OOB_MODE) {
+               flags |= OPEN_REQUIRED;
+               if ((dev->dev_type == SATA_DEV) ||
+                   (dev->tproto & SAS_PROTO_STP)) {
+                       struct smp_resp *rps_resp = &dev->sata_dev.rps_resp;
+                       if (rps_resp->frame_type == SMP_RESPONSE &&
+                           rps_resp->function == SMP_REPORT_PHY_SATA &&
+                           rps_resp->result == SMP_RESP_FUNC_ACC) {
+                               if (rps_resp->rps.affil_valid)
+                                       flags |= STP_AFFIL_POL;
+                               if (rps_resp->rps.affil_supp)
+                                       flags |= SUPPORTS_AFFIL;
+                       }
+               } else {
+                       flags |= CONCURRENT_CONN_SUPP;
+                       if (!dev->parent &&
+                           (dev->dev_type == EDGE_DEV ||
+                            dev->dev_type == FANOUT_DEV))
+                               asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
+                                                      4);
+                       else
+                               asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
+                                                      dev->pathways);
+                       asd_ddbsite_write_byte(asd_ha, ddb, NUM_CTX, 1);
+               }
+       }
+       if (dev->dev_type == SATA_PM)
+               flags |= SATA_MULTIPORT;
+       asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags);
+
+       flags = 0;
+       if (dev->tproto & SAS_PROTO_STP)
+               flags |= STP_CL_POL_NO_TX;
+       asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags);
+
+       asd_ddbsite_write_word(asd_ha, ddb, EXEC_QUEUE_TAIL, 0xFFFF);
+       asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF);
+       asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
+
+       if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) {
+               i = asd_init_sata(dev);
+               if (i < 0) {
+                       asd_free_ddb(asd_ha, ddb);
+                       return i;
+               }
+       }
+
+       if (dev->dev_type == SAS_END_DEV) {
+               struct sas_end_device *rdev = rphy_to_end_device(dev->rphy);
+               if (rdev->I_T_nexus_loss_timeout > 0)
+                       asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
+                                              min(rdev->I_T_nexus_loss_timeout,
+                                                  (u16)ITNL_TIMEOUT_CONST));
+               else
+                       asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
+                                              (u16)ITNL_TIMEOUT_CONST);
+       }
+       return 0;
+}
+
+static int asd_init_sata_pm_table_ddb(struct domain_device *dev)
+{
+       struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+       int ddb, i;
+
+       ddb = asd_get_ddb(asd_ha);
+       if (ddb < 0)
+               return ddb;
+
+       for (i = 0; i < 32; i += 2)
+               asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
+
+       asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
+                              SISTER_DDB, ddb);
+
+       return 0;
+}
+
+#define PM_PORT_FLAGS offsetof(struct asd_ddb_sata_pm_port, pm_port_flags)
+#define PARENT_DDB    offsetof(struct asd_ddb_sata_pm_port, parent_ddb)
+
+/**
+ * asd_init_sata_pm_port_ddb -- SATA Port Multiplier Port
+ * dev: pointer to domain device
+ *
+ * For SATA Port Multiplier Ports we need to allocate one SATA Port
+ * Multiplier Port DDB and depending on whether the target on it
+ * supports SATA II NCQ, one SATA Tag DDB.
+ */
+static int asd_init_sata_pm_port_ddb(struct domain_device *dev)
+{
+       int ddb, i, parent_ddb, pmtable_ddb;
+       struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+       u8  flags;
+
+       ddb = asd_get_ddb(asd_ha);
+       if (ddb < 0)
+               return ddb;
+
+       asd_set_ddb_type(dev);
+       flags = (dev->sata_dev.port_no << 4) | PM_PORT_SET;
+       asd_ddbsite_write_byte(asd_ha, ddb, PM_PORT_FLAGS, flags);
+       asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
+       asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
+       asd_init_sata(dev);
+
+       parent_ddb = (int) (unsigned long) dev->parent->lldd_dev;
+       asd_ddbsite_write_word(asd_ha, ddb, PARENT_DDB, parent_ddb);
+       pmtable_ddb = asd_ddbsite_read_word(asd_ha, parent_ddb, SISTER_DDB);
+       asd_ddbsite_write_word(asd_ha, pmtable_ddb, dev->sata_dev.port_no,ddb);
+
+       if (asd_ddbsite_read_byte(asd_ha, ddb, NUM_SATA_TAGS) > 0) {
+               i = asd_init_sata_tag_ddb(dev);
+               if (i < 0) {
+                       asd_free_ddb(asd_ha, ddb);
+                       return i;
+               }
+       }
+       return 0;
+}
+
+static int asd_init_initiator_ddb(struct domain_device *dev)
+{
+       return -ENODEV;
+}
+
+/**
+ * asd_init_sata_pm_ddb -- SATA Port Multiplier
+ * dev: pointer to domain device
+ *
+ * For STP and direct-attached SATA Port Multipliers we need
+ * one target port DDB entry and one SATA PM table DDB entry.
+ */
+static int asd_init_sata_pm_ddb(struct domain_device *dev)
+{
+       int res = 0;
+
+       res = asd_init_target_ddb(dev);
+       if (res)
+               goto out;
+       res = asd_init_sata_pm_table_ddb(dev);
+       if (res)
+               asd_free_ddb(dev->port->ha->lldd_ha,
+                            (int) (unsigned long) dev->lldd_dev);
+out:
+       return res;
+}
+
+int asd_dev_found(struct domain_device *dev)
+{
+       int res = 0;
+
+       switch (dev->dev_type) {
+       case SATA_PM:
+               res = asd_init_sata_pm_ddb(dev);
+               break;
+       case SATA_PM_PORT:
+               res = asd_init_sata_pm_port_ddb(dev);
+               break;
+       default:
+               if (dev->tproto)
+                       res = asd_init_target_ddb(dev);
+               else
+                       res = asd_init_initiator_ddb(dev);
+       }
+       return res;
+}
+
+void asd_dev_gone(struct domain_device *dev)
+{
+       int ddb, sister_ddb;
+       struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+
+       ddb = (int) (unsigned long) dev->lldd_dev;
+       sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB);
+
+       if (sister_ddb != 0xFFFF)
+               asd_free_ddb(asd_ha, sister_ddb);
+       asd_free_ddb(asd_ha, ddb);
+       dev->lldd_dev = NULL;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c
new file mode 100644 (file)
index 0000000..e6ade59
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+ * Aic94xx SAS/SATA driver dump interface.
+ *
+ * Copyright (C) 2004 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com>
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * 2005/07/14/LT  Complete overhaul of this file.  Update pages, register
+ * locations, names, etc.  Make use of macros.  Print more information.
+ * Print all cseq and lseq mip and mdp.
+ *
+ */
+
+#include "linux/pci.h"
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_reg_def.h"
+#include "aic94xx_sas.h"
+
+#include "aic94xx_dump.h"
+
+#ifdef ASD_DEBUG
+
+#define MD(x)      (1 << (x))
+#define MODE_COMMON (1 << 31)
+#define MODE_0_7    (0xFF)
+
+static const struct lseq_cio_regs {
+       char    *name;
+       u32     offs;
+       u8      width;
+       u32     mode;
+} LSEQmCIOREGS[] = {
+       {"LmMnSCBPTR",    0x20, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) },
+       {"LmMnDDBPTR",    0x22, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) },
+       {"LmREQMBX",      0x30, 32, MODE_COMMON },
+       {"LmRSPMBX",      0x34, 32, MODE_COMMON },
+       {"LmMnINT",       0x38, 32, MODE_0_7 },
+       {"LmMnINTEN",     0x3C, 32, MODE_0_7 },
+       {"LmXMTPRIMD",    0x40, 32, MODE_COMMON },
+       {"LmXMTPRIMCS",   0x44,  8, MODE_COMMON },
+       {"LmCONSTAT",     0x45,  8, MODE_COMMON },
+       {"LmMnDMAERRS",   0x46,  8, MD(0)|MD(1) },
+       {"LmMnSGDMAERRS", 0x47,  8, MD(0)|MD(1) },
+       {"LmMnEXPHDRP",   0x48,  8, MD(0) },
+       {"LmMnSASAALIGN", 0x48,  8, MD(1) },
+       {"LmMnMSKHDRP",   0x49,  8, MD(0) },
+       {"LmMnSTPALIGN",  0x49,  8, MD(1) },
+       {"LmMnRCVHDRP",   0x4A,  8, MD(0) },
+       {"LmMnXMTHDRP",   0x4A,  8, MD(1) },
+       {"LmALIGNMODE",   0x4B,  8, MD(1) },
+       {"LmMnEXPRCVCNT", 0x4C, 32, MD(0) },
+       {"LmMnXMTCNT",    0x4C, 32, MD(1) },
+       {"LmMnCURRTAG",   0x54, 16, MD(0) },
+       {"LmMnPREVTAG",   0x56, 16, MD(0) },
+       {"LmMnACKOFS",    0x58,  8, MD(1) },
+       {"LmMnXFRLVL",    0x59,  8, MD(0)|MD(1) },
+       {"LmMnSGDMACTL",  0x5A,  8, MD(0)|MD(1) },
+       {"LmMnSGDMASTAT", 0x5B,  8, MD(0)|MD(1) },
+       {"LmMnDDMACTL",   0x5C,  8, MD(0)|MD(1) },
+       {"LmMnDDMASTAT",  0x5D,  8, MD(0)|MD(1) },
+       {"LmMnDDMAMODE",  0x5E, 16, MD(0)|MD(1) },
+       {"LmMnPIPECTL",   0x61,  8, MD(0)|MD(1) },
+       {"LmMnACTSCB",    0x62, 16, MD(0)|MD(1) },
+       {"LmMnSGBHADR",   0x64,  8, MD(0)|MD(1) },
+       {"LmMnSGBADR",    0x65,  8, MD(0)|MD(1) },
+       {"LmMnSGDCNT",    0x66,  8, MD(0)|MD(1) },
+       {"LmMnSGDMADR",   0x68, 32, MD(0)|MD(1) },
+       {"LmMnSGDMADR",   0x6C, 32, MD(0)|MD(1) },
+       {"LmMnXFRCNT",    0x70, 32, MD(0)|MD(1) },
+       {"LmMnXMTCRC",    0x74, 32, MD(1) },
+       {"LmCURRTAG",     0x74, 16, MD(0) },
+       {"LmPREVTAG",     0x76, 16, MD(0) },
+       {"LmMnDPSEL",     0x7B,  8, MD(0)|MD(1) },
+       {"LmDPTHSTAT",    0x7C,  8, MODE_COMMON },
+       {"LmMnHOLDLVL",   0x7D,  8, MD(0) },
+       {"LmMnSATAFS",    0x7E,  8, MD(1) },
+       {"LmMnCMPLTSTAT", 0x7F,  8, MD(0)|MD(1) },
+       {"LmPRMSTAT0",    0x80, 32, MODE_COMMON },
+       {"LmPRMSTAT1",    0x84, 32, MODE_COMMON },
+       {"LmGPRMINT",     0x88,  8, MODE_COMMON },
+        {"LmMnCURRSCB",   0x8A, 16, MD(0) },
+       {"LmPRMICODE",    0x8C, 32, MODE_COMMON },
+       {"LmMnRCVCNT",    0x90, 16, MD(0) },
+       {"LmMnBUFSTAT",   0x92, 16, MD(0) },
+       {"LmMnXMTHDRSIZE",0x92,  8, MD(1) },
+       {"LmMnXMTSIZE",   0x93,  8, MD(1) },
+       {"LmMnTGTXFRCNT", 0x94, 32, MD(0) },
+       {"LmMnEXPROFS",   0x98, 32, MD(0) },
+       {"LmMnXMTROFS",   0x98, 32, MD(1) },
+       {"LmMnRCVROFS",   0x9C, 32, MD(0) },
+       {"LmCONCTL",      0xA0, 16, MODE_COMMON },
+       {"LmBITLTIMER",   0xA2, 16, MODE_COMMON },
+       {"LmWWNLOW",      0xA8, 32, MODE_COMMON },
+       {"LmWWNHIGH",     0xAC, 32, MODE_COMMON },
+       {"LmMnFRMERR",    0xB0, 32, MD(0) },
+       {"LmMnFRMERREN",  0xB4, 32, MD(0) },
+       {"LmAWTIMER",     0xB8, 16, MODE_COMMON },
+       {"LmAWTCTL",      0xBA,  8, MODE_COMMON },
+       {"LmMnHDRCMPS",   0xC0, 32, MD(0) },
+       {"LmMnXMTSTAT",   0xC4,  8, MD(1) },
+       {"LmHWTSTATEN",   0xC5,  8, MODE_COMMON },
+       {"LmMnRRDYRC",    0xC6,  8, MD(0) },
+        {"LmMnRRDYTC",    0xC6,  8, MD(1) },
+       {"LmHWTSTAT",     0xC7,  8, MODE_COMMON },
+       {"LmMnDATABUFADR",0xC8, 16, MD(0)|MD(1) },
+       {"LmDWSSTATUS",   0xCB,  8, MODE_COMMON },
+       {"LmMnACTSTAT",   0xCE, 16, MD(0)|MD(1) },
+       {"LmMnREQSCB",    0xD2, 16, MD(0)|MD(1) },
+       {"LmXXXPRIM",     0xD4, 32, MODE_COMMON },
+       {"LmRCVASTAT",    0xD9,  8, MODE_COMMON },
+       {"LmINTDIS1",     0xDA,  8, MODE_COMMON },
+       {"LmPSTORESEL",   0xDB,  8, MODE_COMMON },
+       {"LmPSTORE",      0xDC, 32, MODE_COMMON },
+       {"LmPRIMSTAT0EN", 0xE0, 32, MODE_COMMON },
+       {"LmPRIMSTAT1EN", 0xE4, 32, MODE_COMMON },
+       {"LmDONETCTL",    0xF2, 16, MODE_COMMON },
+       {NULL, 0, 0, 0 }
+};
+/*
+static struct lseq_cio_regs LSEQmOOBREGS[] = {
+   {"OOB_BFLTR"        ,0x100, 8, MD(5)},
+   {"OOB_INIT_MIN"     ,0x102,16, MD(5)},
+   {"OOB_INIT_MAX"     ,0x104,16, MD(5)},
+   {"OOB_INIT_NEG"     ,0x106,16, MD(5)},
+   {"OOB_SAS_MIN"      ,0x108,16, MD(5)},
+   {"OOB_SAS_MAX"      ,0x10A,16, MD(5)},
+   {"OOB_SAS_NEG"      ,0x10C,16, MD(5)},
+   {"OOB_WAKE_MIN"     ,0x10E,16, MD(5)},
+   {"OOB_WAKE_MAX"     ,0x110,16, MD(5)},
+   {"OOB_WAKE_NEG"     ,0x112,16, MD(5)},
+   {"OOB_IDLE_MAX"     ,0x114,16, MD(5)},
+   {"OOB_BURST_MAX"    ,0x116,16, MD(5)},
+   {"OOB_XMIT_BURST"   ,0x118, 8, MD(5)},
+   {"OOB_SEND_PAIRS"   ,0x119, 8, MD(5)},
+   {"OOB_INIT_IDLE"    ,0x11A, 8, MD(5)},
+   {"OOB_INIT_NEGO"    ,0x11C, 8, MD(5)},
+   {"OOB_SAS_IDLE"     ,0x11E, 8, MD(5)},
+   {"OOB_SAS_NEGO"     ,0x120, 8, MD(5)},
+   {"OOB_WAKE_IDLE"    ,0x122, 8, MD(5)},
+   {"OOB_WAKE_NEGO"    ,0x124, 8, MD(5)},
+   {"OOB_DATA_KBITS"   ,0x126, 8, MD(5)},
+   {"OOB_BURST_DATA"   ,0x128,32, MD(5)},
+   {"OOB_ALIGN_0_DATA" ,0x12C,32, MD(5)},
+   {"OOB_ALIGN_1_DATA" ,0x130,32, MD(5)},
+   {"OOB_SYNC_DATA"    ,0x134,32, MD(5)},
+   {"OOB_D10_2_DATA"   ,0x138,32, MD(5)},
+   {"OOB_PHY_RST_CNT"  ,0x13C,32, MD(5)},
+   {"OOB_SIG_GEN"      ,0x140, 8, MD(5)},
+   {"OOB_XMIT"         ,0x141, 8, MD(5)},
+   {"FUNCTION_MAKS"    ,0x142, 8, MD(5)},
+   {"OOB_MODE"         ,0x143, 8, MD(5)},
+   {"CURRENT_STATUS"   ,0x144, 8, MD(5)},
+   {"SPEED_MASK"       ,0x145, 8, MD(5)},
+   {"PRIM_COUNT"       ,0x146, 8, MD(5)},
+   {"OOB_SIGNALS"      ,0x148, 8, MD(5)},
+   {"OOB_DATA_DET"     ,0x149, 8, MD(5)},
+   {"OOB_TIME_OUT"     ,0x14C, 8, MD(5)},
+   {"OOB_TIMER_ENABLE" ,0x14D, 8, MD(5)},
+   {"OOB_STATUS"       ,0x14E, 8, MD(5)},
+   {"HOT_PLUG_DELAY"   ,0x150, 8, MD(5)},
+   {"RCD_DELAY"        ,0x151, 8, MD(5)},
+   {"COMSAS_TIMER"     ,0x152, 8, MD(5)},
+   {"SNTT_DELAY"       ,0x153, 8, MD(5)},
+   {"SPD_CHNG_DELAY"   ,0x154, 8, MD(5)},
+   {"SNLT_DELAY"       ,0x155, 8, MD(5)},
+   {"SNWT_DELAY"       ,0x156, 8, MD(5)},
+   {"ALIGN_DELAY"      ,0x157, 8, MD(5)},
+   {"INT_ENABLE_0"     ,0x158, 8, MD(5)},
+   {"INT_ENABLE_1"     ,0x159, 8, MD(5)},
+   {"INT_ENABLE_2"     ,0x15A, 8, MD(5)},
+   {"INT_ENABLE_3"     ,0x15B, 8, MD(5)},
+   {"OOB_TEST_REG"     ,0x15C, 8, MD(5)},
+   {"PHY_CONTROL_0"    ,0x160, 8, MD(5)},
+   {"PHY_CONTROL_1"    ,0x161, 8, MD(5)},
+   {"PHY_CONTROL_2"    ,0x162, 8, MD(5)},
+   {"PHY_CONTROL_3"    ,0x163, 8, MD(5)},
+   {"PHY_OOB_CAL_TX"   ,0x164, 8, MD(5)},
+   {"PHY_OOB_CAL_RX"   ,0x165, 8, MD(5)},
+   {"OOB_PHY_CAL_TX"   ,0x166, 8, MD(5)},
+   {"OOB_PHY_CAL_RX"   ,0x167, 8, MD(5)},
+   {"PHY_CONTROL_4"    ,0x168, 8, MD(5)},
+   {"PHY_TEST"         ,0x169, 8, MD(5)},
+   {"PHY_PWR_CTL"      ,0x16A, 8, MD(5)},
+   {"PHY_PWR_DELAY"    ,0x16B, 8, MD(5)},
+   {"OOB_SM_CON"       ,0x16C, 8, MD(5)},
+   {"ADDR_TRAP_1"      ,0x16D, 8, MD(5)},
+   {"ADDR_NEXT_1"      ,0x16E, 8, MD(5)},
+   {"NEXT_ST_1"        ,0x16F, 8, MD(5)},
+   {"OOB_SM_STATE"     ,0x170, 8, MD(5)},
+   {"ADDR_TRAP_2"      ,0x171, 8, MD(5)},
+   {"ADDR_NEXT_2"      ,0x172, 8, MD(5)},
+   {"NEXT_ST_2"        ,0x173, 8, MD(5)},
+   {NULL, 0, 0, 0 }
+};
+*/
+#define STR_8BIT   "   %30s[0x%04x]:0x%02x\n"
+#define STR_16BIT  "   %30s[0x%04x]:0x%04x\n"
+#define STR_32BIT  "   %30s[0x%04x]:0x%08x\n"
+#define STR_64BIT  "   %30s[0x%04x]:0x%llx\n"
+
+#define PRINT_REG_8bit(_ha, _n, _r) asd_printk(STR_8BIT, #_n, _n,      \
+                                            asd_read_reg_byte(_ha, _r))
+#define PRINT_REG_16bit(_ha, _n, _r) asd_printk(STR_16BIT, #_n, _n,     \
+                                             asd_read_reg_word(_ha, _r))
+#define PRINT_REG_32bit(_ha, _n, _r) asd_printk(STR_32BIT, #_n, _n,      \
+                                             asd_read_reg_dword(_ha, _r))
+
+#define PRINT_CREG_8bit(_ha, _n) asd_printk(STR_8BIT, #_n, _n,      \
+                                            asd_read_reg_byte(_ha, C##_n))
+#define PRINT_CREG_16bit(_ha, _n) asd_printk(STR_16BIT, #_n, _n,     \
+                                             asd_read_reg_word(_ha, C##_n))
+#define PRINT_CREG_32bit(_ha, _n) asd_printk(STR_32BIT, #_n, _n,      \
+                                             asd_read_reg_dword(_ha, C##_n))
+
+#define MSTR_8BIT   "   Mode:%02d %30s[0x%04x]:0x%02x\n"
+#define MSTR_16BIT  "   Mode:%02d %30s[0x%04x]:0x%04x\n"
+#define MSTR_32BIT  "   Mode:%02d %30s[0x%04x]:0x%08x\n"
+
+#define PRINT_MREG_8bit(_ha, _m, _n, _r) asd_printk(MSTR_8BIT, _m, #_n, _n,   \
+                                            asd_read_reg_byte(_ha, _r))
+#define PRINT_MREG_16bit(_ha, _m, _n, _r) asd_printk(MSTR_16BIT, _m, #_n, _n, \
+                                             asd_read_reg_word(_ha, _r))
+#define PRINT_MREG_32bit(_ha, _m, _n, _r) asd_printk(MSTR_32BIT, _m, #_n, _n, \
+                                             asd_read_reg_dword(_ha, _r))
+
+/* can also be used for MD when the register is mode aware already */
+#define PRINT_MIS_byte(_ha, _n) asd_printk(STR_8BIT, #_n,CSEQ_##_n-CMAPPEDSCR,\
+                                           asd_read_reg_byte(_ha, CSEQ_##_n))
+#define PRINT_MIS_word(_ha, _n) asd_printk(STR_16BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\
+                                           asd_read_reg_word(_ha, CSEQ_##_n))
+#define PRINT_MIS_dword(_ha, _n)                      \
+        asd_printk(STR_32BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\
+                   asd_read_reg_dword(_ha, CSEQ_##_n))
+#define PRINT_MIS_qword(_ha, _n)                                       \
+        asd_printk(STR_64BIT, #_n,CSEQ_##_n-CMAPPEDSCR,                \
+                   (unsigned long long)(((u64)asd_read_reg_dword(_ha, CSEQ_##_n))     \
+                 | (((u64)asd_read_reg_dword(_ha, (CSEQ_##_n)+4))<<32)))
+
+#define CMDP_REG(_n, _m) (_m*(CSEQ_PAGE_SIZE*2)+CSEQ_##_n)
+#define PRINT_CMDP_word(_ha, _n) \
+asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \
+       #_n, \
+       asd_read_reg_word(_ha, CMDP_REG(_n, 0)), \
+       asd_read_reg_word(_ha, CMDP_REG(_n, 1)), \
+       asd_read_reg_word(_ha, CMDP_REG(_n, 2)), \
+       asd_read_reg_word(_ha, CMDP_REG(_n, 3)), \
+       asd_read_reg_word(_ha, CMDP_REG(_n, 4)), \
+       asd_read_reg_word(_ha, CMDP_REG(_n, 5)), \
+       asd_read_reg_word(_ha, CMDP_REG(_n, 6)), \
+       asd_read_reg_word(_ha, CMDP_REG(_n, 7)))
+
+#define PRINT_CMDP_byte(_ha, _n) \
+asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \
+       #_n, \
+       asd_read_reg_byte(_ha, CMDP_REG(_n, 0)), \
+       asd_read_reg_byte(_ha, CMDP_REG(_n, 1)), \
+       asd_read_reg_byte(_ha, CMDP_REG(_n, 2)), \
+       asd_read_reg_byte(_ha, CMDP_REG(_n, 3)), \
+       asd_read_reg_byte(_ha, CMDP_REG(_n, 4)), \
+       asd_read_reg_byte(_ha, CMDP_REG(_n, 5)), \
+       asd_read_reg_byte(_ha, CMDP_REG(_n, 6)), \
+       asd_read_reg_byte(_ha, CMDP_REG(_n, 7)))
+
+static void asd_dump_cseq_state(struct asd_ha_struct *asd_ha)
+{
+       int mode;
+
+       asd_printk("CSEQ STATE\n");
+
+       asd_printk("ARP2 REGISTERS\n");
+
+       PRINT_CREG_32bit(asd_ha, ARP2CTL);
+       PRINT_CREG_32bit(asd_ha, ARP2INT);
+       PRINT_CREG_32bit(asd_ha, ARP2INTEN);
+       PRINT_CREG_8bit(asd_ha, MODEPTR);
+       PRINT_CREG_8bit(asd_ha, ALTMODE);
+       PRINT_CREG_8bit(asd_ha, FLAG);
+       PRINT_CREG_8bit(asd_ha, ARP2INTCTL);
+       PRINT_CREG_16bit(asd_ha, STACK);
+       PRINT_CREG_16bit(asd_ha, PRGMCNT);
+       PRINT_CREG_16bit(asd_ha, ACCUM);
+       PRINT_CREG_16bit(asd_ha, SINDEX);
+       PRINT_CREG_16bit(asd_ha, DINDEX);
+       PRINT_CREG_8bit(asd_ha, SINDIR);
+       PRINT_CREG_8bit(asd_ha, DINDIR);
+       PRINT_CREG_8bit(asd_ha, JUMLDIR);
+       PRINT_CREG_8bit(asd_ha, ARP2HALTCODE);
+       PRINT_CREG_16bit(asd_ha, CURRADDR);
+       PRINT_CREG_16bit(asd_ha, LASTADDR);
+       PRINT_CREG_16bit(asd_ha, NXTLADDR);
+
+       asd_printk("IOP REGISTERS\n");
+
+       PRINT_REG_32bit(asd_ha, BISTCTL1, CBISTCTL);
+       PRINT_CREG_32bit(asd_ha, MAPPEDSCR);
+
+       asd_printk("CIO REGISTERS\n");
+
+       for (mode = 0; mode < 9; mode++)
+               PRINT_MREG_16bit(asd_ha, mode, MnSCBPTR, CMnSCBPTR(mode));
+       PRINT_MREG_16bit(asd_ha, 15, MnSCBPTR, CMnSCBPTR(15));
+
+       for (mode = 0; mode < 9; mode++)
+               PRINT_MREG_16bit(asd_ha, mode, MnDDBPTR, CMnDDBPTR(mode));
+       PRINT_MREG_16bit(asd_ha, 15, MnDDBPTR, CMnDDBPTR(15));
+
+       for (mode = 0; mode < 8; mode++)
+               PRINT_MREG_32bit(asd_ha, mode, MnREQMBX, CMnREQMBX(mode));
+       for (mode = 0; mode < 8; mode++)
+               PRINT_MREG_32bit(asd_ha, mode, MnRSPMBX, CMnRSPMBX(mode));
+       for (mode = 0; mode < 8; mode++)
+               PRINT_MREG_32bit(asd_ha, mode, MnINT, CMnINT(mode));
+       for (mode = 0; mode < 8; mode++)
+               PRINT_MREG_32bit(asd_ha, mode, MnINTEN, CMnINTEN(mode));
+
+       PRINT_CREG_8bit(asd_ha, SCRATCHPAGE);
+       for (mode = 0; mode < 8; mode++)
+               PRINT_MREG_8bit(asd_ha, mode, MnSCRATCHPAGE,
+                               CMnSCRATCHPAGE(mode));
+
+       PRINT_REG_32bit(asd_ha, CLINKCON, CLINKCON);
+       PRINT_REG_8bit(asd_ha, CCONMSK, CCONMSK);
+       PRINT_REG_8bit(asd_ha, CCONEXIST, CCONEXIST);
+       PRINT_REG_16bit(asd_ha, CCONMODE, CCONMODE);
+       PRINT_REG_32bit(asd_ha, CTIMERCALC, CTIMERCALC);
+       PRINT_REG_8bit(asd_ha, CINTDIS, CINTDIS);
+
+       asd_printk("SCRATCH MEMORY\n");
+
+       asd_printk("MIP 4 >>>>>\n");
+       PRINT_MIS_word(asd_ha, Q_EXE_HEAD);
+       PRINT_MIS_word(asd_ha, Q_EXE_TAIL);
+       PRINT_MIS_word(asd_ha, Q_DONE_HEAD);
+       PRINT_MIS_word(asd_ha, Q_DONE_TAIL);
+       PRINT_MIS_word(asd_ha, Q_SEND_HEAD);
+       PRINT_MIS_word(asd_ha, Q_SEND_TAIL);
+       PRINT_MIS_word(asd_ha, Q_DMA2CHIM_HEAD);
+       PRINT_MIS_word(asd_ha, Q_DMA2CHIM_TAIL);
+       PRINT_MIS_word(asd_ha, Q_COPY_HEAD);
+       PRINT_MIS_word(asd_ha, Q_COPY_TAIL);
+       PRINT_MIS_word(asd_ha, REG0);
+       PRINT_MIS_word(asd_ha, REG1);
+       PRINT_MIS_dword(asd_ha, REG2);
+       PRINT_MIS_byte(asd_ha, LINK_CTL_Q_MAP);
+       PRINT_MIS_byte(asd_ha, MAX_CSEQ_MODE);
+       PRINT_MIS_byte(asd_ha, FREE_LIST_HACK_COUNT);
+
+       asd_printk("MIP 5 >>>>\n");
+       PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_QUEUE);
+       PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_COUNT);
+       PRINT_MIS_word(asd_ha, Q_EST_NEXUS_HEAD);
+       PRINT_MIS_word(asd_ha, Q_EST_NEXUS_TAIL);
+       PRINT_MIS_word(asd_ha, NEED_EST_NEXUS_SCB);
+       PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_HEAD);
+       PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_TAIL);
+       PRINT_MIS_byte(asd_ha, EST_NEXUS_SCB_OFFSET);
+
+       asd_printk("MIP 6 >>>>\n");
+       PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR0);
+       PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR1);
+       PRINT_MIS_word(asd_ha, INT_ROUT_SCBPTR);
+       PRINT_MIS_byte(asd_ha, INT_ROUT_MODE);
+       PRINT_MIS_byte(asd_ha, ISR_SCRATCH_FLAGS);
+       PRINT_MIS_word(asd_ha, ISR_SAVE_SINDEX);
+       PRINT_MIS_word(asd_ha, ISR_SAVE_DINDEX);
+       PRINT_MIS_word(asd_ha, Q_MONIRTT_HEAD);
+       PRINT_MIS_word(asd_ha, Q_MONIRTT_TAIL);
+       PRINT_MIS_byte(asd_ha, FREE_SCB_MASK);
+       PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_HEAD);
+       PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_TAIL);
+       PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_HEAD);
+       PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_TAIL);
+
+       asd_printk("MIP 7 >>>>\n");
+       PRINT_MIS_qword(asd_ha, EMPTY_REQ_QUEUE);
+       PRINT_MIS_qword(asd_ha, EMPTY_REQ_COUNT);
+       PRINT_MIS_word(asd_ha, Q_EMPTY_HEAD);
+       PRINT_MIS_word(asd_ha, Q_EMPTY_TAIL);
+       PRINT_MIS_word(asd_ha, NEED_EMPTY_SCB);
+       PRINT_MIS_byte(asd_ha, EMPTY_REQ_HEAD);
+       PRINT_MIS_byte(asd_ha, EMPTY_REQ_TAIL);
+       PRINT_MIS_byte(asd_ha, EMPTY_SCB_OFFSET);
+       PRINT_MIS_word(asd_ha, PRIMITIVE_DATA);
+       PRINT_MIS_dword(asd_ha, TIMEOUT_CONST);
+
+       asd_printk("MDP 0 >>>>\n");
+       asd_printk("%-20s %6s %6s %6s %6s %6s %6s %6s %6s\n",
+                  "Mode: ", "0", "1", "2", "3", "4", "5", "6", "7");
+       PRINT_CMDP_word(asd_ha, LRM_SAVE_SINDEX);
+       PRINT_CMDP_word(asd_ha, LRM_SAVE_SCBPTR);
+       PRINT_CMDP_word(asd_ha, Q_LINK_HEAD);
+       PRINT_CMDP_word(asd_ha, Q_LINK_TAIL);
+       PRINT_CMDP_byte(asd_ha, LRM_SAVE_SCRPAGE);
+
+       asd_printk("MDP 0 Mode 8 >>>>\n");
+       PRINT_MIS_word(asd_ha, RET_ADDR);
+       PRINT_MIS_word(asd_ha, RET_SCBPTR);
+       PRINT_MIS_word(asd_ha, SAVE_SCBPTR);
+       PRINT_MIS_word(asd_ha, EMPTY_TRANS_CTX);
+       PRINT_MIS_word(asd_ha, RESP_LEN);
+       PRINT_MIS_word(asd_ha, TMF_SCBPTR);
+       PRINT_MIS_word(asd_ha, GLOBAL_PREV_SCB);
+       PRINT_MIS_word(asd_ha, GLOBAL_HEAD);
+       PRINT_MIS_word(asd_ha, CLEAR_LU_HEAD);
+       PRINT_MIS_byte(asd_ha, TMF_OPCODE);
+       PRINT_MIS_byte(asd_ha, SCRATCH_FLAGS);
+       PRINT_MIS_word(asd_ha, HSB_SITE);
+       PRINT_MIS_word(asd_ha, FIRST_INV_SCB_SITE);
+       PRINT_MIS_word(asd_ha, FIRST_INV_DDB_SITE);
+
+       asd_printk("MDP 1 Mode 8 >>>>\n");
+       PRINT_MIS_qword(asd_ha, LUN_TO_CLEAR);
+       PRINT_MIS_qword(asd_ha, LUN_TO_CHECK);
+
+       asd_printk("MDP 2 Mode 8 >>>>\n");
+       PRINT_MIS_qword(asd_ha, HQ_NEW_POINTER);
+       PRINT_MIS_qword(asd_ha, HQ_DONE_BASE);
+       PRINT_MIS_dword(asd_ha, HQ_DONE_POINTER);
+       PRINT_MIS_byte(asd_ha, HQ_DONE_PASS);
+}
+
+#define PRINT_LREG_8bit(_h, _lseq, _n) \
+        asd_printk(STR_8BIT, #_n, _n, asd_read_reg_byte(_h, Lm##_n(_lseq)))
+#define PRINT_LREG_16bit(_h, _lseq, _n) \
+        asd_printk(STR_16BIT, #_n, _n, asd_read_reg_word(_h, Lm##_n(_lseq)))
+#define PRINT_LREG_32bit(_h, _lseq, _n) \
+        asd_printk(STR_32BIT, #_n, _n, asd_read_reg_dword(_h, Lm##_n(_lseq)))
+
+#define PRINT_LMIP_byte(_h, _lseq, _n)                              \
+       asd_printk(STR_8BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+                  asd_read_reg_byte(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_word(_h, _lseq, _n)                              \
+       asd_printk(STR_16BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+                  asd_read_reg_word(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_dword(_h, _lseq, _n)                             \
+       asd_printk(STR_32BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+                  asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_qword(_h, _lseq, _n)                                \
+       asd_printk(STR_64BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+                (unsigned long long)(((unsigned long long) \
+                asd_read_reg_dword(_h, LmSEQ_##_n(_lseq))) \
+                 | (((unsigned long long) \
+                asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)+4))<<32)))
+
+static void asd_print_lseq_cio_reg(struct asd_ha_struct *asd_ha,
+                                  u32 lseq_cio_addr, int i)
+{
+       switch (LSEQmCIOREGS[i].width) {
+       case 8:
+               asd_printk("%20s[0x%x]: 0x%02x\n", LSEQmCIOREGS[i].name,
+                          LSEQmCIOREGS[i].offs,
+                          asd_read_reg_byte(asd_ha, lseq_cio_addr +
+                                            LSEQmCIOREGS[i].offs));
+
+               break;
+       case 16:
+               asd_printk("%20s[0x%x]: 0x%04x\n", LSEQmCIOREGS[i].name,
+                          LSEQmCIOREGS[i].offs,
+                          asd_read_reg_word(asd_ha, lseq_cio_addr +
+                                            LSEQmCIOREGS[i].offs));
+
+               break;
+       case 32:
+               asd_printk("%20s[0x%x]: 0x%08x\n", LSEQmCIOREGS[i].name,
+                          LSEQmCIOREGS[i].offs,
+                          asd_read_reg_dword(asd_ha, lseq_cio_addr +
+                                             LSEQmCIOREGS[i].offs));
+               break;
+       }
+}
+
+static void asd_dump_lseq_state(struct asd_ha_struct *asd_ha, int lseq)
+{
+       u32 moffs;
+       int mode;
+
+       asd_printk("LSEQ %d STATE\n", lseq);
+
+       asd_printk("LSEQ%d: ARP2 REGISTERS\n", lseq);
+       PRINT_LREG_32bit(asd_ha, lseq, ARP2CTL);
+       PRINT_LREG_32bit(asd_ha, lseq, ARP2INT);
+       PRINT_LREG_32bit(asd_ha, lseq, ARP2INTEN);
+       PRINT_LREG_8bit(asd_ha, lseq, MODEPTR);
+       PRINT_LREG_8bit(asd_ha, lseq, ALTMODE);
+       PRINT_LREG_8bit(asd_ha, lseq, FLAG);
+       PRINT_LREG_8bit(asd_ha, lseq, ARP2INTCTL);
+       PRINT_LREG_16bit(asd_ha, lseq, STACK);
+       PRINT_LREG_16bit(asd_ha, lseq, PRGMCNT);
+       PRINT_LREG_16bit(asd_ha, lseq, ACCUM);
+       PRINT_LREG_16bit(asd_ha, lseq, SINDEX);
+       PRINT_LREG_16bit(asd_ha, lseq, DINDEX);
+       PRINT_LREG_8bit(asd_ha, lseq, SINDIR);
+       PRINT_LREG_8bit(asd_ha, lseq, DINDIR);
+       PRINT_LREG_8bit(asd_ha, lseq, JUMLDIR);
+       PRINT_LREG_8bit(asd_ha, lseq, ARP2HALTCODE);
+       PRINT_LREG_16bit(asd_ha, lseq, CURRADDR);
+       PRINT_LREG_16bit(asd_ha, lseq, LASTADDR);
+       PRINT_LREG_16bit(asd_ha, lseq, NXTLADDR);
+
+       asd_printk("LSEQ%d: IOP REGISTERS\n", lseq);
+
+       PRINT_LREG_32bit(asd_ha, lseq, MODECTL);
+       PRINT_LREG_32bit(asd_ha, lseq, DBGMODE);
+       PRINT_LREG_32bit(asd_ha, lseq, CONTROL);
+       PRINT_REG_32bit(asd_ha, BISTCTL0, LmBISTCTL0(lseq));
+       PRINT_REG_32bit(asd_ha, BISTCTL1, LmBISTCTL1(lseq));
+
+       asd_printk("LSEQ%d: CIO REGISTERS\n", lseq);
+       asd_printk("Mode common:\n");
+
+       for (mode = 0; mode < 8; mode++) {
+               u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq);
+               int i;
+
+               for (i = 0; LSEQmCIOREGS[i].name; i++)
+                       if (LSEQmCIOREGS[i].mode == MODE_COMMON)
+                               asd_print_lseq_cio_reg(asd_ha,lseq_cio_addr,i);
+       }
+
+       asd_printk("Mode unique:\n");
+       for (mode = 0; mode < 8; mode++) {
+               u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq);
+               int i;
+
+               asd_printk("Mode %d\n", mode);
+               for  (i = 0; LSEQmCIOREGS[i].name; i++) {
+                       if (!(LSEQmCIOREGS[i].mode & (1 << mode)))
+                               continue;
+                       asd_print_lseq_cio_reg(asd_ha, lseq_cio_addr, i);
+               }
+       }
+
+       asd_printk("SCRATCH MEMORY\n");
+
+       asd_printk("LSEQ%d MIP 0 >>>>\n", lseq);
+       PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_HEAD);
+       PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL);
+       PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER);
+       PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS);
+       PRINT_LMIP_qword(asd_ha, lseq, CONNECTION_STATE);
+       PRINT_LMIP_word(asd_ha, lseq, CONCTL);
+       PRINT_LMIP_byte(asd_ha, lseq, CONSTAT);
+       PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES);
+       PRINT_LMIP_word(asd_ha, lseq, REG1_ISR);
+       PRINT_LMIP_word(asd_ha, lseq, REG2_ISR);
+       PRINT_LMIP_word(asd_ha, lseq, REG3_ISR);
+       PRINT_LMIP_qword(asd_ha, lseq,REG0_ISR);
+
+       asd_printk("LSEQ%d MIP 1 >>>>\n", lseq);
+       PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR0);
+       PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR1);
+       PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR2);
+       PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR3);
+       PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE0);
+       PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE1);
+       PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE2);
+       PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE3);
+       PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_HEAD);
+       PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_TAIL);
+       PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_BUF_AVAIL);
+       PRINT_LMIP_dword(asd_ha, lseq, TIMEOUT_CONST);
+       PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_SINDEX);
+       PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_DINDEX);
+
+       asd_printk("LSEQ%d MIP 2 >>>>\n", lseq);
+       PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR0);
+       PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR1);
+       PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR2);
+       PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR3);
+       PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD0);
+       PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD1);
+       PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD2);
+       PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD3);
+       PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_HEAD);
+       PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_TAIL);
+       PRINT_LMIP_byte(asd_ha, lseq, EMPTY_BUFS_AVAIL);
+
+       asd_printk("LSEQ%d MIP 3 >>>>\n", lseq);
+       PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TMR_TOUT_CONST);
+       PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMEOUT);
+       PRINT_LMIP_dword(asd_ha, lseq, SRST_ASSERT_TIMEOUT);
+       PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMEOUT);
+       PRINT_LMIP_dword(asd_ha, lseq, ONE_MILLISEC_TIMEOUT);
+       PRINT_LMIP_dword(asd_ha, lseq, TEN_MS_COMINIT_TIMEOUT);
+       PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMEOUT);
+
+       for (mode = 0; mode < 3; mode++) {
+               asd_printk("LSEQ%d MDP 0 MODE %d >>>>\n", lseq, mode);
+               moffs = mode * LSEQ_MODE_SCRATCH_SIZE;
+
+               asd_printk(STR_16BIT, "RET_ADDR", 0,
+                          asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)
+                                            + moffs));
+               asd_printk(STR_16BIT, "REG0_MODE", 2,
+                          asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)
+                                            + moffs));
+               asd_printk(STR_16BIT, "MODE_FLAGS", 4,
+                          asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)
+                                            + moffs));
+               asd_printk(STR_16BIT, "RET_ADDR2", 0x6,
+                          asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)
+                                            + moffs));
+               asd_printk(STR_16BIT, "RET_ADDR1", 0x8,
+                          asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)
+                                            + moffs));
+               asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB,
+                          asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)
+                                            + moffs));
+               asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC,
+                          asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)
+                                            + moffs));
+       }
+
+       asd_printk("LSEQ%d MDP 0 MODE 5 >>>>\n", lseq);
+       moffs = LSEQ_MODE5_PAGE0_OFFSET;
+       asd_printk(STR_16BIT, "RET_ADDR", 0,
+                  asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq) + moffs));
+       asd_printk(STR_16BIT, "REG0_MODE", 2,
+                  asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq) + moffs));
+       asd_printk(STR_16BIT, "MODE_FLAGS", 4,
+                  asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq) + moffs));
+       asd_printk(STR_16BIT, "RET_ADDR2", 0x6,
+                  asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq) + moffs));
+       asd_printk(STR_16BIT, "RET_ADDR1", 0x8,
+                  asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq) + moffs));
+       asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB,
+          asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq) + moffs));
+       asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC,
+          asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq) + moffs));
+
+       asd_printk("LSEQ%d MDP 0 MODE 0 >>>>\n", lseq);
+       PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_DDB_SITE);
+       PRINT_LMIP_word(asd_ha, lseq, EMPTY_TRANS_CTX);
+       PRINT_LMIP_word(asd_ha, lseq, RESP_LEN);
+       PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_SCB_SITE);
+       PRINT_LMIP_dword(asd_ha, lseq, INTEN_SAVE);
+       PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_FRM_LEN);
+       PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_PROTOCOL);
+       PRINT_LMIP_byte(asd_ha, lseq, RESP_STATUS);
+       PRINT_LMIP_byte(asd_ha, lseq, LAST_LOADED_SGE);
+       PRINT_LMIP_byte(asd_ha, lseq, SAVE_SCBPTR);
+
+       asd_printk("LSEQ%d MDP 0 MODE 1 >>>>\n", lseq);
+       PRINT_LMIP_word(asd_ha, lseq, Q_XMIT_HEAD);
+       PRINT_LMIP_word(asd_ha, lseq, M1_EMPTY_TRANS_CTX);
+       PRINT_LMIP_word(asd_ha, lseq, INI_CONN_TAG);
+       PRINT_LMIP_byte(asd_ha, lseq, FAILED_OPEN_STATUS);
+       PRINT_LMIP_byte(asd_ha, lseq, XMIT_REQUEST_TYPE);
+       PRINT_LMIP_byte(asd_ha, lseq, M1_RESP_STATUS);
+       PRINT_LMIP_byte(asd_ha, lseq, M1_LAST_LOADED_SGE);
+       PRINT_LMIP_word(asd_ha, lseq, M1_SAVE_SCBPTR);
+
+       asd_printk("LSEQ%d MDP 0 MODE 2 >>>>\n", lseq);
+       PRINT_LMIP_word(asd_ha, lseq, PORT_COUNTER);
+       PRINT_LMIP_word(asd_ha, lseq, PM_TABLE_PTR);
+       PRINT_LMIP_word(asd_ha, lseq, SATA_INTERLOCK_TMR_SAVE);
+       PRINT_LMIP_word(asd_ha, lseq, IP_BITL);
+       PRINT_LMIP_word(asd_ha, lseq, COPY_SMP_CONN_TAG);
+       PRINT_LMIP_byte(asd_ha, lseq, P0M2_OFFS1AH);
+
+       asd_printk("LSEQ%d MDP 0 MODE 4/5 >>>>\n", lseq);
+       PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_STATUS);
+       PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_MODE);
+       PRINT_LMIP_word(asd_ha, lseq, Q_LINK_HEAD);
+       PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_ERR);
+       PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_SIGNALS);
+       PRINT_LMIP_byte(asd_ha, lseq, SAS_RESET_MODE);
+       PRINT_LMIP_byte(asd_ha, lseq, LINK_RESET_RETRY_COUNT);
+       PRINT_LMIP_byte(asd_ha, lseq, NUM_LINK_RESET_RETRIES);
+       PRINT_LMIP_word(asd_ha, lseq, OOB_INT_ENABLES);
+       PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_TIMEOUT);
+       PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_DOWN_COUNT);
+
+       asd_printk("LSEQ%d MDP 1 MODE 0 >>>>\n", lseq);
+       PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR0);
+       PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR1);
+
+       asd_printk("LSEQ%d MDP 1 MODE 1 >>>>\n", lseq);
+       PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR0);
+       PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR1);
+
+       asd_printk("LSEQ%d MDP 1 MODE 2 >>>>\n", lseq);
+       PRINT_LMIP_dword(asd_ha, lseq, INVALID_DWORD_COUNT);
+       PRINT_LMIP_dword(asd_ha, lseq, DISPARITY_ERROR_COUNT);
+       PRINT_LMIP_dword(asd_ha, lseq, LOSS_OF_SYNC_COUNT);
+
+       asd_printk("LSEQ%d MDP 1 MODE 4/5 >>>>\n", lseq);
+       PRINT_LMIP_dword(asd_ha, lseq, FRAME_TYPE_MASK);
+       PRINT_LMIP_dword(asd_ha, lseq, HASHED_SRC_ADDR_MASK_PRINT);
+       PRINT_LMIP_byte(asd_ha, lseq, NUM_FILL_BYTES_MASK);
+       PRINT_LMIP_word(asd_ha, lseq, TAG_MASK);
+       PRINT_LMIP_word(asd_ha, lseq, TARGET_PORT_XFER_TAG);
+       PRINT_LMIP_dword(asd_ha, lseq, DATA_OFFSET);
+
+       asd_printk("LSEQ%d MDP 2 MODE 0 >>>>\n", lseq);
+       PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMER_TERM_TS);
+       PRINT_LMIP_byte(asd_ha, lseq, DEVICE_BITS);
+       PRINT_LMIP_word(asd_ha, lseq, SDB_DDB);
+       PRINT_LMIP_word(asd_ha, lseq, SDB_NUM_TAGS);
+       PRINT_LMIP_word(asd_ha, lseq, SDB_CURR_TAG);
+
+       asd_printk("LSEQ%d MDP 2 MODE 1 >>>>\n", lseq);
+       PRINT_LMIP_qword(asd_ha, lseq, TX_ID_ADDR_FRAME);
+       PRINT_LMIP_dword(asd_ha, lseq, OPEN_TIMER_TERM_TS);
+       PRINT_LMIP_dword(asd_ha, lseq, SRST_AS_TIMER_TERM_TS);
+       PRINT_LMIP_dword(asd_ha, lseq, LAST_LOADED_SG_EL);
+
+       asd_printk("LSEQ%d MDP 2 MODE 2 >>>>\n", lseq);
+       PRINT_LMIP_dword(asd_ha, lseq, CLOSE_TIMER_TERM_TS);
+       PRINT_LMIP_dword(asd_ha, lseq, BREAK_TIMER_TERM_TS);
+       PRINT_LMIP_dword(asd_ha, lseq, DWS_RESET_TIMER_TERM_TS);
+       PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMER_TERM_TS);
+       PRINT_LMIP_dword(asd_ha, lseq, MCTL_TIMER_TERM_TS);
+
+       asd_printk("LSEQ%d MDP 2 MODE 4/5 >>>>\n", lseq);
+       PRINT_LMIP_dword(asd_ha, lseq, COMINIT_TIMER_TERM_TS);
+       PRINT_LMIP_dword(asd_ha, lseq, RCV_ID_TIMER_TERM_TS);
+       PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMER_TERM_TS);
+       PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TIMER_TERM_TS);
+}
+
+/**
+ * asd_dump_ddb_site -- dump a CSEQ DDB site
+ * @asd_ha: pointer to host adapter structure
+ * @site_no: site number of interest
+ */
+void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no)
+{
+       if (site_no >= asd_ha->hw_prof.max_ddbs)
+               return;
+
+#define DDB_FIELDB(__name)                                        \
+       asd_ddbsite_read_byte(asd_ha, site_no,                    \
+                             offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+#define DDB2_FIELDB(__name)                                       \
+       asd_ddbsite_read_byte(asd_ha, site_no,                    \
+                             offsetof(struct asd_ddb_stp_sata_target_port, __name))
+#define DDB_FIELDW(__name)                                        \
+       asd_ddbsite_read_word(asd_ha, site_no,                    \
+                             offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+
+#define DDB_FIELDD(__name)                                         \
+       asd_ddbsite_read_dword(asd_ha, site_no,                    \
+                              offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+
+       asd_printk("DDB: 0x%02x\n", site_no);
+       asd_printk("conn_type: 0x%02x\n", DDB_FIELDB(conn_type));
+       asd_printk("conn_rate: 0x%02x\n", DDB_FIELDB(conn_rate));
+       asd_printk("init_conn_tag: 0x%04x\n", be16_to_cpu(DDB_FIELDW(init_conn_tag)));
+       asd_printk("send_queue_head: 0x%04x\n", be16_to_cpu(DDB_FIELDW(send_queue_head)));
+       asd_printk("sq_suspended: 0x%02x\n", DDB_FIELDB(sq_suspended));
+       asd_printk("DDB Type: 0x%02x\n", DDB_FIELDB(ddb_type));
+       asd_printk("AWT Default: 0x%04x\n", DDB_FIELDW(awt_def));
+       asd_printk("compat_features: 0x%02x\n", DDB_FIELDB(compat_features));
+       asd_printk("Pathway Blocked Count: 0x%02x\n",
+                  DDB_FIELDB(pathway_blocked_count));
+       asd_printk("arb_wait_time: 0x%04x\n", DDB_FIELDW(arb_wait_time));
+       asd_printk("more_compat_features: 0x%08x\n",
+                  DDB_FIELDD(more_compat_features));
+       asd_printk("Conn Mask: 0x%02x\n", DDB_FIELDB(conn_mask));
+       asd_printk("flags: 0x%02x\n", DDB_FIELDB(flags));
+       asd_printk("flags2: 0x%02x\n", DDB2_FIELDB(flags2));
+       asd_printk("ExecQ Tail: 0x%04x\n",DDB_FIELDW(exec_queue_tail));
+       asd_printk("SendQ Tail: 0x%04x\n",DDB_FIELDW(send_queue_tail));
+       asd_printk("Active Task Count: 0x%04x\n",
+                  DDB_FIELDW(active_task_count));
+       asd_printk("ITNL Reason: 0x%02x\n", DDB_FIELDB(itnl_reason));
+       asd_printk("ITNL Timeout Const: 0x%04x\n", DDB_FIELDW(itnl_timeout));
+       asd_printk("ITNL timestamp: 0x%08x\n", DDB_FIELDD(itnl_timestamp));
+}
+
+void asd_dump_ddb_0(struct asd_ha_struct *asd_ha)
+{
+#define DDB0_FIELDB(__name)                                  \
+       asd_ddbsite_read_byte(asd_ha, 0,                     \
+                             offsetof(struct asd_ddb_seq_shared, __name))
+#define DDB0_FIELDW(__name)                                  \
+       asd_ddbsite_read_word(asd_ha, 0,                     \
+                             offsetof(struct asd_ddb_seq_shared, __name))
+
+#define DDB0_FIELDD(__name)                                  \
+       asd_ddbsite_read_dword(asd_ha,0 ,                    \
+                              offsetof(struct asd_ddb_seq_shared, __name))
+
+#define DDB0_FIELDA(__name, _o)                              \
+       asd_ddbsite_read_byte(asd_ha, 0,                     \
+                             offsetof(struct asd_ddb_seq_shared, __name)+_o)
+
+
+       asd_printk("DDB: 0\n");
+       asd_printk("q_free_ddb_head:%04x\n", DDB0_FIELDW(q_free_ddb_head));
+       asd_printk("q_free_ddb_tail:%04x\n", DDB0_FIELDW(q_free_ddb_tail));
+       asd_printk("q_free_ddb_cnt:%04x\n",  DDB0_FIELDW(q_free_ddb_cnt));
+       asd_printk("q_used_ddb_head:%04x\n", DDB0_FIELDW(q_used_ddb_head));
+       asd_printk("q_used_ddb_tail:%04x\n", DDB0_FIELDW(q_used_ddb_tail));
+       asd_printk("shared_mem_lock:%04x\n", DDB0_FIELDW(shared_mem_lock));
+       asd_printk("smp_conn_tag:%04x\n",    DDB0_FIELDW(smp_conn_tag));
+       asd_printk("est_nexus_buf_cnt:%04x\n", DDB0_FIELDW(est_nexus_buf_cnt));
+       asd_printk("est_nexus_buf_thresh:%04x\n",
+                  DDB0_FIELDW(est_nexus_buf_thresh));
+       asd_printk("conn_not_active:%02x\n", DDB0_FIELDB(conn_not_active));
+       asd_printk("phy_is_up:%02x\n",       DDB0_FIELDB(phy_is_up));
+       asd_printk("port_map_by_links:%02x %02x %02x %02x "
+                  "%02x %02x %02x %02x\n",
+                  DDB0_FIELDA(port_map_by_links, 0),
+                  DDB0_FIELDA(port_map_by_links, 1),
+                  DDB0_FIELDA(port_map_by_links, 2),
+                  DDB0_FIELDA(port_map_by_links, 3),
+                  DDB0_FIELDA(port_map_by_links, 4),
+                  DDB0_FIELDA(port_map_by_links, 5),
+                  DDB0_FIELDA(port_map_by_links, 6),
+                  DDB0_FIELDA(port_map_by_links, 7));
+}
+
+static void asd_dump_scb_site(struct asd_ha_struct *asd_ha, u16 site_no)
+{
+
+#define SCB_FIELDB(__name)                                                 \
+       asd_scbsite_read_byte(asd_ha, site_no, sizeof(struct scb_header)   \
+                             + offsetof(struct initiate_ssp_task, __name))
+#define SCB_FIELDW(__name)                                                 \
+       asd_scbsite_read_word(asd_ha, site_no, sizeof(struct scb_header)   \
+                             + offsetof(struct initiate_ssp_task, __name))
+#define SCB_FIELDD(__name)                                                 \
+       asd_scbsite_read_dword(asd_ha, site_no, sizeof(struct scb_header)  \
+                              + offsetof(struct initiate_ssp_task, __name))
+
+       asd_printk("Total Xfer Len: 0x%08x.\n", SCB_FIELDD(total_xfer_len));
+       asd_printk("Frame Type: 0x%02x.\n", SCB_FIELDB(ssp_frame.frame_type));
+       asd_printk("Tag: 0x%04x.\n", SCB_FIELDW(ssp_frame.tag));
+       asd_printk("Target Port Xfer Tag: 0x%04x.\n",
+                  SCB_FIELDW(ssp_frame.tptt));
+       asd_printk("Data Offset: 0x%08x.\n", SCB_FIELDW(ssp_frame.data_offs));
+       asd_printk("Retry Count: 0x%02x.\n", SCB_FIELDB(retry_count));
+}
+
+/**
+ * asd_dump_scb_sites -- dump currently used CSEQ SCB sites
+ * @asd_ha: pointer to host adapter struct
+ */
+void asd_dump_scb_sites(struct asd_ha_struct *asd_ha)
+{
+       u16     site_no;
+
+       for (site_no = 0; site_no < asd_ha->hw_prof.max_scbs; site_no++) {
+               u8 opcode;
+
+               if (!SCB_SITE_VALID(site_no))
+                       continue;
+
+               /* We are only interested in SCB sites currently used.
+                */
+               opcode = asd_scbsite_read_byte(asd_ha, site_no,
+                                              offsetof(struct scb_header,
+                                                       opcode));
+               if (opcode == 0xFF)
+                       continue;
+
+               asd_printk("\nSCB: 0x%x\n", site_no);
+               asd_dump_scb_site(asd_ha, site_no);
+       }
+}
+
+/**
+ * ads_dump_seq_state -- dump CSEQ and LSEQ states
+ * @asd_ha: pointer to host adapter structure
+ * @lseq_mask: mask of LSEQs of interest
+ */
+void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask)
+{
+       int lseq;
+
+       asd_dump_cseq_state(asd_ha);
+
+       if (lseq_mask != 0)
+               for_each_sequencer(lseq_mask, lseq_mask, lseq)
+                       asd_dump_lseq_state(asd_ha, lseq);
+}
+
+void asd_dump_frame_rcvd(struct asd_phy *phy,
+                        struct done_list_struct *dl)
+{
+       unsigned long flags;
+       int i;
+
+       switch ((dl->status_block[1] & 0x70) >> 3) {
+       case SAS_PROTO_STP:
+               ASD_DPRINTK("STP proto device-to-host FIS:\n");
+               break;
+       default:
+       case SAS_PROTO_SSP:
+               ASD_DPRINTK("SAS proto IDENTIFY:\n");
+               break;
+       }
+       spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
+       for (i = 0; i < phy->sas_phy.frame_rcvd_size; i+=4)
+               ASD_DPRINTK("%02x: %02x %02x %02x %02x\n",
+                           i,
+                           phy->frame_rcvd[i],
+                           phy->frame_rcvd[i+1],
+                           phy->frame_rcvd[i+2],
+                           phy->frame_rcvd[i+3]);
+       spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
+}
+
+static inline void asd_dump_scb(struct asd_ascb *ascb, int ind)
+{
+       asd_printk("scb%d: vaddr: 0x%p, dma_handle: 0x%llx, next: 0x%llx, "
+                  "index:%d, opcode:0x%02x\n",
+                  ind, ascb->dma_scb.vaddr,
+                  (unsigned long long)ascb->dma_scb.dma_handle,
+                  (unsigned long long)
+                  le64_to_cpu(ascb->scb->header.next_scb),
+                  le16_to_cpu(ascb->scb->header.index),
+                  ascb->scb->header.opcode);
+}
+
+void asd_dump_scb_list(struct asd_ascb *ascb, int num)
+{
+       int i = 0;
+
+       asd_printk("dumping %d scbs:\n", num);
+
+       asd_dump_scb(ascb, i++);
+       --num;
+
+       if (num > 0 && !list_empty(&ascb->list)) {
+               struct list_head *el;
+
+               list_for_each(el, &ascb->list) {
+                       struct asd_ascb *s = list_entry(el, struct asd_ascb,
+                                                       list);
+                       asd_dump_scb(s, i++);
+                       if (--num <= 0)
+                               break;
+               }
+       }
+}
+
+#endif /* ASD_DEBUG */
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.h b/drivers/scsi/aic94xx/aic94xx_dump.h
new file mode 100644 (file)
index 0000000..0c388e7
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Aic94xx SAS/SATA driver dump header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _AIC94XX_DUMP_H_
+#define _AIC94XX_DUMP_H_
+
+#ifdef ASD_DEBUG
+
+void asd_dump_ddb_0(struct asd_ha_struct *asd_ha);
+void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no);
+void asd_dump_scb_sites(struct asd_ha_struct *asd_ha);
+void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask);
+void asd_dump_frame_rcvd(struct asd_phy *phy,
+                        struct done_list_struct *dl);
+void asd_dump_scb_list(struct asd_ascb *ascb, int num);
+#else /* ASD_DEBUG */
+
+static inline void asd_dump_ddb_0(struct asd_ha_struct *asd_ha) { }
+static inline void asd_dump_target_ddb(struct asd_ha_struct *asd_ha,
+                                    u16 site_no) { }
+static inline void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) { }
+static inline void asd_dump_seq_state(struct asd_ha_struct *asd_ha,
+                                     u8 lseq_mask) { }
+static inline void asd_dump_frame_rcvd(struct asd_phy *phy,
+                                      struct done_list_struct *dl) { }
+static inline void asd_dump_scb_list(struct asd_ascb *ascb, int num) { }
+#endif /* ASD_DEBUG */
+
+#endif /* _AIC94XX_DUMP_H_ */
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
new file mode 100644 (file)
index 0000000..075cea8
--- /dev/null
@@ -0,0 +1,1376 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+#include "aic94xx_dump.h"
+
+u32 MBAR0_SWB_SIZE;
+
+/* ---------- Initialization ---------- */
+
+static void asd_get_user_sas_addr(struct asd_ha_struct *asd_ha)
+{
+       extern char sas_addr_str[];
+       /* If the user has specified a WWN it overrides other settings
+        */
+       if (sas_addr_str[0] != '\0')
+               asd_destringify_sas_addr(asd_ha->hw_prof.sas_addr,
+                                        sas_addr_str);
+       else if (asd_ha->hw_prof.sas_addr[0] != 0)
+               asd_stringify_sas_addr(sas_addr_str, asd_ha->hw_prof.sas_addr);
+}
+
+static void asd_propagate_sas_addr(struct asd_ha_struct *asd_ha)
+{
+       int i;
+
+       for (i = 0; i < ASD_MAX_PHYS; i++) {
+               if (asd_ha->hw_prof.phy_desc[i].sas_addr[0] == 0)
+                       continue;
+               /* Set a phy's address only if it has none.
+                */
+               ASD_DPRINTK("setting phy%d addr to %llx\n", i,
+                           SAS_ADDR(asd_ha->hw_prof.sas_addr));
+               memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr,
+                      asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
+       }
+}
+
+/* ---------- PHY initialization ---------- */
+
+static void asd_init_phy_identify(struct asd_phy *phy)
+{
+       phy->identify_frame = phy->id_frm_tok->vaddr;
+
+       memset(phy->identify_frame, 0, sizeof(*phy->identify_frame));
+
+       phy->identify_frame->dev_type = SAS_END_DEV;
+       if (phy->sas_phy.role & PHY_ROLE_INITIATOR)
+               phy->identify_frame->initiator_bits = phy->sas_phy.iproto;
+       if (phy->sas_phy.role & PHY_ROLE_TARGET)
+               phy->identify_frame->target_bits = phy->sas_phy.tproto;
+       memcpy(phy->identify_frame->sas_addr, phy->phy_desc->sas_addr,
+              SAS_ADDR_SIZE);
+       phy->identify_frame->phy_id = phy->sas_phy.id;
+}
+
+static int asd_init_phy(struct asd_phy *phy)
+{
+       struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+       sas_phy->enabled = 1;
+       sas_phy->class = SAS;
+       sas_phy->iproto = SAS_PROTO_ALL;
+       sas_phy->tproto = 0;
+       sas_phy->type = PHY_TYPE_PHYSICAL;
+       sas_phy->role = PHY_ROLE_INITIATOR;
+       sas_phy->oob_mode = OOB_NOT_CONNECTED;
+       sas_phy->linkrate = PHY_LINKRATE_NONE;
+
+       phy->id_frm_tok = asd_alloc_coherent(asd_ha,
+                                            sizeof(*phy->identify_frame),
+                                            GFP_KERNEL);
+       if (!phy->id_frm_tok) {
+               asd_printk("no mem for IDENTIFY for phy%d\n", sas_phy->id);
+               return -ENOMEM;
+       } else
+               asd_init_phy_identify(phy);
+
+       memset(phy->frame_rcvd, 0, sizeof(phy->frame_rcvd));
+
+       return 0;
+}
+
+static int asd_init_phys(struct asd_ha_struct *asd_ha)
+{
+       u8 i;
+       u8 phy_mask = asd_ha->hw_prof.enabled_phys;
+
+       for (i = 0; i < ASD_MAX_PHYS; i++) {
+               struct asd_phy *phy = &asd_ha->phys[i];
+
+               phy->phy_desc = &asd_ha->hw_prof.phy_desc[i];
+
+               phy->sas_phy.enabled = 0;
+               phy->sas_phy.id = i;
+               phy->sas_phy.sas_addr = &phy->phy_desc->sas_addr[0];
+               phy->sas_phy.frame_rcvd = &phy->frame_rcvd[0];
+               phy->sas_phy.ha = &asd_ha->sas_ha;
+               phy->sas_phy.lldd_phy = phy;
+       }
+
+       /* Now enable and initialize only the enabled phys. */
+       for_each_phy(phy_mask, phy_mask, i) {
+               int err = asd_init_phy(&asd_ha->phys[i]);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* ---------- Sliding windows ---------- */
+
+static int asd_init_sw(struct asd_ha_struct *asd_ha)
+{
+       struct pci_dev *pcidev = asd_ha->pcidev;
+       int err;
+       u32 v;
+
+       /* Unlock MBARs */
+       err = pci_read_config_dword(pcidev, PCI_CONF_MBAR_KEY, &v);
+       if (err) {
+               asd_printk("couldn't access conf. space of %s\n",
+                          pci_name(pcidev));
+               goto Err;
+       }
+       if (v)
+               err = pci_write_config_dword(pcidev, PCI_CONF_MBAR_KEY, v);
+       if (err) {
+               asd_printk("couldn't write to MBAR_KEY of %s\n",
+                          pci_name(pcidev));
+               goto Err;
+       }
+
+       /* Set sliding windows A, B and C to point to proper internal
+        * memory regions.
+        */
+       pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWA, REG_BASE_ADDR);
+       pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWB,
+                              REG_BASE_ADDR_CSEQCIO);
+       pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWC, REG_BASE_ADDR_EXSI);
+       asd_ha->io_handle[0].swa_base = REG_BASE_ADDR;
+       asd_ha->io_handle[0].swb_base = REG_BASE_ADDR_CSEQCIO;
+       asd_ha->io_handle[0].swc_base = REG_BASE_ADDR_EXSI;
+       MBAR0_SWB_SIZE = asd_ha->io_handle[0].len - 0x80;
+       if (!asd_ha->iospace) {
+               /* MBAR1 will point to OCM (On Chip Memory) */
+               pci_write_config_dword(pcidev, PCI_CONF_MBAR1, OCM_BASE_ADDR);
+               asd_ha->io_handle[1].swa_base = OCM_BASE_ADDR;
+       }
+       spin_lock_init(&asd_ha->iolock);
+Err:
+       return err;
+}
+
+/* ---------- SCB initialization ---------- */
+
+/**
+ * asd_init_scbs - manually allocate the first SCB.
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This allocates the very first SCB which would be sent to the
+ * sequencer for execution.  Its bus address is written to
+ * CSEQ_Q_NEW_POINTER, mode page 2, mode 8.  Since the bus address of
+ * the _next_ scb to be DMA-ed to the host adapter is read from the last
+ * SCB DMA-ed to the host adapter, we have to always stay one step
+ * ahead of the sequencer and keep one SCB already allocated.
+ */
+static int asd_init_scbs(struct asd_ha_struct *asd_ha)
+{
+       struct asd_seq_data *seq = &asd_ha->seq;
+       int bitmap_bytes;
+
+       /* allocate the index array and bitmap */
+       asd_ha->seq.tc_index_bitmap_bits = asd_ha->hw_prof.max_scbs;
+       asd_ha->seq.tc_index_array = kzalloc(asd_ha->seq.tc_index_bitmap_bits*
+                                            sizeof(void *), GFP_KERNEL);
+       if (!asd_ha->seq.tc_index_array)
+               return -ENOMEM;
+
+       bitmap_bytes = (asd_ha->seq.tc_index_bitmap_bits+7)/8;
+       bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
+       asd_ha->seq.tc_index_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
+       if (!asd_ha->seq.tc_index_bitmap)
+               return -ENOMEM;
+
+       spin_lock_init(&seq->tc_index_lock);
+
+       seq->next_scb.size = sizeof(struct scb);
+       seq->next_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, GFP_KERNEL,
+                                            &seq->next_scb.dma_handle);
+       if (!seq->next_scb.vaddr) {
+               kfree(asd_ha->seq.tc_index_bitmap);
+               kfree(asd_ha->seq.tc_index_array);
+               asd_ha->seq.tc_index_bitmap = NULL;
+               asd_ha->seq.tc_index_array = NULL;
+               return -ENOMEM;
+       }
+
+       seq->pending = 0;
+       spin_lock_init(&seq->pend_q_lock);
+       INIT_LIST_HEAD(&seq->pend_q);
+
+       return 0;
+}
+
+static inline void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha)
+{
+       asd_ha->hw_prof.max_scbs = asd_get_cmdctx_size(asd_ha)/ASD_SCB_SIZE;
+       asd_ha->hw_prof.max_ddbs = asd_get_devctx_size(asd_ha)/ASD_DDB_SIZE;
+       ASD_DPRINTK("max_scbs:%d, max_ddbs:%d\n",
+                   asd_ha->hw_prof.max_scbs,
+                   asd_ha->hw_prof.max_ddbs);
+}
+
+/* ---------- Done List initialization ---------- */
+
+static void asd_dl_tasklet_handler(unsigned long);
+
+static int asd_init_dl(struct asd_ha_struct *asd_ha)
+{
+       asd_ha->seq.actual_dl
+               = asd_alloc_coherent(asd_ha,
+                            ASD_DL_SIZE * sizeof(struct done_list_struct),
+                                    GFP_KERNEL);
+       if (!asd_ha->seq.actual_dl)
+               return -ENOMEM;
+       asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr;
+       asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE;
+       asd_ha->seq.dl_next = 0;
+       tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler,
+                    (unsigned long) asd_ha);
+
+       return 0;
+}
+
+/* ---------- EDB and ESCB init ---------- */
+
+static int asd_alloc_edbs(struct asd_ha_struct *asd_ha, unsigned int gfp_flags)
+{
+       struct asd_seq_data *seq = &asd_ha->seq;
+       int i;
+
+       seq->edb_arr = kmalloc(seq->num_edbs*sizeof(*seq->edb_arr), gfp_flags);
+       if (!seq->edb_arr)
+               return -ENOMEM;
+
+       for (i = 0; i < seq->num_edbs; i++) {
+               seq->edb_arr[i] = asd_alloc_coherent(asd_ha, ASD_EDB_SIZE,
+                                                    gfp_flags);
+               if (!seq->edb_arr[i])
+                       goto Err_unroll;
+               memset(seq->edb_arr[i]->vaddr, 0, ASD_EDB_SIZE);
+       }
+
+       ASD_DPRINTK("num_edbs:%d\n", seq->num_edbs);
+
+       return 0;
+
+Err_unroll:
+       for (i-- ; i >= 0; i--)
+               asd_free_coherent(asd_ha, seq->edb_arr[i]);
+       kfree(seq->edb_arr);
+       seq->edb_arr = NULL;
+
+       return -ENOMEM;
+}
+
+static int asd_alloc_escbs(struct asd_ha_struct *asd_ha,
+                          unsigned int gfp_flags)
+{
+       struct asd_seq_data *seq = &asd_ha->seq;
+       struct asd_ascb *escb;
+       int i, escbs;
+
+       seq->escb_arr = kmalloc(seq->num_escbs*sizeof(*seq->escb_arr),
+                               gfp_flags);
+       if (!seq->escb_arr)
+               return -ENOMEM;
+
+       escbs = seq->num_escbs;
+       escb = asd_ascb_alloc_list(asd_ha, &escbs, gfp_flags);
+       if (!escb) {
+               asd_printk("couldn't allocate list of escbs\n");
+               goto Err;
+       }
+       seq->num_escbs -= escbs;  /* subtract what was not allocated */
+       ASD_DPRINTK("num_escbs:%d\n", seq->num_escbs);
+
+       for (i = 0; i < seq->num_escbs; i++, escb = list_entry(escb->list.next,
+                                                              struct asd_ascb,
+                                                              list)) {
+               seq->escb_arr[i] = escb;
+               escb->scb->header.opcode = EMPTY_SCB;
+       }
+
+       return 0;
+Err:
+       kfree(seq->escb_arr);
+       seq->escb_arr = NULL;
+       return -ENOMEM;
+
+}
+
+static void asd_assign_edbs2escbs(struct asd_ha_struct *asd_ha)
+{
+       struct asd_seq_data *seq = &asd_ha->seq;
+       int i, k, z = 0;
+
+       for (i = 0; i < seq->num_escbs; i++) {
+               struct asd_ascb *ascb = seq->escb_arr[i];
+               struct empty_scb *escb = &ascb->scb->escb;
+
+               ascb->edb_index = z;
+
+               escb->num_valid = ASD_EDBS_PER_SCB;
+
+               for (k = 0; k < ASD_EDBS_PER_SCB; k++) {
+                       struct sg_el *eb = &escb->eb[k];
+                       struct asd_dma_tok *edb = seq->edb_arr[z++];
+
+                       memset(eb, 0, sizeof(*eb));
+                       eb->bus_addr = cpu_to_le64(((u64) edb->dma_handle));
+                       eb->size = cpu_to_le32(((u32) edb->size));
+               }
+       }
+}
+
+/**
+ * asd_init_escbs -- allocate and initialize empty scbs
+ * @asd_ha: pointer to host adapter structure
+ *
+ * An empty SCB has sg_elements of ASD_EDBS_PER_SCB (7) buffers.
+ * They transport sense data, etc.
+ */
+static int asd_init_escbs(struct asd_ha_struct *asd_ha)
+{
+       struct asd_seq_data *seq = &asd_ha->seq;
+       int err = 0;
+
+       /* Allocate two empty data buffers (edb) per sequencer. */
+       int edbs = 2*(1+asd_ha->hw_prof.num_phys);
+
+       seq->num_escbs = (edbs+ASD_EDBS_PER_SCB-1)/ASD_EDBS_PER_SCB;
+       seq->num_edbs = seq->num_escbs * ASD_EDBS_PER_SCB;
+
+       err = asd_alloc_edbs(asd_ha, GFP_KERNEL);
+       if (err) {
+               asd_printk("couldn't allocate edbs\n");
+               return err;
+       }
+
+       err = asd_alloc_escbs(asd_ha, GFP_KERNEL);
+       if (err) {
+               asd_printk("couldn't allocate escbs\n");
+               return err;
+       }
+
+       asd_assign_edbs2escbs(asd_ha);
+       /* In order to insure that normal SCBs do not overfill sequencer
+        * memory and leave no space for escbs (halting condition),
+        * we increment pending here by the number of escbs.  However,
+        * escbs are never pending.
+        */
+       seq->pending   = seq->num_escbs;
+       seq->can_queue = 1 + (asd_ha->hw_prof.max_scbs - seq->pending)/2;
+
+       return 0;
+}
+
+/* ---------- HW initialization ---------- */
+
+/**
+ * asd_chip_hardrst -- hard reset the chip
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This takes 16 cycles and is synchronous to CFCLK, which runs
+ * at 200 MHz, so this should take at most 80 nanoseconds.
+ */
+int asd_chip_hardrst(struct asd_ha_struct *asd_ha)
+{
+       int i;
+       int count = 100;
+       u32 reg;
+
+       for (i = 0 ; i < 4 ; i++) {
+               asd_write_reg_dword(asd_ha, COMBIST, HARDRST);
+       }
+
+       do {
+               udelay(1);
+               reg = asd_read_reg_dword(asd_ha, CHIMINT);
+               if (reg & HARDRSTDET) {
+                       asd_write_reg_dword(asd_ha, CHIMINT,
+                                           HARDRSTDET|PORRSTDET);
+                       return 0;
+               }
+       } while (--count > 0);
+
+       return -ENODEV;
+}
+
+/**
+ * asd_init_chip -- initialize the chip
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Hard resets the chip, disables HA interrupts, downloads the sequnecer
+ * microcode and starts the sequencers.  The caller has to explicitly
+ * enable HA interrupts with asd_enable_ints(asd_ha).
+ */
+static int asd_init_chip(struct asd_ha_struct *asd_ha)
+{
+       int err;
+
+       err = asd_chip_hardrst(asd_ha);
+       if (err) {
+               asd_printk("couldn't hard reset %s\n",
+                           pci_name(asd_ha->pcidev));
+               goto out;
+       }
+
+       asd_disable_ints(asd_ha);
+
+       err = asd_init_seqs(asd_ha);
+       if (err) {
+               asd_printk("couldn't init seqs for %s\n",
+                          pci_name(asd_ha->pcidev));
+               goto out;
+       }
+
+       err = asd_start_seqs(asd_ha);
+       if (err) {
+               asd_printk("coudln't start seqs for %s\n",
+                          pci_name(asd_ha->pcidev));
+               goto out;
+       }
+out:
+       return err;
+}
+
+#define MAX_DEVS ((OCM_MAX_SIZE) / (ASD_DDB_SIZE))
+
+static int max_devs = 0;
+module_param_named(max_devs, max_devs, int, S_IRUGO);
+MODULE_PARM_DESC(max_devs, "\n"
+       "\tMaximum number of SAS devices to support (not LUs).\n"
+       "\tDefault: 2176, Maximum: 65663.\n");
+
+static int max_cmnds = 0;
+module_param_named(max_cmnds, max_cmnds, int, S_IRUGO);
+MODULE_PARM_DESC(max_cmnds, "\n"
+       "\tMaximum number of commands queuable.\n"
+       "\tDefault: 512, Maximum: 66047.\n");
+
+static void asd_extend_devctx_ocm(struct asd_ha_struct *asd_ha)
+{
+       unsigned long dma_addr = OCM_BASE_ADDR;
+       u32 d;
+
+       dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
+       asd_write_reg_addr(asd_ha, DEVCTXBASE, (dma_addr_t) dma_addr);
+       d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+       d |= 4;
+       asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+       asd_ha->hw_prof.max_ddbs += MAX_DEVS;
+}
+
+static int asd_extend_devctx(struct asd_ha_struct *asd_ha)
+{
+       dma_addr_t dma_handle;
+       unsigned long dma_addr;
+       u32 d;
+       int size;
+
+       asd_extend_devctx_ocm(asd_ha);
+
+       asd_ha->hw_prof.ddb_ext = NULL;
+       if (max_devs <= asd_ha->hw_prof.max_ddbs || max_devs > 0xFFFF) {
+               max_devs = asd_ha->hw_prof.max_ddbs;
+               return 0;
+       }
+
+       size = (max_devs - asd_ha->hw_prof.max_ddbs + 1) * ASD_DDB_SIZE;
+
+       asd_ha->hw_prof.ddb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
+       if (!asd_ha->hw_prof.ddb_ext) {
+               asd_printk("couldn't allocate memory for %d devices\n",
+                          max_devs);
+               max_devs = asd_ha->hw_prof.max_ddbs;
+               return -ENOMEM;
+       }
+       dma_handle = asd_ha->hw_prof.ddb_ext->dma_handle;
+       dma_addr = ALIGN((unsigned long) dma_handle, ASD_DDB_SIZE);
+       dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
+       dma_handle = (dma_addr_t) dma_addr;
+       asd_write_reg_addr(asd_ha, DEVCTXBASE, dma_handle);
+       d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+       d &= ~4;
+       asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+
+       asd_ha->hw_prof.max_ddbs = max_devs;
+
+       return 0;
+}
+
+static int asd_extend_cmdctx(struct asd_ha_struct *asd_ha)
+{
+       dma_addr_t dma_handle;
+       unsigned long dma_addr;
+       u32 d;
+       int size;
+
+       asd_ha->hw_prof.scb_ext = NULL;
+       if (max_cmnds <= asd_ha->hw_prof.max_scbs || max_cmnds > 0xFFFF) {
+               max_cmnds = asd_ha->hw_prof.max_scbs;
+               return 0;
+       }
+
+       size = (max_cmnds - asd_ha->hw_prof.max_scbs + 1) * ASD_SCB_SIZE;
+
+       asd_ha->hw_prof.scb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
+       if (!asd_ha->hw_prof.scb_ext) {
+               asd_printk("couldn't allocate memory for %d commands\n",
+                          max_cmnds);
+               max_cmnds = asd_ha->hw_prof.max_scbs;
+               return -ENOMEM;
+       }
+       dma_handle = asd_ha->hw_prof.scb_ext->dma_handle;
+       dma_addr = ALIGN((unsigned long) dma_handle, ASD_SCB_SIZE);
+       dma_addr -= asd_ha->hw_prof.max_scbs * ASD_SCB_SIZE;
+       dma_handle = (dma_addr_t) dma_addr;
+       asd_write_reg_addr(asd_ha, CMDCTXBASE, dma_handle);
+       d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+       d &= ~1;
+       asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+
+       asd_ha->hw_prof.max_scbs = max_cmnds;
+
+       return 0;
+}
+
+/**
+ * asd_init_ctxmem -- initialize context memory
+ * asd_ha: pointer to host adapter structure
+ *
+ * This function sets the maximum number of SCBs and
+ * DDBs which can be used by the sequencer.  This is normally
+ * 512 and 128 respectively.  If support for more SCBs or more DDBs
+ * is required then CMDCTXBASE, DEVCTXBASE and CTXDOMAIN are
+ * initialized here to extend context memory to point to host memory,
+ * thus allowing unlimited support for SCBs and DDBs -- only limited
+ * by host memory.
+ */
+static int asd_init_ctxmem(struct asd_ha_struct *asd_ha)
+{
+       int bitmap_bytes;
+
+       asd_get_max_scb_ddb(asd_ha);
+       asd_extend_devctx(asd_ha);
+       asd_extend_cmdctx(asd_ha);
+
+       /* The kernel wants bitmaps to be unsigned long sized. */
+       bitmap_bytes = (asd_ha->hw_prof.max_ddbs+7)/8;
+       bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
+       asd_ha->hw_prof.ddb_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
+       if (!asd_ha->hw_prof.ddb_bitmap)
+               return -ENOMEM;
+       spin_lock_init(&asd_ha->hw_prof.ddb_lock);
+
+       return 0;
+}
+
+int asd_init_hw(struct asd_ha_struct *asd_ha)
+{
+       int err;
+       u32 v;
+
+       err = asd_init_sw(asd_ha);
+       if (err)
+               return err;
+
+       err = pci_read_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL, &v);
+       if (err) {
+               asd_printk("couldn't read PCIC_HSTPCIX_CNTRL of %s\n",
+                          pci_name(asd_ha->pcidev));
+               return err;
+       }
+       pci_write_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL,
+                                       v | SC_TMR_DIS);
+       if (err) {
+               asd_printk("couldn't disable split completion timer of %s\n",
+                          pci_name(asd_ha->pcidev));
+               return err;
+       }
+
+       err = asd_read_ocm(asd_ha);
+       if (err) {
+               asd_printk("couldn't read ocm(%d)\n", err);
+               /* While suspicios, it is not an error that we
+                * couldn't read the OCM. */
+       }
+
+       err = asd_read_flash(asd_ha);
+       if (err) {
+               asd_printk("couldn't read flash(%d)\n", err);
+               /* While suspicios, it is not an error that we
+                * couldn't read FLASH memory.
+                */
+       }
+
+       asd_init_ctxmem(asd_ha);
+
+       asd_get_user_sas_addr(asd_ha);
+       if (!asd_ha->hw_prof.sas_addr[0]) {
+               asd_printk("No SAS Address provided for %s\n",
+                          pci_name(asd_ha->pcidev));
+               err = -ENODEV;
+               goto Out;
+       }
+
+       asd_propagate_sas_addr(asd_ha);
+
+       err = asd_init_phys(asd_ha);
+       if (err) {
+               asd_printk("couldn't initialize phys for %s\n",
+                           pci_name(asd_ha->pcidev));
+               goto Out;
+       }
+
+       err = asd_init_scbs(asd_ha);
+       if (err) {
+               asd_printk("couldn't initialize scbs for %s\n",
+                           pci_name(asd_ha->pcidev));
+               goto Out;
+       }
+
+       err = asd_init_dl(asd_ha);
+       if (err) {
+               asd_printk("couldn't initialize the done list:%d\n",
+                           err);
+               goto Out;
+       }
+
+       err = asd_init_escbs(asd_ha);
+       if (err) {
+               asd_printk("couldn't initialize escbs\n");
+               goto Out;
+       }
+
+       err = asd_init_chip(asd_ha);
+       if (err) {
+               asd_printk("couldn't init the chip\n");
+               goto Out;
+       }
+Out:
+       return err;
+}
+
+/* ---------- Chip reset ---------- */
+
+/**
+ * asd_chip_reset -- reset the host adapter, etc
+ * @asd_ha: pointer to host adapter structure of interest
+ *
+ * Called from the ISR.  Hard reset the chip.  Let everything
+ * timeout.  This should be no different than hot-unplugging the
+ * host adapter.  Once everything times out we'll init the chip with
+ * a call to asd_init_chip() and enable interrupts with asd_enable_ints().
+ * XXX finish.
+ */
+static void asd_chip_reset(struct asd_ha_struct *asd_ha)
+{
+       struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+
+       ASD_DPRINTK("chip reset for %s\n", pci_name(asd_ha->pcidev));
+       asd_chip_hardrst(asd_ha);
+       sas_ha->notify_ha_event(sas_ha, HAE_RESET);
+}
+
+/* ---------- Done List Routines ---------- */
+
+static void asd_dl_tasklet_handler(unsigned long data)
+{
+       struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data;
+       struct asd_seq_data *seq = &asd_ha->seq;
+       unsigned long flags;
+
+       while (1) {
+               struct done_list_struct *dl = &seq->dl[seq->dl_next];
+               struct asd_ascb *ascb;
+
+               if ((dl->toggle & DL_TOGGLE_MASK) != seq->dl_toggle)
+                       break;
+
+               /* find the aSCB */
+               spin_lock_irqsave(&seq->tc_index_lock, flags);
+               ascb = asd_tc_index_find(seq, (int)le16_to_cpu(dl->index));
+               spin_unlock_irqrestore(&seq->tc_index_lock, flags);
+               if (unlikely(!ascb)) {
+                       ASD_DPRINTK("BUG:sequencer:dl:no ascb?!\n");
+                       goto next_1;
+               } else if (ascb->scb->header.opcode == EMPTY_SCB) {
+                       goto out;
+               } else if (!ascb->uldd_timer && !del_timer(&ascb->timer)) {
+                       goto next_1;
+               }
+               spin_lock_irqsave(&seq->pend_q_lock, flags);
+               list_del_init(&ascb->list);
+               seq->pending--;
+               spin_unlock_irqrestore(&seq->pend_q_lock, flags);
+       out:
+               ascb->tasklet_complete(ascb, dl);
+
+       next_1:
+               seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1);
+               if (!seq->dl_next)
+                       seq->dl_toggle ^= DL_TOGGLE_MASK;
+       }
+}
+
+/* ---------- Interrupt Service Routines ---------- */
+
+/**
+ * asd_process_donelist_isr -- schedule processing of done list entries
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_process_donelist_isr(struct asd_ha_struct *asd_ha)
+{
+       tasklet_schedule(&asd_ha->seq.dl_tasklet);
+}
+
+/**
+ * asd_com_sas_isr -- process device communication interrupt (COMINT)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_com_sas_isr(struct asd_ha_struct *asd_ha)
+{
+       u32 comstat = asd_read_reg_dword(asd_ha, COMSTAT);
+
+       /* clear COMSTAT int */
+       asd_write_reg_dword(asd_ha, COMSTAT, 0xFFFFFFFF);
+
+       if (comstat & CSBUFPERR) {
+               asd_printk("%s: command/status buffer dma parity error\n",
+                          pci_name(asd_ha->pcidev));
+       } else if (comstat & CSERR) {
+               int i;
+               u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
+               dmaerr &= 0xFF;
+               asd_printk("%s: command/status dma error, DMAERR: 0x%02x, "
+                          "CSDMAADR: 0x%04x, CSDMAADR+4: 0x%04x\n",
+                          pci_name(asd_ha->pcidev),
+                          dmaerr,
+                          asd_read_reg_dword(asd_ha, CSDMAADR),
+                          asd_read_reg_dword(asd_ha, CSDMAADR+4));
+               asd_printk("CSBUFFER:\n");
+               for (i = 0; i < 8; i++) {
+                       asd_printk("%08x %08x %08x %08x\n",
+                                  asd_read_reg_dword(asd_ha, CSBUFFER),
+                                  asd_read_reg_dword(asd_ha, CSBUFFER+4),
+                                  asd_read_reg_dword(asd_ha, CSBUFFER+8),
+                                  asd_read_reg_dword(asd_ha, CSBUFFER+12));
+               }
+               asd_dump_seq_state(asd_ha, 0);
+       } else if (comstat & OVLYERR) {
+               u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
+               dmaerr = (dmaerr >> 8) & 0xFF;
+               asd_printk("%s: overlay dma error:0x%x\n",
+                          pci_name(asd_ha->pcidev),
+                          dmaerr);
+       }
+       asd_chip_reset(asd_ha);
+}
+
+static inline void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus)
+{
+       static const char *halt_code[256] = {
+               "UNEXPECTED_INTERRUPT0",
+               "UNEXPECTED_INTERRUPT1",
+               "UNEXPECTED_INTERRUPT2",
+               "UNEXPECTED_INTERRUPT3",
+               "UNEXPECTED_INTERRUPT4",
+               "UNEXPECTED_INTERRUPT5",
+               "UNEXPECTED_INTERRUPT6",
+               "UNEXPECTED_INTERRUPT7",
+               "UNEXPECTED_INTERRUPT8",
+               "UNEXPECTED_INTERRUPT9",
+               "UNEXPECTED_INTERRUPT10",
+               [11 ... 19] = "unknown[11,19]",
+               "NO_FREE_SCB_AVAILABLE",
+               "INVALID_SCB_OPCODE",
+               "INVALID_MBX_OPCODE",
+               "INVALID_ATA_STATE",
+               "ATA_QUEUE_FULL",
+               "ATA_TAG_TABLE_FAULT",
+               "ATA_TAG_MASK_FAULT",
+               "BAD_LINK_QUEUE_STATE",
+               "DMA2CHIM_QUEUE_ERROR",
+               "EMPTY_SCB_LIST_FULL",
+               "unknown[30]",
+               "IN_USE_SCB_ON_FREE_LIST",
+               "BAD_OPEN_WAIT_STATE",
+               "INVALID_STP_AFFILIATION",
+               "unknown[34]",
+               "EXEC_QUEUE_ERROR",
+               "TOO_MANY_EMPTIES_NEEDED",
+               "EMPTY_REQ_QUEUE_ERROR",
+               "Q_MONIRTT_MGMT_ERROR",
+               "TARGET_MODE_FLOW_ERROR",
+               "DEVICE_QUEUE_NOT_FOUND",
+               "START_IRTT_TIMER_ERROR",
+               "ABORT_TASK_ILLEGAL_REQ",
+               [43 ... 255] = "unknown[43,255]"
+       };
+
+       if (dchstatus & CSEQINT) {
+               u32 arp2int = asd_read_reg_dword(asd_ha, CARP2INT);
+
+               if (arp2int & (ARP2WAITTO|ARP2ILLOPC|ARP2PERR|ARP2CIOPERR)) {
+                       asd_printk("%s: CSEQ arp2int:0x%x\n",
+                                  pci_name(asd_ha->pcidev),
+                                  arp2int);
+               } else if (arp2int & ARP2HALTC)
+                       asd_printk("%s: CSEQ halted: %s\n",
+                                  pci_name(asd_ha->pcidev),
+                                  halt_code[(arp2int>>16)&0xFF]);
+               else
+                       asd_printk("%s: CARP2INT:0x%x\n",
+                                  pci_name(asd_ha->pcidev),
+                                  arp2int);
+       }
+       if (dchstatus & LSEQINT_MASK) {
+               int lseq;
+               u8  lseq_mask = dchstatus & LSEQINT_MASK;
+
+               for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+                       u32 arp2int = asd_read_reg_dword(asd_ha,
+                                                        LmARP2INT(lseq));
+                       if (arp2int & (ARP2WAITTO | ARP2ILLOPC | ARP2PERR
+                                      | ARP2CIOPERR)) {
+                               asd_printk("%s: LSEQ%d arp2int:0x%x\n",
+                                          pci_name(asd_ha->pcidev),
+                                          lseq, arp2int);
+                               /* XXX we should only do lseq reset */
+                       } else if (arp2int & ARP2HALTC)
+                               asd_printk("%s: LSEQ%d halted: %s\n",
+                                          pci_name(asd_ha->pcidev),
+                                          lseq,halt_code[(arp2int>>16)&0xFF]);
+                       else
+                               asd_printk("%s: LSEQ%d ARP2INT:0x%x\n",
+                                          pci_name(asd_ha->pcidev), lseq,
+                                          arp2int);
+               }
+       }
+       asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_dch_sas_isr -- process device channel interrupt (DEVINT)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_dch_sas_isr(struct asd_ha_struct *asd_ha)
+{
+       u32 dchstatus = asd_read_reg_dword(asd_ha, DCHSTATUS);
+
+       if (dchstatus & CFIFTOERR) {
+               asd_printk("%s: CFIFTOERR\n", pci_name(asd_ha->pcidev));
+               asd_chip_reset(asd_ha);
+       } else
+               asd_arp2_err(asd_ha, dchstatus);
+}
+
+/**
+ * ads_rbi_exsi_isr -- process external system interface interrupt (INITERR)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha)
+{
+       u32 stat0r = asd_read_reg_dword(asd_ha, ASISTAT0R);
+
+       if (!(stat0r & ASIERR)) {
+               asd_printk("hmm, EXSI interrupted but no error?\n");
+               return;
+       }
+
+       if (stat0r & ASIFMTERR) {
+               asd_printk("ASI SEEPROM format error for %s\n",
+                          pci_name(asd_ha->pcidev));
+       } else if (stat0r & ASISEECHKERR) {
+               u32 stat1r = asd_read_reg_dword(asd_ha, ASISTAT1R);
+               asd_printk("ASI SEEPROM checksum 0x%x error for %s\n",
+                          stat1r & CHECKSUM_MASK,
+                          pci_name(asd_ha->pcidev));
+       } else {
+               u32 statr = asd_read_reg_dword(asd_ha, ASIERRSTATR);
+
+               if (!(statr & CPI2ASIMSTERR_MASK)) {
+                       ASD_DPRINTK("hmm, ASIERR?\n");
+                       return;
+               } else {
+                       u32 addr = asd_read_reg_dword(asd_ha, ASIERRADDR);
+                       u32 data = asd_read_reg_dword(asd_ha, ASIERRDATAR);
+
+                       asd_printk("%s: CPI2 xfer err: addr: 0x%x, wdata: 0x%x, "
+                                  "count: 0x%x, byteen: 0x%x, targerr: 0x%x "
+                                  "master id: 0x%x, master err: 0x%x\n",
+                                  pci_name(asd_ha->pcidev),
+                                  addr, data,
+                                  (statr & CPI2ASIBYTECNT_MASK) >> 16,
+                                  (statr & CPI2ASIBYTEEN_MASK) >> 12,
+                                  (statr & CPI2ASITARGERR_MASK) >> 8,
+                                  (statr & CPI2ASITARGMID_MASK) >> 4,
+                                  (statr & CPI2ASIMSTERR_MASK));
+               }
+       }
+       asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_hst_pcix_isr -- process host interface interrupts
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Asserted on PCIX errors: target abort, etc.
+ */
+static inline void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha)
+{
+       u16 status;
+       u32 pcix_status;
+       u32 ecc_status;
+
+       pci_read_config_word(asd_ha->pcidev, PCI_STATUS, &status);
+       pci_read_config_dword(asd_ha->pcidev, PCIX_STATUS, &pcix_status);
+       pci_read_config_dword(asd_ha->pcidev, ECC_CTRL_STAT, &ecc_status);
+
+       if (status & PCI_STATUS_DETECTED_PARITY)
+               asd_printk("parity error for %s\n", pci_name(asd_ha->pcidev));
+       else if (status & PCI_STATUS_REC_MASTER_ABORT)
+               asd_printk("master abort for %s\n", pci_name(asd_ha->pcidev));
+       else if (status & PCI_STATUS_REC_TARGET_ABORT)
+               asd_printk("target abort for %s\n", pci_name(asd_ha->pcidev));
+       else if (status & PCI_STATUS_PARITY)
+               asd_printk("data parity for %s\n", pci_name(asd_ha->pcidev));
+       else if (pcix_status & RCV_SCE) {
+               asd_printk("received split completion error for %s\n",
+                          pci_name(asd_ha->pcidev));
+               pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
+               /* XXX: Abort task? */
+               return;
+       } else if (pcix_status & UNEXP_SC) {
+               asd_printk("unexpected split completion for %s\n",
+                          pci_name(asd_ha->pcidev));
+               pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
+               /* ignore */
+               return;
+       } else if (pcix_status & SC_DISCARD)
+               asd_printk("split completion discarded for %s\n",
+                          pci_name(asd_ha->pcidev));
+       else if (ecc_status & UNCOR_ECCERR)
+               asd_printk("uncorrectable ECC error for %s\n",
+                          pci_name(asd_ha->pcidev));
+       asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_hw_isr -- host adapter interrupt service routine
+ * @irq: ignored
+ * @dev_id: pointer to host adapter structure
+ * @regs: ignored
+ *
+ * The ISR processes done list entries and level 3 error handling.
+ */
+irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct asd_ha_struct *asd_ha = dev_id;
+       u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT);
+
+       if (!chimint)
+               return IRQ_NONE;
+
+       asd_write_reg_dword(asd_ha, CHIMINT, chimint);
+       (void) asd_read_reg_dword(asd_ha, CHIMINT);
+
+       if (chimint & DLAVAIL)
+               asd_process_donelist_isr(asd_ha);
+       if (chimint & COMINT)
+               asd_com_sas_isr(asd_ha);
+       if (chimint & DEVINT)
+               asd_dch_sas_isr(asd_ha);
+       if (chimint & INITERR)
+               asd_rbi_exsi_isr(asd_ha);
+       if (chimint & HOSTERR)
+               asd_hst_pcix_isr(asd_ha);
+
+       return IRQ_HANDLED;
+}
+
+/* ---------- SCB handling ---------- */
+
+static inline struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha,
+                                             unsigned int gfp_flags)
+{
+       extern kmem_cache_t *asd_ascb_cache;
+       struct asd_seq_data *seq = &asd_ha->seq;
+       struct asd_ascb *ascb;
+       unsigned long flags;
+
+       ascb = kmem_cache_alloc(asd_ascb_cache, gfp_flags);
+
+       if (ascb) {
+               memset(ascb, 0, sizeof(*ascb));
+               ascb->dma_scb.size = sizeof(struct scb);
+               ascb->dma_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool,
+                                                    gfp_flags,
+                                                   &ascb->dma_scb.dma_handle);
+               if (!ascb->dma_scb.vaddr) {
+                       kmem_cache_free(asd_ascb_cache, ascb);
+                       return NULL;
+               }
+               memset(ascb->dma_scb.vaddr, 0, sizeof(struct scb));
+               asd_init_ascb(asd_ha, ascb);
+
+               spin_lock_irqsave(&seq->tc_index_lock, flags);
+               ascb->tc_index = asd_tc_index_get(seq, ascb);
+               spin_unlock_irqrestore(&seq->tc_index_lock, flags);
+               if (ascb->tc_index == -1)
+                       goto undo;
+
+               ascb->scb->header.index = cpu_to_le16((u16)ascb->tc_index);
+       }
+
+       return ascb;
+undo:
+       dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
+                     ascb->dma_scb.dma_handle);
+       kmem_cache_free(asd_ascb_cache, ascb);
+       ASD_DPRINTK("no index for ascb\n");
+       return NULL;
+}
+
+/**
+ * asd_ascb_alloc_list -- allocate a list of aSCBs
+ * @asd_ha: pointer to host adapter structure
+ * @num: pointer to integer number of aSCBs
+ * @gfp_flags: GFP_ flags.
+ *
+ * This is the only function which is used to allocate aSCBs.
+ * It can allocate one or many. If more than one, then they form
+ * a linked list in two ways: by their list field of the ascb struct
+ * and by the next_scb field of the scb_header.
+ *
+ * Returns NULL if no memory was available, else pointer to a list
+ * of ascbs.  When this function returns, @num would be the number
+ * of SCBs which were not able to be allocated, 0 if all requested
+ * were able to be allocated.
+ */
+struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
+                                    *asd_ha, int *num,
+                                    unsigned int gfp_flags)
+{
+       struct asd_ascb *first = NULL;
+
+       for ( ; *num > 0; --*num) {
+               struct asd_ascb *ascb = asd_ascb_alloc(asd_ha, gfp_flags);
+
+               if (!ascb)
+                       break;
+               else if (!first)
+                       first = ascb;
+               else {
+                       struct asd_ascb *last = list_entry(first->list.prev,
+                                                          struct asd_ascb,
+                                                          list);
+                       list_add_tail(&ascb->list, &first->list);
+                       last->scb->header.next_scb =
+                               cpu_to_le64(((u64)ascb->dma_scb.dma_handle));
+               }
+       }
+
+       return first;
+}
+
+/**
+ * asd_swap_head_scb -- swap the head scb
+ * @asd_ha: pointer to host adapter structure
+ * @ascb: pointer to the head of an ascb list
+ *
+ * The sequencer knows the DMA address of the next SCB to be DMAed to
+ * the host adapter, from initialization or from the last list DMAed.
+ * seq->next_scb keeps the address of this SCB.  The sequencer will
+ * DMA to the host adapter this list of SCBs.  But the head (first
+ * element) of this list is not known to the sequencer.  Here we swap
+ * the head of the list with the known SCB (memcpy()).
+ * Only one memcpy() is required per list so it is in our interest
+ * to keep the list of SCB as long as possible so that the ratio
+ * of number of memcpy calls to the number of SCB DMA-ed is as small
+ * as possible.
+ *
+ * LOCKING: called with the pending list lock held.
+ */
+static inline void asd_swap_head_scb(struct asd_ha_struct *asd_ha,
+                                    struct asd_ascb *ascb)
+{
+       struct asd_seq_data *seq = &asd_ha->seq;
+       struct asd_ascb *last = list_entry(ascb->list.prev,
+                                          struct asd_ascb,
+                                          list);
+       struct asd_dma_tok t = ascb->dma_scb;
+
+       memcpy(seq->next_scb.vaddr, ascb->scb, sizeof(*ascb->scb));
+       ascb->dma_scb = seq->next_scb;
+       ascb->scb = ascb->dma_scb.vaddr;
+       seq->next_scb = t;
+       last->scb->header.next_scb =
+               cpu_to_le64(((u64)seq->next_scb.dma_handle));
+}
+
+/**
+ * asd_start_timers -- (add and) start timers of SCBs
+ * @list: pointer to struct list_head of the scbs
+ * @to: timeout in jiffies
+ *
+ * If an SCB in the @list has no timer function, assign the default
+ * one,  then start the timer of the SCB.  This function is
+ * intended to be called from asd_post_ascb_list(), just prior to
+ * posting the SCBs to the sequencer.
+ */
+static inline void asd_start_scb_timers(struct list_head *list)
+{
+       struct asd_ascb *ascb;
+       list_for_each_entry(ascb, list, list) {
+               if (!ascb->uldd_timer) {
+                       ascb->timer.data = (unsigned long) ascb;
+                       ascb->timer.function = asd_ascb_timedout;
+                       ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
+                       add_timer(&ascb->timer);
+               }
+       }
+}
+
+/**
+ * asd_post_ascb_list -- post a list of 1 or more aSCBs to the host adapter
+ * @asd_ha: pointer to a host adapter structure
+ * @ascb: pointer to the first aSCB in the list
+ * @num: number of aSCBs in the list (to be posted)
+ *
+ * See queueing comment in asd_post_escb_list().
+ *
+ * Additional note on queuing: In order to minimize the ratio of memcpy()
+ * to the number of ascbs sent, we try to batch-send as many ascbs as possible
+ * in one go.
+ * Two cases are possible:
+ *    A) can_queue >= num,
+ *    B) can_queue < num.
+ * Case A: we can send the whole batch at once.  Increment "pending"
+ * in the beginning of this function, when it is checked, in order to
+ * eliminate races when this function is called by multiple processes.
+ * Case B: should never happen if the managing layer considers
+ * lldd_queue_size.
+ */
+int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+                      int num)
+{
+       unsigned long flags;
+       LIST_HEAD(list);
+       int can_queue;
+
+       spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+       can_queue = asd_ha->hw_prof.max_scbs - asd_ha->seq.pending;
+       if (can_queue >= num)
+               asd_ha->seq.pending += num;
+       else
+               can_queue = 0;
+
+       if (!can_queue) {
+               spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+               asd_printk("%s: scb queue full\n", pci_name(asd_ha->pcidev));
+               return -SAS_QUEUE_FULL;
+       }
+
+       asd_swap_head_scb(asd_ha, ascb);
+
+       __list_add(&list, ascb->list.prev, &ascb->list);
+
+       asd_start_scb_timers(&list);
+
+       asd_ha->seq.scbpro += num;
+       list_splice_init(&list, asd_ha->seq.pend_q.prev);
+       asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
+       spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+       return 0;
+}
+
+/**
+ * asd_post_escb_list -- post a list of 1 or more empty scb
+ * @asd_ha: pointer to a host adapter structure
+ * @ascb: pointer to the first empty SCB in the list
+ * @num: number of aSCBs in the list (to be posted)
+ *
+ * This is essentially the same as asd_post_ascb_list, but we do not
+ * increment pending, add those to the pending list or get indexes.
+ * See asd_init_escbs() and asd_init_post_escbs().
+ *
+ * Since sending a list of ascbs is a superset of sending a single
+ * ascb, this function exists to generalize this.  More specifically,
+ * when sending a list of those, we want to do only a _single_
+ * memcpy() at swap head, as opposed to for each ascb sent (in the
+ * case of sending them one by one).  That is, we want to minimize the
+ * ratio of memcpy() operations to the number of ascbs sent.  The same
+ * logic applies to asd_post_ascb_list().
+ */
+int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+                      int num)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+       asd_swap_head_scb(asd_ha, ascb);
+       asd_ha->seq.scbpro += num;
+       asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
+       spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+       return 0;
+}
+
+/* ---------- LED ---------- */
+
+/**
+ * asd_turn_led -- turn on/off an LED
+ * @asd_ha: pointer to host adapter structure
+ * @phy_id: the PHY id whose LED we want to manupulate
+ * @op: 1 to turn on, 0 to turn off
+ */
+void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
+{
+       if (phy_id < ASD_MAX_PHYS) {
+               u32 v = asd_read_reg_dword(asd_ha, LmCONTROL(phy_id));
+               if (op)
+                       v |= LEDPOL;
+               else
+                       v &= ~LEDPOL;
+               asd_write_reg_dword(asd_ha, LmCONTROL(phy_id), v);
+       }
+}
+
+/**
+ * asd_control_led -- enable/disable an LED on the board
+ * @asd_ha: pointer to host adapter structure
+ * @phy_id: integer, the phy id
+ * @op: integer, 1 to enable, 0 to disable the LED
+ *
+ * First we output enable the LED, then we set the source
+ * to be an external module.
+ */
+void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
+{
+       if (phy_id < ASD_MAX_PHYS) {
+               u32 v;
+
+               v = asd_read_reg_dword(asd_ha, GPIOOER);
+               if (op)
+                       v |= (1 << phy_id);
+               else
+                       v &= ~(1 << phy_id);
+               asd_write_reg_dword(asd_ha, GPIOOER, v);
+
+               v = asd_read_reg_dword(asd_ha, GPIOCNFGR);
+               if (op)
+                       v |= (1 << phy_id);
+               else
+                       v &= ~(1 << phy_id);
+               asd_write_reg_dword(asd_ha, GPIOCNFGR, v);
+       }
+}
+
+/* ---------- PHY enable ---------- */
+
+static int asd_enable_phy(struct asd_ha_struct *asd_ha, int phy_id)
+{
+       struct asd_phy *phy = &asd_ha->phys[phy_id];
+
+       asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, INT_ENABLE_2), 0);
+       asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, HOT_PLUG_DELAY),
+                          HOTPLUG_DELAY_TIMEOUT);
+
+       /* Get defaults from manuf. sector */
+       /* XXX we need defaults for those in case MS is broken. */
+       asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_0),
+                          phy->phy_desc->phy_control_0);
+       asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_1),
+                          phy->phy_desc->phy_control_1);
+       asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_2),
+                          phy->phy_desc->phy_control_2);
+       asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_3),
+                          phy->phy_desc->phy_control_3);
+
+       asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(phy_id),
+                           ASD_COMINIT_TIMEOUT);
+
+       asd_write_reg_addr(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(phy_id),
+                          phy->id_frm_tok->dma_handle);
+
+       asd_control_led(asd_ha, phy_id, 1);
+
+       return 0;
+}
+
+int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask)
+{
+       u8  phy_m;
+       u8  i;
+       int num = 0, k;
+       struct asd_ascb *ascb;
+       struct asd_ascb *ascb_list;
+
+       if (!phy_mask) {
+               asd_printk("%s called with phy_mask of 0!?\n", __FUNCTION__);
+               return 0;
+       }
+
+       for_each_phy(phy_mask, phy_m, i) {
+               num++;
+               asd_enable_phy(asd_ha, i);
+       }
+
+       k = num;
+       ascb_list = asd_ascb_alloc_list(asd_ha, &k, GFP_KERNEL);
+       if (!ascb_list) {
+               asd_printk("no memory for control phy ascb list\n");
+               return -ENOMEM;
+       }
+       num -= k;
+
+       ascb = ascb_list;
+       for_each_phy(phy_mask, phy_m, i) {
+               asd_build_control_phy(ascb, i, ENABLE_PHY);
+               ascb = list_entry(ascb->list.next, struct asd_ascb, list);
+       }
+       ASD_DPRINTK("posting %d control phy scbs\n", num);
+       k = asd_post_ascb_list(asd_ha, ascb_list, num);
+       if (k)
+               asd_ascb_free_list(ascb_list);
+
+       return k;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
new file mode 100644 (file)
index 0000000..c7d5053
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _AIC94XX_HWI_H_
+#define _AIC94XX_HWI_H_
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include <scsi/libsas.h>
+
+#include "aic94xx.h"
+#include "aic94xx_sas.h"
+
+/* Define ASD_MAX_PHYS to the maximum phys ever. Currently 8. */
+#define ASD_MAX_PHYS       8
+#define ASD_PCBA_SN_SIZE   12
+
+/* Those are to be further named properly, the "RAZORx" part, and
+ * subsequently included in include/linux/pci_ids.h.
+ */
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F
+
+struct asd_ha_addrspace {
+       void __iomem  *addr;
+       unsigned long  start;       /* pci resource start */
+       unsigned long  len;         /* pci resource len */
+       unsigned long  flags;       /* pci resource flags */
+
+       /* addresses internal to the host adapter */
+       u32 swa_base; /* mmspace 1 (MBAR1) uses this only */
+       u32 swb_base;
+       u32 swc_base;
+};
+
+struct bios_struct {
+       int    present;
+       u8     maj;
+       u8     min;
+       u32    bld;
+};
+
+struct unit_element_struct {
+       u16    num;
+       u16    size;
+       void   *area;
+};
+
+struct flash_struct {
+       u32    bar;
+       int    present;
+       int    wide;
+       u8     manuf;
+       u8     dev_id;
+       u8     sec_prot;
+
+       u32    dir_offs;
+};
+
+struct asd_phy_desc {
+       /* From CTRL-A settings, then set to what is appropriate */
+       u8     sas_addr[SAS_ADDR_SIZE];
+       u8     max_sas_lrate;
+       u8     min_sas_lrate;
+       u8     max_sata_lrate;
+       u8     min_sata_lrate;
+       u8     flags;
+#define ASD_CRC_DIS  1
+#define ASD_SATA_SPINUP_HOLD 2
+
+       u8     phy_control_0; /* mode 5 reg 0x160 */
+       u8     phy_control_1; /* mode 5 reg 0x161 */
+       u8     phy_control_2; /* mode 5 reg 0x162 */
+       u8     phy_control_3; /* mode 5 reg 0x163 */
+};
+
+struct asd_dma_tok {
+       void *vaddr;
+       dma_addr_t dma_handle;
+       size_t size;
+};
+
+struct hw_profile {
+       struct bios_struct bios;
+       struct unit_element_struct ue;
+       struct flash_struct flash;
+
+       u8     sas_addr[SAS_ADDR_SIZE];
+       char   pcba_sn[ASD_PCBA_SN_SIZE+1];
+
+       u8     enabled_phys;      /* mask of enabled phys */
+       struct asd_phy_desc phy_desc[ASD_MAX_PHYS];
+       u32    max_scbs;          /* absolute sequencer scb queue size */
+       struct asd_dma_tok *scb_ext;
+       u32    max_ddbs;
+       struct asd_dma_tok *ddb_ext;
+
+       spinlock_t ddb_lock;
+       void  *ddb_bitmap;
+
+       int    num_phys;          /* ENABLEABLE */
+       int    max_phys;          /* REPORTED + ENABLEABLE */
+
+       unsigned addr_range;      /* max # of addrs; max # of possible ports */
+       unsigned port_name_base;
+       unsigned dev_name_base;
+       unsigned sata_name_base;
+};
+
+struct asd_ascb {
+       struct list_head list;
+       struct asd_ha_struct *ha;
+
+       struct scb *scb;          /* equals dma_scb->vaddr */
+       struct asd_dma_tok dma_scb;
+       struct asd_dma_tok *sg_arr;
+
+       void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *);
+       u8     uldd_timer:1;
+
+       /* internally generated command */
+       struct timer_list timer;
+       struct completion completion;
+       u8        tag_valid:1;
+       __be16    tag;            /* error recovery only */
+
+       /* If this is an Empty SCB, index of first edb in seq->edb_arr. */
+       int    edb_index;
+
+       /* Used by the timer timeout function. */
+       int    tc_index;
+
+       void   *uldd_task;
+};
+
+#define ASD_DL_SIZE_BITS   0x8
+#define ASD_DL_SIZE        (1<<(2+ASD_DL_SIZE_BITS))
+#define ASD_DEF_DL_TOGGLE  0x01
+
+struct asd_seq_data {
+       spinlock_t pend_q_lock;
+       u16    scbpro;
+       int    pending;
+       struct list_head pend_q;
+       int    can_queue;         /* per adapter */
+       struct asd_dma_tok next_scb; /* next scb to be delivered to CSEQ */
+
+       spinlock_t tc_index_lock;
+       void **tc_index_array;
+       void *tc_index_bitmap;
+       int   tc_index_bitmap_bits;
+
+       struct tasklet_struct dl_tasklet;
+       struct done_list_struct *dl; /* array of done list entries, equals */
+       struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */
+       int    dl_toggle;
+       int    dl_next;
+
+       int    num_edbs;
+       struct asd_dma_tok **edb_arr;
+       int    num_escbs;
+       struct asd_ascb **escb_arr; /* array of pointers to escbs */
+};
+
+/* This is the Host Adapter structure.  It describes the hardware
+ * SAS adapter.
+ */
+struct asd_ha_struct {
+       struct pci_dev   *pcidev;
+       const char       *name;
+
+       struct sas_ha_struct sas_ha;
+
+       u8                revision_id;
+
+       int               iospace;
+       spinlock_t        iolock;
+       struct asd_ha_addrspace io_handle[2];
+
+       struct hw_profile hw_prof;
+
+       struct asd_phy    phys[ASD_MAX_PHYS];
+       struct asd_sas_port   ports[ASD_MAX_PHYS];
+
+       struct dma_pool  *scb_pool;
+
+       struct asd_seq_data  seq; /* sequencer related */
+};
+
+/* ---------- Common macros ---------- */
+
+#define ASD_BUSADDR_LO(__dma_handle) ((u32)(__dma_handle))
+#define ASD_BUSADDR_HI(__dma_handle) (((sizeof(dma_addr_t))==8)     \
+                                    ? ((u32)((__dma_handle) >> 32)) \
+                                    : ((u32)0))
+
+#define dev_to_asd_ha(__dev)  pci_get_drvdata(to_pci_dev(__dev))
+#define SCB_SITE_VALID(__site_no) (((__site_no) & 0xF0FF) != 0x00FF   \
+                                && ((__site_no) & 0xF0FF) > 0x001F)
+/* For each bit set in __lseq_mask, set __lseq to equal the bit
+ * position of the set bit and execute the statement following.
+ * __mc is the temporary mask, used as a mask "counter".
+ */
+#define for_each_sequencer(__lseq_mask, __mc, __lseq)                        \
+       for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
+               if (((__mc) & 1))
+#define for_each_phy(__lseq_mask, __mc, __lseq)                              \
+       for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
+               if (((__mc) & 1))
+
+#define PHY_ENABLED(_HA, _I) ((_HA)->hw_prof.enabled_phys & (1<<(_I)))
+
+/* ---------- DMA allocs ---------- */
+
+static inline struct asd_dma_tok *asd_dmatok_alloc(unsigned int flags)
+{
+       return kmem_cache_alloc(asd_dma_token_cache, flags);
+}
+
+static inline void asd_dmatok_free(struct asd_dma_tok *token)
+{
+       kmem_cache_free(asd_dma_token_cache, token);
+}
+
+static inline struct asd_dma_tok *asd_alloc_coherent(struct asd_ha_struct *
+                                                    asd_ha, size_t size,
+                                                    unsigned int flags)
+{
+       struct asd_dma_tok *token = asd_dmatok_alloc(flags);
+       if (token) {
+               token->size = size;
+               token->vaddr = dma_alloc_coherent(&asd_ha->pcidev->dev,
+                                                 token->size,
+                                                 &token->dma_handle,
+                                                 flags);
+               if (!token->vaddr) {
+                       asd_dmatok_free(token);
+                       token = NULL;
+               }
+       }
+       return token;
+}
+
+static inline void asd_free_coherent(struct asd_ha_struct *asd_ha,
+                                    struct asd_dma_tok *token)
+{
+       if (token) {
+               dma_free_coherent(&asd_ha->pcidev->dev, token->size,
+                                 token->vaddr, token->dma_handle);
+               asd_dmatok_free(token);
+       }
+}
+
+static inline void asd_init_ascb(struct asd_ha_struct *asd_ha,
+                                struct asd_ascb *ascb)
+{
+       INIT_LIST_HEAD(&ascb->list);
+       ascb->scb = ascb->dma_scb.vaddr;
+       ascb->ha = asd_ha;
+       ascb->timer.function = NULL;
+       init_timer(&ascb->timer);
+       ascb->tc_index = -1;
+       init_completion(&ascb->completion);
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline void asd_tc_index_release(struct asd_seq_data *seq, int index)
+{
+       seq->tc_index_array[index] = NULL;
+       clear_bit(index, seq->tc_index_bitmap);
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline int asd_tc_index_get(struct asd_seq_data *seq, void *ptr)
+{
+       int index;
+
+       index = find_first_zero_bit(seq->tc_index_bitmap,
+                                   seq->tc_index_bitmap_bits);
+       if (index == seq->tc_index_bitmap_bits)
+               return -1;
+
+       seq->tc_index_array[index] = ptr;
+       set_bit(index, seq->tc_index_bitmap);
+
+       return index;
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline void *asd_tc_index_find(struct asd_seq_data *seq, int index)
+{
+       return seq->tc_index_array[index];
+}
+
+/**
+ * asd_ascb_free -- free a single aSCB after is has completed
+ * @ascb: pointer to the aSCB of interest
+ *
+ * This frees an aSCB after it has been executed/completed by
+ * the sequencer.
+ */
+static inline void asd_ascb_free(struct asd_ascb *ascb)
+{
+       if (ascb) {
+               struct asd_ha_struct *asd_ha = ascb->ha;
+               unsigned long flags;
+
+               BUG_ON(!list_empty(&ascb->list));
+               spin_lock_irqsave(&ascb->ha->seq.tc_index_lock, flags);
+               asd_tc_index_release(&ascb->ha->seq, ascb->tc_index);
+               spin_unlock_irqrestore(&ascb->ha->seq.tc_index_lock, flags);
+               dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
+                             ascb->dma_scb.dma_handle);
+               kmem_cache_free(asd_ascb_cache, ascb);
+       }
+}
+
+/**
+ * asd_ascb_list_free -- free a list of ascbs
+ * @ascb_list: a list of ascbs
+ *
+ * This function will free a list of ascbs allocated by asd_ascb_alloc_list.
+ * It is used when say the scb queueing function returned QUEUE_FULL,
+ * and we do not need the ascbs any more.
+ */
+static inline void asd_ascb_free_list(struct asd_ascb *ascb_list)
+{
+       LIST_HEAD(list);
+       struct list_head *n, *pos;
+
+       __list_add(&list, ascb_list->list.prev, &ascb_list->list);
+       list_for_each_safe(pos, n, &list) {
+               list_del_init(pos);
+               asd_ascb_free(list_entry(pos, struct asd_ascb, list));
+       }
+}
+
+/* ---------- Function declarations ---------- */
+
+int  asd_init_hw(struct asd_ha_struct *asd_ha);
+irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs);
+
+
+struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
+                                    *asd_ha, int *num,
+                                    unsigned int gfp_mask);
+
+int  asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+                       int num);
+int  asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+                       int num);
+
+int  asd_init_post_escbs(struct asd_ha_struct *asd_ha);
+void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc);
+void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
+void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
+int  asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask);
+void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
+                                     u8 subfunc);
+
+void asd_ascb_timedout(unsigned long data);
+int  asd_chip_hardrst(struct asd_ha_struct *asd_ha);
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
new file mode 100644 (file)
index 0000000..3ec2e46
--- /dev/null
@@ -0,0 +1,860 @@
+/*
+ * Aic94xx SAS/SATA driver initialization.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <scsi/scsi_host.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+
+/* The format is "version.release.patchlevel" */
+#define ASD_DRIVER_VERSION "1.0.2"
+
+static int use_msi = 0;
+module_param_named(use_msi, use_msi, int, S_IRUGO);
+MODULE_PARM_DESC(use_msi, "\n"
+       "\tEnable(1) or disable(0) using PCI MSI.\n"
+       "\tDefault: 0");
+
+static int lldd_max_execute_num = 0;
+module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
+MODULE_PARM_DESC(collector, "\n"
+       "\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
+       "\tMode.  If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
+       "\tThe aic94xx SAS LLDD supports both modes.\n"
+       "\tDefault: 0 (Direct Mode).\n");
+
+char sas_addr_str[2*SAS_ADDR_SIZE + 1] = "";
+
+static struct scsi_transport_template *aic94xx_transport_template;
+
+static struct scsi_host_template aic94xx_sht = {
+       .module                 = THIS_MODULE,
+       /* .name is initialized */
+       .name                   = "aic94xx",
+       .queuecommand           = sas_queuecommand,
+       .target_alloc           = sas_target_alloc,
+       .slave_configure        = sas_slave_configure,
+       .slave_destroy          = sas_slave_destroy,
+       .change_queue_depth     = sas_change_queue_depth,
+       .change_queue_type      = sas_change_queue_type,
+       .bios_param             = sas_bios_param,
+       .can_queue              = 1,
+       .cmd_per_lun            = 1,
+       .this_id                = -1,
+       .sg_tablesize           = SG_ALL,
+       .max_sectors            = SCSI_DEFAULT_MAX_SECTORS,
+       .use_clustering         = ENABLE_CLUSTERING,
+};
+
+static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
+{
+       int err, i;
+       struct asd_ha_addrspace *io_handle;
+
+       asd_ha->iospace = 0;
+       for (i = 0; i < 3; i += 2) {
+               io_handle = &asd_ha->io_handle[i==0?0:1];
+               io_handle->start = pci_resource_start(asd_ha->pcidev, i);
+               io_handle->len   = pci_resource_len(asd_ha->pcidev, i);
+               io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);
+               err = -ENODEV;
+               if (!io_handle->start || !io_handle->len) {
+                       asd_printk("MBAR%d start or length for %s is 0.\n",
+                                  i==0?0:1, pci_name(asd_ha->pcidev));
+                       goto Err;
+               }
+               err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);
+               if (err) {
+                       asd_printk("couldn't reserve memory region for %s\n",
+                                  pci_name(asd_ha->pcidev));
+                       goto Err;
+               }
+               if (io_handle->flags & IORESOURCE_CACHEABLE)
+                       io_handle->addr = ioremap(io_handle->start,
+                                                 io_handle->len);
+               else
+                       io_handle->addr = ioremap_nocache(io_handle->start,
+                                                         io_handle->len);
+               if (!io_handle->addr) {
+                       asd_printk("couldn't map MBAR%d of %s\n", i==0?0:1,
+                                  pci_name(asd_ha->pcidev));
+                       goto Err_unreq;
+               }
+       }
+
+       return 0;
+Err_unreq:
+       pci_release_region(asd_ha->pcidev, i);
+Err:
+       if (i > 0) {
+               io_handle = &asd_ha->io_handle[0];
+               iounmap(io_handle->addr);
+               pci_release_region(asd_ha->pcidev, 0);
+       }
+       return err;
+}
+
+static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
+{
+       struct asd_ha_addrspace *io_handle;
+
+       io_handle = &asd_ha->io_handle[1];
+       iounmap(io_handle->addr);
+       pci_release_region(asd_ha->pcidev, 2);
+
+       io_handle = &asd_ha->io_handle[0];
+       iounmap(io_handle->addr);
+       pci_release_region(asd_ha->pcidev, 0);
+}
+
+static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
+{
+       int i = PCI_IOBAR_OFFSET, err;
+       struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];
+
+       asd_ha->iospace = 1;
+       io_handle->start = pci_resource_start(asd_ha->pcidev, i);
+       io_handle->len   = pci_resource_len(asd_ha->pcidev, i);
+       io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);
+       io_handle->addr  = (void __iomem *) io_handle->start;
+       if (!io_handle->start || !io_handle->len) {
+               asd_printk("couldn't get IO ports for %s\n",
+                          pci_name(asd_ha->pcidev));
+               return -ENODEV;
+       }
+       err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);
+       if (err) {
+               asd_printk("couldn't reserve io space for %s\n",
+                          pci_name(asd_ha->pcidev));
+       }
+
+       return err;
+}
+
+static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
+{
+       pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
+}
+
+static int __devinit asd_map_ha(struct asd_ha_struct *asd_ha)
+{
+       int err;
+       u16 cmd_reg;
+
+       err = pci_read_config_word(asd_ha->pcidev, PCI_COMMAND, &cmd_reg);
+       if (err) {
+               asd_printk("couldn't read command register of %s\n",
+                          pci_name(asd_ha->pcidev));
+               goto Err;
+       }
+
+       err = -ENODEV;
+       if (cmd_reg & PCI_COMMAND_MEMORY) {
+               if ((err = asd_map_memio(asd_ha)))
+                       goto Err;
+       } else if (cmd_reg & PCI_COMMAND_IO) {
+               if ((err = asd_map_ioport(asd_ha)))
+                       goto Err;
+               asd_printk("%s ioport mapped -- upgrade your hardware\n",
+                          pci_name(asd_ha->pcidev));
+       } else {
+               asd_printk("no proper device access to %s\n",
+                          pci_name(asd_ha->pcidev));
+               goto Err;
+       }
+
+       return 0;
+Err:
+       return err;
+}
+
+static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
+{
+       if (asd_ha->iospace)
+               asd_unmap_ioport(asd_ha);
+       else
+               asd_unmap_memio(asd_ha);
+}
+
+static const char *asd_dev_rev[30] = {
+       [0] = "A0",
+       [1] = "A1",
+       [8] = "B0",
+};
+
+static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
+{
+       int err, i;
+
+       err = pci_read_config_byte(asd_ha->pcidev, PCI_REVISION_ID,
+                                  &asd_ha->revision_id);
+       if (err) {
+               asd_printk("couldn't read REVISION ID register of %s\n",
+                          pci_name(asd_ha->pcidev));
+               goto Err;
+       }
+       err = -ENODEV;
+       if (asd_ha->revision_id < AIC9410_DEV_REV_B0) {
+               asd_printk("%s is revision %s (%X), which is not supported\n",
+                          pci_name(asd_ha->pcidev),
+                          asd_dev_rev[asd_ha->revision_id],
+                          asd_ha->revision_id);
+               goto Err;
+       }
+       /* Provide some sane default values. */
+       asd_ha->hw_prof.max_scbs = 512;
+       asd_ha->hw_prof.max_ddbs = 128;
+       asd_ha->hw_prof.num_phys = ASD_MAX_PHYS;
+       /* All phys are enabled, by default. */
+       asd_ha->hw_prof.enabled_phys = 0xFF;
+       for (i = 0; i < ASD_MAX_PHYS; i++) {
+               asd_ha->hw_prof.phy_desc[i].max_sas_lrate = PHY_LINKRATE_3;
+               asd_ha->hw_prof.phy_desc[i].min_sas_lrate = PHY_LINKRATE_1_5;
+               asd_ha->hw_prof.phy_desc[i].max_sata_lrate= PHY_LINKRATE_1_5;
+               asd_ha->hw_prof.phy_desc[i].min_sata_lrate= PHY_LINKRATE_1_5;
+       }
+
+       return 0;
+Err:
+       return err;
+}
+
+static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha)
+{
+       int err = asd_common_setup(asd_ha);
+
+       if (err)
+               return err;
+
+       asd_ha->hw_prof.addr_range = 8;
+       asd_ha->hw_prof.port_name_base = 0;
+       asd_ha->hw_prof.dev_name_base = 8;
+       asd_ha->hw_prof.sata_name_base = 16;
+
+       return 0;
+}
+
+static int __devinit asd_aic9405_setup(struct asd_ha_struct *asd_ha)
+{
+       int err = asd_common_setup(asd_ha);
+
+       if (err)
+               return err;
+
+       asd_ha->hw_prof.addr_range = 4;
+       asd_ha->hw_prof.port_name_base = 0;
+       asd_ha->hw_prof.dev_name_base = 4;
+       asd_ha->hw_prof.sata_name_base = 8;
+
+       return 0;
+}
+
+static ssize_t asd_show_dev_rev(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       asd_dev_rev[asd_ha->revision_id]);
+}
+static DEVICE_ATTR(revision, S_IRUGO, asd_show_dev_rev, NULL);
+
+static ssize_t asd_show_dev_bios_build(struct device *dev,
+                                      struct device_attribute *attr,char *buf)
+{
+       struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+       return snprintf(buf, PAGE_SIZE, "%d\n", asd_ha->hw_prof.bios.bld);
+}
+static DEVICE_ATTR(bios_build, S_IRUGO, asd_show_dev_bios_build, NULL);
+
+static ssize_t asd_show_dev_pcba_sn(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+       return snprintf(buf, PAGE_SIZE, "%s\n", asd_ha->hw_prof.pcba_sn);
+}
+static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
+
+static void asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
+{
+       device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+       device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+       device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+}
+
+static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
+{
+       device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+       device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+       device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+}
+
+/* The first entry, 0, is used for dynamic ids, the rest for devices
+ * we know about.
+ */
+static struct asd_pcidev_struct {
+       const char * name;
+       int (*setup)(struct asd_ha_struct *asd_ha);
+} asd_pcidev_data[] = {
+       /* Id 0 is used for dynamic ids. */
+       { .name  = "Adaptec AIC-94xx SAS/SATA Host Adapter",
+         .setup = asd_aic9410_setup
+       },
+       { .name  = "Adaptec AIC-9410W SAS/SATA Host Adapter",
+         .setup = asd_aic9410_setup
+       },
+       { .name  = "Adaptec AIC-9405W SAS/SATA Host Adapter",
+         .setup = asd_aic9405_setup
+       },
+};
+
+static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha)
+{
+       asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool",
+                                          &asd_ha->pcidev->dev,
+                                          sizeof(struct scb),
+                                          8, 0);
+       if (!asd_ha->scb_pool) {
+               asd_printk("couldn't create scb pool\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/**
+ * asd_free_edbs -- free empty data buffers
+ * asd_ha: pointer to host adapter structure
+ */
+static inline void asd_free_edbs(struct asd_ha_struct *asd_ha)
+{
+       struct asd_seq_data *seq = &asd_ha->seq;
+       int i;
+
+       for (i = 0; i < seq->num_edbs; i++)
+               asd_free_coherent(asd_ha, seq->edb_arr[i]);
+       kfree(seq->edb_arr);
+       seq->edb_arr = NULL;
+}
+
+static inline void asd_free_escbs(struct asd_ha_struct *asd_ha)
+{
+       struct asd_seq_data *seq = &asd_ha->seq;
+       int i;
+
+       for (i = 0; i < seq->num_escbs; i++) {
+               if (!list_empty(&seq->escb_arr[i]->list))
+                       list_del_init(&seq->escb_arr[i]->list);
+
+               asd_ascb_free(seq->escb_arr[i]);
+       }
+       kfree(seq->escb_arr);
+       seq->escb_arr = NULL;
+}
+
+static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha)
+{
+       int i;
+
+       if (asd_ha->hw_prof.ddb_ext)
+               asd_free_coherent(asd_ha, asd_ha->hw_prof.ddb_ext);
+       if (asd_ha->hw_prof.scb_ext)
+               asd_free_coherent(asd_ha, asd_ha->hw_prof.scb_ext);
+
+       if (asd_ha->hw_prof.ddb_bitmap)
+               kfree(asd_ha->hw_prof.ddb_bitmap);
+       asd_ha->hw_prof.ddb_bitmap = NULL;
+
+       for (i = 0; i < ASD_MAX_PHYS; i++) {
+               struct asd_phy *phy = &asd_ha->phys[i];
+
+               asd_free_coherent(asd_ha, phy->id_frm_tok);
+       }
+       if (asd_ha->seq.escb_arr)
+               asd_free_escbs(asd_ha);
+       if (asd_ha->seq.edb_arr)
+               asd_free_edbs(asd_ha);
+       if (asd_ha->hw_prof.ue.area) {
+               kfree(asd_ha->hw_prof.ue.area);
+               asd_ha->hw_prof.ue.area = NULL;
+       }
+       if (asd_ha->seq.tc_index_array) {
+               kfree(asd_ha->seq.tc_index_array);
+               kfree(asd_ha->seq.tc_index_bitmap);
+               asd_ha->seq.tc_index_array = NULL;
+               asd_ha->seq.tc_index_bitmap = NULL;
+       }
+       if (asd_ha->seq.actual_dl) {
+                       asd_free_coherent(asd_ha, asd_ha->seq.actual_dl);
+                       asd_ha->seq.actual_dl = NULL;
+                       asd_ha->seq.dl = NULL;
+       }
+       if (asd_ha->seq.next_scb.vaddr) {
+               dma_pool_free(asd_ha->scb_pool, asd_ha->seq.next_scb.vaddr,
+                             asd_ha->seq.next_scb.dma_handle);
+               asd_ha->seq.next_scb.vaddr = NULL;
+       }
+       dma_pool_destroy(asd_ha->scb_pool);
+       asd_ha->scb_pool = NULL;
+}
+
+kmem_cache_t *asd_dma_token_cache;
+kmem_cache_t *asd_ascb_cache;
+
+static int asd_create_global_caches(void)
+{
+       if (!asd_dma_token_cache) {
+               asd_dma_token_cache
+                       = kmem_cache_create(ASD_DRIVER_NAME "_dma_token",
+                                           sizeof(struct asd_dma_tok),
+                                           0,
+                                           SLAB_HWCACHE_ALIGN,
+                                           NULL, NULL);
+               if (!asd_dma_token_cache) {
+                       asd_printk("couldn't create dma token cache\n");
+                       return -ENOMEM;
+               }
+       }
+
+       if (!asd_ascb_cache) {
+               asd_ascb_cache = kmem_cache_create(ASD_DRIVER_NAME "_ascb",
+                                                  sizeof(struct asd_ascb),
+                                                  0,
+                                                  SLAB_HWCACHE_ALIGN,
+                                                  NULL, NULL);
+               if (!asd_ascb_cache) {
+                       asd_printk("couldn't create ascb cache\n");
+                       goto Err;
+               }
+       }
+
+       return 0;
+Err:
+       kmem_cache_destroy(asd_dma_token_cache);
+       asd_dma_token_cache = NULL;
+       return -ENOMEM;
+}
+
+static void asd_destroy_global_caches(void)
+{
+       if (asd_dma_token_cache)
+               kmem_cache_destroy(asd_dma_token_cache);
+       asd_dma_token_cache = NULL;
+
+       if (asd_ascb_cache)
+               kmem_cache_destroy(asd_ascb_cache);
+       asd_ascb_cache = NULL;
+}
+
+static int asd_register_sas_ha(struct asd_ha_struct *asd_ha)
+{
+       int i;
+       struct asd_sas_phy   **sas_phys =
+               kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_phy), GFP_KERNEL);
+       struct asd_sas_port  **sas_ports =
+               kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_port), GFP_KERNEL);
+
+       if (!sas_phys || !sas_ports) {
+               kfree(sas_phys);
+               kfree(sas_ports);
+               return -ENOMEM;
+       }
+
+       asd_ha->sas_ha.sas_ha_name = (char *) asd_ha->name;
+       asd_ha->sas_ha.lldd_module = THIS_MODULE;
+       asd_ha->sas_ha.sas_addr = &asd_ha->hw_prof.sas_addr[0];
+
+       for (i = 0; i < ASD_MAX_PHYS; i++) {
+               sas_phys[i] = &asd_ha->phys[i].sas_phy;
+               sas_ports[i] = &asd_ha->ports[i];
+       }
+
+       asd_ha->sas_ha.sas_phy = sas_phys;
+       asd_ha->sas_ha.sas_port= sas_ports;
+       asd_ha->sas_ha.num_phys= ASD_MAX_PHYS;
+
+       asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue;
+
+       return sas_register_ha(&asd_ha->sas_ha);
+}
+
+static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
+{
+       int err;
+
+       err = sas_unregister_ha(&asd_ha->sas_ha);
+
+       sas_remove_host(asd_ha->sas_ha.core.shost);
+       scsi_remove_host(asd_ha->sas_ha.core.shost);
+       scsi_host_put(asd_ha->sas_ha.core.shost);
+
+       kfree(asd_ha->sas_ha.sas_phy);
+       kfree(asd_ha->sas_ha.sas_port);
+
+       return err;
+}
+
+static int __devinit asd_pci_probe(struct pci_dev *dev,
+                                  const struct pci_device_id *id)
+{
+       struct asd_pcidev_struct *asd_dev;
+       unsigned asd_id = (unsigned) id->driver_data;
+       struct asd_ha_struct *asd_ha;
+       struct Scsi_Host *shost;
+       int err;
+
+       if (asd_id >= ARRAY_SIZE(asd_pcidev_data)) {
+               asd_printk("wrong driver_data in PCI table\n");
+               return -ENODEV;
+       }
+
+       if ((err = pci_enable_device(dev))) {
+               asd_printk("couldn't enable device %s\n", pci_name(dev));
+               return err;
+       }
+
+       pci_set_master(dev);
+
+       err = -ENOMEM;
+
+       shost = scsi_host_alloc(&aic94xx_sht, sizeof(void *));
+       if (!shost)
+               goto Err;
+
+       asd_dev = &asd_pcidev_data[asd_id];
+
+       asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL);
+       if (!asd_ha) {
+               asd_printk("out of memory\n");
+               goto Err;
+       }
+       asd_ha->pcidev = dev;
+       asd_ha->sas_ha.pcidev = asd_ha->pcidev;
+       asd_ha->sas_ha.lldd_ha = asd_ha;
+
+       asd_ha->name = asd_dev->name;
+       asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
+
+       SHOST_TO_SAS_HA(shost) = &asd_ha->sas_ha;
+       asd_ha->sas_ha.core.shost = shost;
+       shost->transportt = aic94xx_transport_template;
+       shost->max_id = ~0;
+       shost->max_lun = ~0;
+       shost->max_cmd_len = 16;
+
+       err = scsi_add_host(shost, &dev->dev);
+       if (err) {
+               scsi_host_put(shost);
+               goto Err_free;
+       }
+
+
+
+       err = asd_dev->setup(asd_ha);
+       if (err)
+               goto Err_free;
+
+       err = -ENODEV;
+       if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)
+           && !pci_set_consistent_dma_mask(dev, DMA_64BIT_MASK))
+               ;
+       else if (!pci_set_dma_mask(dev, DMA_32BIT_MASK)
+                && !pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK))
+               ;
+       else {
+               asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
+               goto Err_free;
+       }
+
+       pci_set_drvdata(dev, asd_ha);
+
+       err = asd_map_ha(asd_ha);
+       if (err)
+               goto Err_free;
+
+       err = asd_create_ha_caches(asd_ha);
+        if (err)
+               goto Err_unmap;
+
+       err = asd_init_hw(asd_ha);
+       if (err)
+               goto Err_free_cache;
+
+       asd_printk("device %s: SAS addr %llx, PCBA SN %s, %d phys, %d enabled "
+                  "phys, flash %s, BIOS %s%d\n",
+                  pci_name(dev), SAS_ADDR(asd_ha->hw_prof.sas_addr),
+                  asd_ha->hw_prof.pcba_sn, asd_ha->hw_prof.max_phys,
+                  asd_ha->hw_prof.num_phys,
+                  asd_ha->hw_prof.flash.present ? "present" : "not present",
+                  asd_ha->hw_prof.bios.present ? "build " : "not present",
+                  asd_ha->hw_prof.bios.bld);
+
+       if (use_msi)
+               pci_enable_msi(asd_ha->pcidev);
+
+       err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, SA_SHIRQ,
+                         ASD_DRIVER_NAME, asd_ha);
+       if (err) {
+               asd_printk("couldn't get irq %d for %s\n",
+                          asd_ha->pcidev->irq, pci_name(asd_ha->pcidev));
+               goto Err_irq;
+       }
+       asd_enable_ints(asd_ha);
+
+       err = asd_init_post_escbs(asd_ha);
+       if (err) {
+               asd_printk("couldn't post escbs for %s\n",
+                          pci_name(asd_ha->pcidev));
+               goto Err_escbs;
+       }
+       ASD_DPRINTK("escbs posted\n");
+
+       asd_create_dev_attrs(asd_ha);
+
+       err = asd_register_sas_ha(asd_ha);
+       if (err)
+               goto Err_reg_sas;
+
+       err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys);
+       if (err) {
+               asd_printk("coudln't enable phys, err:%d\n", err);
+               goto Err_en_phys;
+       }
+       ASD_DPRINTK("enabled phys\n");
+       /* give the phy enabling interrupt event time to come in (1s
+        * is empirically about all it takes) */
+       ssleep(1);
+       /* Wait for discovery to finish */
+       scsi_flush_work(asd_ha->sas_ha.core.shost);
+
+       return 0;
+Err_en_phys:
+       asd_unregister_sas_ha(asd_ha);
+Err_reg_sas:
+       asd_remove_dev_attrs(asd_ha);
+Err_escbs:
+       asd_disable_ints(asd_ha);
+       free_irq(dev->irq, asd_ha);
+Err_irq:
+       if (use_msi)
+               pci_disable_msi(dev);
+       asd_chip_hardrst(asd_ha);
+Err_free_cache:
+       asd_destroy_ha_caches(asd_ha);
+Err_unmap:
+       asd_unmap_ha(asd_ha);
+Err_free:
+       kfree(asd_ha);
+       scsi_remove_host(shost);
+Err:
+       pci_disable_device(dev);
+       return err;
+}
+
+static void asd_free_queues(struct asd_ha_struct *asd_ha)
+{
+       unsigned long flags;
+       LIST_HEAD(pending);
+       struct list_head *n, *pos;
+
+       spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+       asd_ha->seq.pending = 0;
+       list_splice_init(&asd_ha->seq.pend_q, &pending);
+       spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+       if (!list_empty(&pending))
+               ASD_DPRINTK("Uh-oh! Pending is not empty!\n");
+
+       list_for_each_safe(pos, n, &pending) {
+               struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list);
+               list_del_init(pos);
+               ASD_DPRINTK("freeing from pending\n");
+               asd_ascb_free(ascb);
+       }
+}
+
+static void asd_turn_off_leds(struct asd_ha_struct *asd_ha)
+{
+       u8 phy_mask = asd_ha->hw_prof.enabled_phys;
+       u8 i;
+
+       for_each_phy(phy_mask, phy_mask, i) {
+               asd_turn_led(asd_ha, i, 0);
+               asd_control_led(asd_ha, i, 0);
+       }
+}
+
+static void __devexit asd_pci_remove(struct pci_dev *dev)
+{
+       struct asd_ha_struct *asd_ha = pci_get_drvdata(dev);
+
+       if (!asd_ha)
+               return;
+
+       asd_unregister_sas_ha(asd_ha);
+
+       asd_disable_ints(asd_ha);
+
+       asd_remove_dev_attrs(asd_ha);
+
+       /* XXX more here as needed */
+
+       free_irq(dev->irq, asd_ha);
+       if (use_msi)
+               pci_disable_msi(asd_ha->pcidev);
+       asd_turn_off_leds(asd_ha);
+       asd_chip_hardrst(asd_ha);
+       asd_free_queues(asd_ha);
+       asd_destroy_ha_caches(asd_ha);
+       asd_unmap_ha(asd_ha);
+       kfree(asd_ha);
+       pci_disable_device(dev);
+       return;
+}
+
+static ssize_t asd_version_show(struct device_driver *driver, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION);
+}
+static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL);
+
+static void asd_create_driver_attrs(struct device_driver *driver)
+{
+       driver_create_file(driver, &driver_attr_version);
+}
+
+static void asd_remove_driver_attrs(struct device_driver *driver)
+{
+       driver_remove_file(driver, &driver_attr_version);
+}
+
+static struct sas_domain_function_template aic94xx_transport_functions = {
+       .lldd_port_formed       = asd_update_port_links,
+
+       .lldd_dev_found         = asd_dev_found,
+       .lldd_dev_gone          = asd_dev_gone,
+
+       .lldd_execute_task      = asd_execute_task,
+
+       .lldd_abort_task        = asd_abort_task,
+       .lldd_abort_task_set    = asd_abort_task_set,
+       .lldd_clear_aca         = asd_clear_aca,
+       .lldd_clear_task_set    = asd_clear_task_set,
+       .lldd_I_T_nexus_reset   = NULL,
+       .lldd_lu_reset          = asd_lu_reset,
+       .lldd_query_task        = asd_query_task,
+
+       .lldd_clear_nexus_port  = asd_clear_nexus_port,
+       .lldd_clear_nexus_ha    = asd_clear_nexus_ha,
+
+       .lldd_control_phy       = asd_control_phy,
+};
+
+static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10),
+        0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12),
+        0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E),
+        0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30),
+        0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
+        0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E),
+        0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F),
+        0, 0, 2},
+       {}
+};
+
+MODULE_DEVICE_TABLE(pci, aic94xx_pci_table);
+
+static struct pci_driver aic94xx_pci_driver = {
+       .name           = ASD_DRIVER_NAME,
+       .id_table       = aic94xx_pci_table,
+       .probe          = asd_pci_probe,
+       .remove         = __devexit_p(asd_pci_remove),
+};
+
+static int __init aic94xx_init(void)
+{
+       int err;
+
+
+       asd_printk("%s version %s loaded\n", ASD_DRIVER_DESCRIPTION,
+                  ASD_DRIVER_VERSION);
+
+       err = asd_create_global_caches();
+       if (err)
+               return err;
+
+       aic94xx_transport_template =
+               sas_domain_attach_transport(&aic94xx_transport_functions);
+       if (err)
+               goto out_destroy_caches;
+
+       err = pci_register_driver(&aic94xx_pci_driver);
+       if (err)
+               goto out_release_transport;
+
+       asd_create_driver_attrs(&aic94xx_pci_driver.driver);
+
+       return err;
+
+ out_release_transport:
+       sas_release_transport(aic94xx_transport_template);
+ out_destroy_caches:
+       asd_destroy_global_caches();
+
+       return err;
+}
+
+static void __exit aic94xx_exit(void)
+{
+       asd_remove_driver_attrs(&aic94xx_pci_driver.driver);
+       pci_unregister_driver(&aic94xx_pci_driver);
+       sas_release_transport(aic94xx_transport_template);
+       asd_destroy_global_caches();
+       asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION,
+                  ASD_DRIVER_VERSION);
+}
+
+module_init(aic94xx_init);
+module_exit(aic94xx_exit);
+
+MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");
+MODULE_DESCRIPTION(ASD_DRIVER_DESCRIPTION);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(ASD_DRIVER_VERSION);
diff --git a/drivers/scsi/aic94xx/aic94xx_reg.c b/drivers/scsi/aic94xx/aic94xx_reg.c
new file mode 100644 (file)
index 0000000..f210dac
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Aic94xx SAS/SATA driver register access.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <linux/pci.h>
+#include "aic94xx_reg.h"
+#include "aic94xx.h"
+
+/* Writing to device address space.
+ * Offset comes before value to remind that the operation of
+ * this function is *offs = val.
+ */
+static inline void asd_write_byte(struct asd_ha_struct *asd_ha,
+                                 unsigned long offs, u8 val)
+{
+       if (unlikely(asd_ha->iospace))
+               outb(val,
+                    (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+       else
+               writeb(val, asd_ha->io_handle[0].addr + offs);
+       wmb();
+}
+
+static inline void asd_write_word(struct asd_ha_struct *asd_ha,
+                                 unsigned long offs, u16 val)
+{
+       if (unlikely(asd_ha->iospace))
+               outw(val,
+                    (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+       else
+               writew(val, asd_ha->io_handle[0].addr + offs);
+       wmb();
+}
+
+static inline void asd_write_dword(struct asd_ha_struct *asd_ha,
+                                  unsigned long offs, u32 val)
+{
+       if (unlikely(asd_ha->iospace))
+               outl(val,
+                    (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+       else
+               writel(val, asd_ha->io_handle[0].addr + offs);
+       wmb();
+}
+
+/* Reading from device address space.
+ */
+static inline u8 asd_read_byte(struct asd_ha_struct *asd_ha,
+                              unsigned long offs)
+{
+       u8 val;
+       if (unlikely(asd_ha->iospace))
+               val = inb((unsigned long) asd_ha->io_handle[0].addr
+                         + (offs & 0xFF));
+       else
+               val = readb(asd_ha->io_handle[0].addr + offs);
+       rmb();
+       return val;
+}
+
+static inline u16 asd_read_word(struct asd_ha_struct *asd_ha,
+                               unsigned long offs)
+{
+       u16 val;
+       if (unlikely(asd_ha->iospace))
+               val = inw((unsigned long)asd_ha->io_handle[0].addr
+                         + (offs & 0xFF));
+       else
+               val = readw(asd_ha->io_handle[0].addr + offs);
+       rmb();
+       return val;
+}
+
+static inline u32 asd_read_dword(struct asd_ha_struct *asd_ha,
+                                unsigned long offs)
+{
+       u32 val;
+       if (unlikely(asd_ha->iospace))
+               val = inl((unsigned long) asd_ha->io_handle[0].addr
+                         + (offs & 0xFF));
+       else
+               val = readl(asd_ha->io_handle[0].addr + offs);
+       rmb();
+       return val;
+}
+
+static inline u32 asd_mem_offs_swa(void)
+{
+       return 0;
+}
+
+static inline u32 asd_mem_offs_swc(void)
+{
+       return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
+}
+
+static inline u32 asd_mem_offs_swb(void)
+{
+       return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
+}
+
+/* We know that the register wanted is in the range
+ * of the sliding window.
+ */
+#define ASD_READ_SW(ww, type, ord)                                     \
+static inline type asd_read_##ww##_##ord (struct asd_ha_struct *asd_ha,\
+                                         u32 reg)                     \
+{                                                                      \
+       struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];    \
+       u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
+       return asd_read_##ord (asd_ha, (unsigned long) map_offs);      \
+}
+
+#define ASD_WRITE_SW(ww, type, ord)                                    \
+static inline void asd_write_##ww##_##ord (struct asd_ha_struct *asd_ha,\
+                                 u32 reg, type val)                   \
+{                                                                      \
+       struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];    \
+       u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
+       asd_write_##ord (asd_ha, (unsigned long) map_offs, val);       \
+}
+
+ASD_READ_SW(swa, u8,  byte);
+ASD_READ_SW(swa, u16, word);
+ASD_READ_SW(swa, u32, dword);
+
+ASD_READ_SW(swb, u8,  byte);
+ASD_READ_SW(swb, u16, word);
+ASD_READ_SW(swb, u32, dword);
+
+ASD_READ_SW(swc, u8,  byte);
+ASD_READ_SW(swc, u16, word);
+ASD_READ_SW(swc, u32, dword);
+
+ASD_WRITE_SW(swa, u8,  byte);
+ASD_WRITE_SW(swa, u16, word);
+ASD_WRITE_SW(swa, u32, dword);
+
+ASD_WRITE_SW(swb, u8,  byte);
+ASD_WRITE_SW(swb, u16, word);
+ASD_WRITE_SW(swb, u32, dword);
+
+ASD_WRITE_SW(swc, u8,  byte);
+ASD_WRITE_SW(swc, u16, word);
+ASD_WRITE_SW(swc, u32, dword);
+
+/*
+ * A word about sliding windows:
+ * MBAR0 is divided into sliding windows A, C and B, in that order.
+ * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
+ * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
+ * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
+ * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
+ * See asd_init_sw() in aic94xx_hwi.c
+ *
+ * We map the most common registers we'd access of the internal 4GB
+ * host adapter memory space.  If a register/internal memory location
+ * is wanted which is not mapped, we slide SWB, by paging it,
+ * see asd_move_swb() in aic94xx_reg.c.
+ */
+
+/**
+ * asd_move_swb -- move sliding window B
+ * @asd_ha: pointer to host adapter structure
+ * @reg: register desired to be within range of the new window
+ */
+static inline void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
+{
+       u32 base = reg & ~(MBAR0_SWB_SIZE-1);
+       pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
+       asd_ha->io_handle[0].swb_base = base;
+}
+
+static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
+{
+       struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
+       BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
+       if (io_handle->swa_base <= reg
+           && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
+               asd_write_swa_byte (asd_ha, reg,val);
+       else if (io_handle->swb_base <= reg
+                && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
+               asd_write_swb_byte (asd_ha, reg, val);
+       else if (io_handle->swc_base <= reg
+                && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
+               asd_write_swc_byte (asd_ha, reg, val);
+       else {
+               /* Ok, we have to move SWB */
+               asd_move_swb(asd_ha, reg);
+               asd_write_swb_byte (asd_ha, reg, val);
+       }
+}
+
+#define ASD_WRITE_REG(type, ord)                                  \
+void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
+{                                                                 \
+       struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
+       unsigned long flags;                                      \
+       BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
+       spin_lock_irqsave(&asd_ha->iolock, flags);                \
+       if (io_handle->swa_base <= reg                            \
+           && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
+               asd_write_swa_##ord (asd_ha, reg,val);            \
+       else if (io_handle->swb_base <= reg                       \
+                && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
+               asd_write_swb_##ord (asd_ha, reg, val);           \
+       else if (io_handle->swc_base <= reg                       \
+                && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
+               asd_write_swc_##ord (asd_ha, reg, val);           \
+       else {                                                    \
+               /* Ok, we have to move SWB */                     \
+               asd_move_swb(asd_ha, reg);                        \
+               asd_write_swb_##ord (asd_ha, reg, val);           \
+       }                                                         \
+       spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
+}
+
+ASD_WRITE_REG(u8, byte);
+ASD_WRITE_REG(u16,word);
+ASD_WRITE_REG(u32,dword);
+
+static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
+{
+       struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
+       u8 val;
+       BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
+       if (io_handle->swa_base <= reg
+           && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
+               val = asd_read_swa_byte (asd_ha, reg);
+       else if (io_handle->swb_base <= reg
+                && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
+               val = asd_read_swb_byte (asd_ha, reg);
+       else if (io_handle->swc_base <= reg
+                && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
+               val = asd_read_swc_byte (asd_ha, reg);
+       else {
+               /* Ok, we have to move SWB */
+               asd_move_swb(asd_ha, reg);
+               val = asd_read_swb_byte (asd_ha, reg);
+       }
+       return val;
+}
+
+#define ASD_READ_REG(type, ord)                                   \
+type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg)   \
+{                                                                 \
+       struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
+       type val;                                                 \
+       unsigned long flags;                                      \
+       BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
+       spin_lock_irqsave(&asd_ha->iolock, flags);                \
+       if (io_handle->swa_base <= reg                            \
+           && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
+               val = asd_read_swa_##ord (asd_ha, reg);           \
+       else if (io_handle->swb_base <= reg                       \
+                && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
+               val = asd_read_swb_##ord (asd_ha, reg);           \
+       else if (io_handle->swc_base <= reg                       \
+                && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
+               val = asd_read_swc_##ord (asd_ha, reg);           \
+       else {                                                    \
+               /* Ok, we have to move SWB */                     \
+               asd_move_swb(asd_ha, reg);                        \
+               val = asd_read_swb_##ord (asd_ha, reg);           \
+       }                                                         \
+       spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
+       return val;                                               \
+}
+
+ASD_READ_REG(u8, byte);
+ASD_READ_REG(u16,word);
+ASD_READ_REG(u32,dword);
+
+/**
+ * asd_read_reg_string -- read a string of bytes from io space memory
+ * @asd_ha: pointer to host adapter structure
+ * @dst: pointer to a destination buffer where data will be written to
+ * @offs: start offset (register) to read from
+ * @count: number of bytes to read
+ */
+void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
+                        u32 offs, int count)
+{
+       u8 *p = dst;
+       unsigned long flags;
+
+       spin_lock_irqsave(&asd_ha->iolock, flags);
+       for ( ; count > 0; count--, offs++, p++)
+               *p = __asd_read_reg_byte(asd_ha, offs);
+       spin_unlock_irqrestore(&asd_ha->iolock, flags);
+}
+
+/**
+ * asd_write_reg_string -- write a string of bytes to io space memory
+ * @asd_ha: pointer to host adapter structure
+ * @src: pointer to source buffer where data will be read from
+ * @offs: start offset (register) to write to
+ * @count: number of bytes to write
+ */
+void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
+                         u32 offs, int count)
+{
+       u8 *p = src;
+       unsigned long flags;
+
+       spin_lock_irqsave(&asd_ha->iolock, flags);
+       for ( ; count > 0; count--, offs++, p++)
+               __asd_write_reg_byte(asd_ha, offs, *p);
+       spin_unlock_irqrestore(&asd_ha->iolock, flags);
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_reg.h b/drivers/scsi/aic94xx/aic94xx_reg.h
new file mode 100644 (file)
index 0000000..2279307
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Aic94xx SAS/SATA driver hardware registers definitions.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _AIC94XX_REG_H_
+#define _AIC94XX_REG_H_
+
+#include <asm/io.h>
+#include "aic94xx_hwi.h"
+
+/* Values */
+#define AIC9410_DEV_REV_B0            0x8
+
+/* MBAR0, SWA, SWB, SWC, internal memory space addresses */
+#define REG_BASE_ADDR                 0xB8000000
+#define REG_BASE_ADDR_CSEQCIO         0xB8002000
+#define REG_BASE_ADDR_EXSI            0xB8042800
+
+#define MBAR0_SWA_SIZE                0x58
+extern  u32    MBAR0_SWB_SIZE;
+#define MBAR0_SWC_SIZE                0x8
+
+/* MBAR1, points to On Chip Memory */
+#define OCM_BASE_ADDR                 0xA0000000
+#define OCM_MAX_SIZE                  0x20000
+
+/* Smallest address possible to reference */
+#define ALL_BASE_ADDR                 OCM_BASE_ADDR
+
+/* PCI configuration space registers */
+#define PCI_IOBAR_OFFSET              4
+
+#define PCI_CONF_MBAR1                0x6C
+#define PCI_CONF_MBAR0_SWA            0x70
+#define PCI_CONF_MBAR0_SWB            0x74
+#define PCI_CONF_MBAR0_SWC            0x78
+#define PCI_CONF_MBAR_KEY             0x7C
+#define PCI_CONF_FLSH_BAR             0xB8
+
+#include "aic94xx_reg_def.h"
+
+u8  asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg);
+u16 asd_read_reg_word(struct asd_ha_struct *asd_ha, u32 reg);
+u32 asd_read_reg_dword(struct asd_ha_struct *asd_ha, u32 reg);
+
+void asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val);
+void asd_write_reg_word(struct asd_ha_struct *asd_ha, u32 reg, u16 val);
+void asd_write_reg_dword(struct asd_ha_struct *asd_ha, u32 reg, u32 val);
+
+void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
+                        u32 offs, int count);
+void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
+                         u32 offs, int count);
+
+#define ASD_READ_OCM(type, ord, S)                                    \
+static inline type asd_read_ocm_##ord (struct asd_ha_struct *asd_ha,  \
+                                        u32 offs)                    \
+{                                                                     \
+       struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1];   \
+       type val = read##S (io_handle->addr + (unsigned long) offs);  \
+       rmb();                                                        \
+       return val;                                                   \
+}
+
+ASD_READ_OCM(u8, byte, b);
+ASD_READ_OCM(u16,word, w);
+ASD_READ_OCM(u32,dword,l);
+
+#define ASD_WRITE_OCM(type, ord, S)                                    \
+static inline void asd_write_ocm_##ord (struct asd_ha_struct *asd_ha,  \
+                                        u32 offs, type val)          \
+{                                                                     \
+       struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1];   \
+       write##S (val, io_handle->addr + (unsigned long) offs);       \
+       return;                                                       \
+}
+
+ASD_WRITE_OCM(u8, byte, b);
+ASD_WRITE_OCM(u16,word, w);
+ASD_WRITE_OCM(u32,dword,l);
+
+#define ASD_DDBSITE_READ(type, ord)                                        \
+static inline type asd_ddbsite_read_##ord (struct asd_ha_struct *asd_ha,   \
+                                          u16 ddb_site_no,                \
+                                          u16 offs)                       \
+{                                                                          \
+       asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs);          \
+       asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no);                  \
+       return asd_read_reg_##ord (asd_ha, CTXACCESS);                     \
+}
+
+ASD_DDBSITE_READ(u32, dword);
+ASD_DDBSITE_READ(u16, word);
+
+static inline u8 asd_ddbsite_read_byte(struct asd_ha_struct *asd_ha,
+                                      u16 ddb_site_no,
+                                      u16 offs)
+{
+       if (offs & 1)
+               return asd_ddbsite_read_word(asd_ha, ddb_site_no,
+                                            offs & ~1) >> 8;
+       else
+               return asd_ddbsite_read_word(asd_ha, ddb_site_no,
+                                            offs) & 0xFF;
+}
+
+
+#define ASD_DDBSITE_WRITE(type, ord)                                       \
+static inline void asd_ddbsite_write_##ord (struct asd_ha_struct *asd_ha,  \
+                                       u16 ddb_site_no,                   \
+                                       u16 offs, type val)                \
+{                                                                          \
+       asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs);          \
+       asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no);                  \
+       asd_write_reg_##ord (asd_ha, CTXACCESS, val);                      \
+}
+
+ASD_DDBSITE_WRITE(u32, dword);
+ASD_DDBSITE_WRITE(u16, word);
+
+static inline void asd_ddbsite_write_byte(struct asd_ha_struct *asd_ha,
+                                         u16 ddb_site_no,
+                                         u16 offs, u8 val)
+{
+       u16 base = offs & ~1;
+       u16 rval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base);
+       if (offs & 1)
+               rval = (val << 8) | (rval & 0xFF);
+       else
+               rval = (rval & 0xFF00) | val;
+       asd_ddbsite_write_word(asd_ha, ddb_site_no, base, rval);
+}
+
+
+#define ASD_SCBSITE_READ(type, ord)                                        \
+static inline type asd_scbsite_read_##ord (struct asd_ha_struct *asd_ha,   \
+                                          u16 scb_site_no,                \
+                                          u16 offs)                       \
+{                                                                          \
+       asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs);          \
+       asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no);                  \
+       return asd_read_reg_##ord (asd_ha, CTXACCESS);                     \
+}
+
+ASD_SCBSITE_READ(u32, dword);
+ASD_SCBSITE_READ(u16, word);
+
+static inline u8 asd_scbsite_read_byte(struct asd_ha_struct *asd_ha,
+                                      u16 scb_site_no,
+                                      u16 offs)
+{
+       if (offs & 1)
+               return asd_scbsite_read_word(asd_ha, scb_site_no,
+                                            offs & ~1) >> 8;
+       else
+               return asd_scbsite_read_word(asd_ha, scb_site_no,
+                                            offs) & 0xFF;
+}
+
+
+#define ASD_SCBSITE_WRITE(type, ord)                                       \
+static inline void asd_scbsite_write_##ord (struct asd_ha_struct *asd_ha,  \
+                                       u16 scb_site_no,                   \
+                                       u16 offs, type val)                \
+{                                                                          \
+       asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs);          \
+       asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no);                  \
+       asd_write_reg_##ord (asd_ha, CTXACCESS, val);                      \
+}
+
+ASD_SCBSITE_WRITE(u32, dword);
+ASD_SCBSITE_WRITE(u16, word);
+
+static inline void asd_scbsite_write_byte(struct asd_ha_struct *asd_ha,
+                                         u16 scb_site_no,
+                                         u16 offs, u8 val)
+{
+       u16 base = offs & ~1;
+       u16 rval = asd_scbsite_read_word(asd_ha, scb_site_no, base);
+       if (offs & 1)
+               rval = (val << 8) | (rval & 0xFF);
+       else
+               rval = (rval & 0xFF00) | val;
+       asd_scbsite_write_word(asd_ha, scb_site_no, base, rval);
+}
+
+/**
+ * asd_ddbsite_update_word -- atomically update a word in a ddb site
+ * @asd_ha: pointer to host adapter structure
+ * @ddb_site_no: the DDB site number
+ * @offs: the offset into the DDB
+ * @oldval: old value found in that offset
+ * @newval: the new value to replace it
+ *
+ * This function is used when the sequencers are running and we need to
+ * update a DDB site atomically without expensive pausing and upausing
+ * of the sequencers and accessing the DDB site through the CIO bus.
+ *
+ * Return 0 on success; -EFAULT on parity error; -EAGAIN if the old value
+ * is different than the current value at that offset.
+ */
+static inline int asd_ddbsite_update_word(struct asd_ha_struct *asd_ha,
+                                         u16 ddb_site_no, u16 offs,
+                                         u16 oldval, u16 newval)
+{
+       u8  done;
+       u16 oval = asd_ddbsite_read_word(asd_ha, ddb_site_no, offs);
+       if (oval != oldval)
+               return -EAGAIN;
+       asd_write_reg_word(asd_ha, AOLDDATA, oldval);
+       asd_write_reg_word(asd_ha, ANEWDATA, newval);
+       do {
+               done = asd_read_reg_byte(asd_ha, ATOMICSTATCTL);
+       } while (!(done & ATOMICDONE));
+       if (done & ATOMICERR)
+               return -EFAULT;   /* parity error */
+       else if (done & ATOMICWIN)
+               return 0;         /* success */
+       else
+               return -EAGAIN;   /* oldval different than current value */
+}
+
+static inline int asd_ddbsite_update_byte(struct asd_ha_struct *asd_ha,
+                                         u16 ddb_site_no, u16 offs,
+                                         u8 _oldval, u8 _newval)
+{
+       u16 base = offs & ~1;
+       u16 oval;
+       u16 nval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base);
+       if (offs & 1) {
+               if ((nval >> 8) != _oldval)
+                       return -EAGAIN;
+               nval = (_newval << 8) | (nval & 0xFF);
+               oval = (_oldval << 8) | (nval & 0xFF);
+       } else {
+               if ((nval & 0xFF) != _oldval)
+                       return -EAGAIN;
+               nval = (nval & 0xFF00) | _newval;
+               oval = (nval & 0xFF00) | _oldval;
+       }
+       return asd_ddbsite_update_word(asd_ha, ddb_site_no, base, oval, nval);
+}
+
+static inline void asd_write_reg_addr(struct asd_ha_struct *asd_ha, u32 reg,
+                                     dma_addr_t dma_handle)
+{
+       asd_write_reg_dword(asd_ha, reg,   ASD_BUSADDR_LO(dma_handle));
+       asd_write_reg_dword(asd_ha, reg+4, ASD_BUSADDR_HI(dma_handle));
+}
+
+static inline u32 asd_get_cmdctx_size(struct asd_ha_struct *asd_ha)
+{
+       /* DCHREVISION returns 0, possibly broken */
+       u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE;
+       return ctxmemsize ? 65536 : 32768;
+}
+
+static inline u32 asd_get_devctx_size(struct asd_ha_struct *asd_ha)
+{
+       u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE;
+       return ctxmemsize ? 8192 : 4096;
+}
+
+static inline void asd_disable_ints(struct asd_ha_struct *asd_ha)
+{
+       asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN);
+}
+
+static inline void asd_enable_ints(struct asd_ha_struct *asd_ha)
+{
+       /* Enable COM SAS interrupt on errors, COMSTAT */
+       asd_write_reg_dword(asd_ha, COMSTATEN,
+                           EN_CSBUFPERR | EN_CSERR | EN_OVLYERR);
+       /* Enable DCH SAS CFIFTOERR */
+       asd_write_reg_dword(asd_ha, DCHSTATUS, EN_CFIFTOERR);
+       /* Enable Host Device interrupts */
+       asd_write_reg_dword(asd_ha, CHIMINTEN, SET_CHIMINTEN);
+}
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h
new file mode 100644 (file)
index 0000000..b79f45f
--- /dev/null
@@ -0,0 +1,2398 @@
+/*
+ * Aic94xx SAS/SATA driver hardware registers defintions.
+ *
+ * Copyright (C) 2004 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com>
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * Luben Tuikov: Some register value updates to make it work with the window
+ * agnostic register r/w functions.  Some register corrections, sizes,
+ * etc.
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_reg_def.h#27 $
+ *
+ */
+
+#ifndef _ADP94XX_REG_DEF_H_
+#define _ADP94XX_REG_DEF_H_
+
+/*
+ * Common definitions.
+ */
+#define CSEQ_MODE_PAGE_SIZE    0x200           /* CSEQ mode page size */
+#define LmSEQ_MODE_PAGE_SIZE   0x200           /* LmSEQ mode page size */
+#define LmSEQ_HOST_REG_SIZE    0x4000          /* LmSEQ Host Register size */
+
+/********************* COM_SAS registers definition *************************/
+
+/* The base is REG_BASE_ADDR, defined in aic94xx_reg.h.
+ */
+
+/*
+ * CHIM Registers, Address Range : (0x00-0xFF)
+ */
+#define COMBIST                (REG_BASE_ADDR + 0x00)
+
+/* bits 31:24 */
+#define                L7BLKRST                0x80000000
+#define                L6BLKRST                0x40000000
+#define                L5BLKRST                0x20000000
+#define                L4BLKRST                0x10000000
+#define                L3BLKRST                0x08000000
+#define                L2BLKRST                0x04000000
+#define                L1BLKRST                0x02000000
+#define                L0BLKRST                0x01000000
+#define                LmBLKRST                0xFF000000
+#define LmBLKRST_COMBIST(phyid)                (1 << (24 + phyid))
+
+#define                OCMBLKRST               0x00400000
+#define                CTXMEMBLKRST            0x00200000
+#define                CSEQBLKRST              0x00100000
+#define                EXSIBLKRST              0x00040000
+#define                DPIBLKRST               0x00020000
+#define                DFIFBLKRST              0x00010000
+#define                HARDRST                 0x00000200
+#define                COMBLKRST               0x00000100
+#define                FRCDFPERR               0x00000080
+#define                FRCCIOPERR              0x00000020
+#define                FRCBISTERR              0x00000010
+#define                COMBISTEN               0x00000004
+#define                COMBISTDONE             0x00000002      /* ro */
+#define        COMBISTFAIL             0x00000001      /* ro */
+
+#define COMSTAT                (REG_BASE_ADDR + 0x04)
+
+#define                REQMBXREAD              0x00000040
+#define        RSPMBXAVAIL             0x00000020
+#define        CSBUFPERR               0x00000008
+#define                OVLYERR                 0x00000004
+#define        CSERR                   0x00000002
+#define                OVLYDMADONE             0x00000001
+
+#define                COMSTAT_MASK            (REQMBXREAD | RSPMBXAVAIL | \
+                                        CSBUFPERR | OVLYERR | CSERR |\
+                                        OVLYDMADONE)
+
+#define COMSTATEN      (REG_BASE_ADDR + 0x08)
+
+#define                EN_REQMBXREAD           0x00000040
+#define                EN_RSPMBXAVAIL          0x00000020
+#define                EN_CSBUFPERR            0x00000008
+#define                EN_OVLYERR              0x00000004
+#define                EN_CSERR                0x00000002
+#define                EN_OVLYDONE             0x00000001
+
+#define SCBPRO         (REG_BASE_ADDR + 0x0C)
+
+#define                SCBCONS_MASK            0xFFFF0000
+#define                SCBPRO_MASK             0x0000FFFF
+
+#define CHIMREQMBX     (REG_BASE_ADDR + 0x10)
+
+#define CHIMRSPMBX     (REG_BASE_ADDR + 0x14)
+
+#define CHIMINT                (REG_BASE_ADDR + 0x18)
+
+#define                EXT_INT0                0x00000800
+#define                EXT_INT1                0x00000400
+#define                PORRSTDET               0x00000200
+#define                HARDRSTDET              0x00000100
+#define                DLAVAILQ                0x00000080      /* ro */
+#define                HOSTERR                 0x00000040
+#define                INITERR                 0x00000020
+#define                DEVINT                  0x00000010
+#define                COMINT                  0x00000008
+#define                DEVTIMER2               0x00000004
+#define                DEVTIMER1               0x00000002
+#define                DLAVAIL                 0x00000001
+
+#define                CHIMINT_MASK            (HOSTERR | INITERR | DEVINT | COMINT |\
+                                        DEVTIMER2 | DEVTIMER1 | DLAVAIL)
+
+#define        DEVEXCEPT_MASK          (HOSTERR | INITERR | DEVINT | COMINT)
+
+#define CHIMINTEN      (REG_BASE_ADDR + 0x1C)
+
+#define                RST_EN_EXT_INT1         0x01000000
+#define                RST_EN_EXT_INT0         0x00800000
+#define                RST_EN_HOSTERR          0x00400000
+#define                RST_EN_INITERR          0x00200000
+#define                RST_EN_DEVINT           0x00100000
+#define                RST_EN_COMINT           0x00080000
+#define                RST_EN_DEVTIMER2        0x00040000
+#define                RST_EN_DEVTIMER1        0x00020000
+#define                RST_EN_DLAVAIL          0x00010000
+#define                SET_EN_EXT_INT1         0x00000100
+#define                SET_EN_EXT_INT0         0x00000080
+#define                SET_EN_HOSTERR          0x00000040
+#define                SET_EN_INITERR          0x00000020
+#define                SET_EN_DEVINT           0x00000010
+#define                SET_EN_COMINT           0x00000008
+#define                SET_EN_DEVTIMER2        0x00000004
+#define                SET_EN_DEVTIMER1        0x00000002
+#define                SET_EN_DLAVAIL          0x00000001
+
+#define                RST_CHIMINTEN           (RST_EN_HOSTERR | RST_EN_INITERR | \
+                                        RST_EN_DEVINT | RST_EN_COMINT | \
+                                        RST_EN_DEVTIMER2 | RST_EN_DEVTIMER1 |\
+                                        RST_EN_DLAVAIL)
+
+#define                SET_CHIMINTEN           (SET_EN_HOSTERR | SET_EN_INITERR |\
+                                        SET_EN_DEVINT | SET_EN_COMINT |\
+                                        SET_EN_DLAVAIL)
+
+#define OVLYDMACTL     (REG_BASE_ADDR + 0x20)
+
+#define                OVLYADR_MASK            0x07FF0000
+#define                OVLYLSEQ_MASK           0x0000FF00
+#define                OVLYCSEQ                0x00000080
+#define                OVLYHALTERR             0x00000040
+#define                PIOCMODE                0x00000020
+#define                RESETOVLYDMA            0x00000008      /* wo */
+#define                STARTOVLYDMA            0x00000004
+#define                STOPOVLYDMA             0x00000002      /* wo */
+#define                OVLYDMAACT              0x00000001      /* ro */
+
+#define OVLYDMACNT     (REG_BASE_ADDR + 0x24)
+
+#define                OVLYDOMAIN1             0x20000000      /* ro */
+#define                OVLYDOMAIN0             0x10000000
+#define                OVLYBUFADR_MASK         0x007F0000
+#define                OVLYDMACNT_MASK         0x00003FFF
+
+#define OVLYDMAADR     (REG_BASE_ADDR + 0x28)
+
+#define DMAERR         (REG_BASE_ADDR + 0x30)
+
+#define                OVLYERRSTAT_MASK        0x0000FF00      /* ro */
+#define                CSERRSTAT_MASK          0x000000FF      /* ro */
+
+#define SPIODATA       (REG_BASE_ADDR + 0x34)
+
+/* 0x38 - 0x3C are reserved  */
+
+#define T1CNTRLR       (REG_BASE_ADDR + 0x40)
+
+#define                T1DONE                  0x00010000      /* ro */
+#define                TIMER64                 0x00000400
+#define                T1ENABLE                0x00000200
+#define                T1RELOAD                0x00000100
+#define                T1PRESCALER_MASK        0x00000003
+
+#define        T1CMPR          (REG_BASE_ADDR + 0x44)
+
+#define T1CNTR         (REG_BASE_ADDR + 0x48)
+
+#define T2CNTRLR       (REG_BASE_ADDR + 0x4C)
+
+#define                T2DONE                  0x00010000      /* ro */
+#define                T2ENABLE                0x00000200
+#define                T2RELOAD                0x00000100
+#define                T2PRESCALER_MASK        0x00000003
+
+#define        T2CMPR          (REG_BASE_ADDR + 0x50)
+
+#define T2CNTR         (REG_BASE_ADDR + 0x54)
+
+/* 0x58h - 0xFCh are reserved */
+
+/*
+ * DCH_SAS Registers, Address Range : (0x800-0xFFF)
+ */
+#define CMDCTXBASE     (REG_BASE_ADDR + 0x800)
+
+#define DEVCTXBASE     (REG_BASE_ADDR + 0x808)
+
+#define CTXDOMAIN      (REG_BASE_ADDR + 0x810)
+
+#define                DEVCTXDOMAIN1           0x00000008      /* ro */
+#define                DEVCTXDOMAIN0           0x00000004
+#define                CMDCTXDOMAIN1           0x00000002      /* ro */
+#define                CMDCTXDOMAIN0           0x00000001
+
+#define DCHCTL         (REG_BASE_ADDR + 0x814)
+
+#define                OCMBISTREPAIR           0x00080000
+#define                OCMBISTEN               0x00040000
+#define                OCMBISTDN               0x00020000      /* ro */
+#define                OCMBISTFAIL             0x00010000      /* ro */
+#define                DDBBISTEN               0x00004000
+#define                DDBBISTDN               0x00002000      /* ro */
+#define                DDBBISTFAIL             0x00001000      /* ro */
+#define                SCBBISTEN               0x00000400
+#define                SCBBISTDN               0x00000200      /* ro */
+#define                SCBBISTFAIL             0x00000100      /* ro */
+
+#define                MEMSEL_MASK             0x000000E0
+#define                MEMSEL_CCM_LSEQ         0x00000000
+#define                MEMSEL_CCM_IOP          0x00000020
+#define                MEMSEL_CCM_SASCTL       0x00000040
+#define                MEMSEL_DCM_LSEQ         0x00000060
+#define                MEMSEL_DCM_IOP          0x00000080
+#define                MEMSEL_OCM              0x000000A0
+
+#define                FRCERR                  0x00000010
+#define                AUTORLS                 0x00000001
+
+#define DCHREVISION    (REG_BASE_ADDR + 0x818)
+
+#define                DCHREVISION_MASK        0x000000FF
+
+#define DCHSTATUS      (REG_BASE_ADDR + 0x81C)
+
+#define                EN_CFIFTOERR            0x00020000
+#define                CFIFTOERR               0x00000200
+#define                CSEQINT                 0x00000100      /* ro */
+#define                LSEQ7INT                0x00000080      /* ro */
+#define                LSEQ6INT                0x00000040      /* ro */
+#define                LSEQ5INT                0x00000020      /* ro */
+#define                LSEQ4INT                0x00000010      /* ro */
+#define                LSEQ3INT                0x00000008      /* ro */
+#define                LSEQ2INT                0x00000004      /* ro */
+#define                LSEQ1INT                0x00000002      /* ro */
+#define                LSEQ0INT                0x00000001      /* ro */
+
+#define                LSEQINT_MASK            (LSEQ7INT | LSEQ6INT | LSEQ5INT |\
+                                        LSEQ4INT | LSEQ3INT | LSEQ2INT |\
+                                        LSEQ1INT | LSEQ0INT)
+
+#define DCHDFIFDEBUG   (REG_BASE_ADDR + 0x820)
+#define                ENFAIRMST               0x00FF0000
+#define                DISWRMST9               0x00000200
+#define                DISWRMST8               0x00000100
+#define                DISRDMST                0x000000FF
+
+#define ATOMICSTATCTL  (REG_BASE_ADDR + 0x824)
+/* 8 bit wide */
+#define                AUTOINC                 0x80
+#define                ATOMICERR               0x04
+#define                ATOMICWIN               0x02
+#define                ATOMICDONE              0x01
+
+
+#define ALTCIOADR      (REG_BASE_ADDR + 0x828)
+/* 16 bit; bits 8:0 define CIO addr space of CSEQ */
+
+#define ASCBPTR                (REG_BASE_ADDR + 0x82C)
+/* 16 bit wide */
+
+#define ADDBPTR                (REG_BASE_ADDR + 0x82E)
+/* 16 bit wide */
+
+#define ANEWDATA       (REG_BASE_ADDR + 0x830)
+/* 16 bit */
+
+#define AOLDDATA       (REG_BASE_ADDR + 0x834)
+/* 16 bit */
+
+#define CTXACCESS      (REG_BASE_ADDR + 0x838)
+/* 32 bit */
+
+/* 0x83Ch - 0xFFCh are reserved */
+
+/*
+ * ARP2 External Processor Registers, Address Range : (0x00-0x1F)
+ */
+#define ARP2CTL                0x00
+
+#define                FRCSCRPERR              0x00040000
+#define                FRCARP2PERR             0x00020000
+#define                FRCARP2ILLOPC           0x00010000
+#define                ENWAITTO                0x00008000
+#define                PERRORDIS               0x00004000
+#define                FAILDIS                 0x00002000
+#define                CIOPERRDIS              0x00001000
+#define                BREAKEN3                0x00000800
+#define                BREAKEN2                0x00000400
+#define                BREAKEN1                0x00000200
+#define                BREAKEN0                0x00000100
+#define                EPAUSE                  0x00000008
+#define                PAUSED                  0x00000004      /* ro */
+#define                STEP                    0x00000002
+#define                ARP2RESET               0x00000001      /* wo */
+
+#define ARP2INT                0x04
+
+#define                HALTCODE_MASK           0x00FF0000      /* ro */
+#define                ARP2WAITTO              0x00000100
+#define                ARP2HALTC               0x00000080
+#define                ARP2ILLOPC              0x00000040
+#define                ARP2PERR                0x00000020
+#define                ARP2CIOPERR             0x00000010
+#define                ARP2BREAK3              0x00000008
+#define                ARP2BREAK2              0x00000004
+#define                ARP2BREAK1              0x00000002
+#define                ARP2BREAK0              0x00000001
+
+#define ARP2INTEN      0x08
+
+#define                EN_ARP2WAITTO           0x00000100
+#define                EN_ARP2HALTC            0x00000080
+#define                EN_ARP2ILLOPC           0x00000040
+#define                EN_ARP2PERR             0x00000020
+#define                EN_ARP2CIOPERR          0x00000010
+#define                EN_ARP2BREAK3           0x00000008
+#define                EN_ARP2BREAK2           0x00000004
+#define                EN_ARP2BREAK1           0x00000002
+#define                EN_ARP2BREAK0           0x00000001
+
+#define ARP2BREAKADR01 0x0C
+
+#define                BREAKADR1_MASK          0x0FFF0000
+#define                BREAKADR0_MASK          0x00000FFF
+
+#define        ARP2BREAKADR23  0x10
+
+#define                BREAKADR3_MASK          0x0FFF0000
+#define                BREAKADR2_MASK          0x00000FFF
+
+/* 0x14h - 0x1Ch are reserved */
+
+/*
+ * ARP2 Registers, Address Range : (0x00-0x1F)
+ * The definitions have the same address offset for CSEQ and LmSEQ
+ * CIO Bus Registers.
+ */
+#define MODEPTR                0x00
+
+#define                DSTMODE                 0xF0
+#define                SRCMODE                 0x0F
+
+#define ALTMODE                0x01
+
+#define                ALTDMODE                0xF0
+#define                ALTSMODE                0x0F
+
+#define ATOMICXCHG     0x02
+
+#define FLAG           0x04
+
+#define                INTCODE_MASK            0xF0
+#define                ALTMODEV2               0x04
+#define                CARRY_INT               0x02
+#define                CARRY                   0x01
+
+#define ARP2INTCTL     0x05
+
+#define        PAUSEDIS                0x80
+#define                RSTINTCTL               0x40
+#define                POPALTMODE              0x08
+#define                ALTMODEV                0x04
+#define                INTMASK                 0x02
+#define                IRET                    0x01
+
+#define STACK          0x06
+
+#define FUNCTION1      0x07
+
+#define PRGMCNT                0x08
+
+#define ACCUM          0x0A
+
+#define SINDEX         0x0C
+
+#define DINDEX         0x0E
+
+#define ALLONES                0x10
+
+#define ALLZEROS       0x11
+
+#define SINDIR         0x12
+
+#define DINDIR         0x13
+
+#define JUMLDIR                0x14
+
+#define ARP2HALTCODE   0x15
+
+#define CURRADDR       0x16
+
+#define LASTADDR       0x18
+
+#define NXTLADDR       0x1A
+
+#define DBGPORTPTR     0x1C
+
+#define DBGPORT                0x1D
+
+/*
+ * CIO Registers.
+ * The definitions have the same address offset for CSEQ and LmSEQ
+ * CIO Bus Registers.
+ */
+#define MnSCBPTR       0x20
+
+#define MnDDBPTR       0x22
+
+#define SCRATCHPAGE    0x24
+
+#define MnSCRATCHPAGE  0x25
+
+#define SCRATCHPAGESV  0x26
+
+#define MnSCRATCHPAGESV        0x27
+
+#define MnDMAERRS      0x46
+
+#define MnSGDMAERRS    0x47
+
+#define MnSGBUF                0x53
+
+#define MnSGDMASTAT    0x5b
+
+#define MnDDMACTL      0x5c    /* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDDMASTAT     0x5d    /* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDDMAMODE     0x5e    /* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDMAENG       0x60
+
+#define MnPIPECTL      0x61
+
+#define MnSGBADR       0x65
+
+#define MnSCB_SITE     0x100
+
+#define MnDDB_SITE     0x180
+
+/*
+ * The common definitions below have the same address offset for both
+ * CSEQ and LmSEQ.
+ */
+#define BISTCTL0       0x4C
+
+#define BISTCTL1       0x50
+
+#define MAPPEDSCR      0x800
+
+/*
+ * CSEQ Host Register, Address Range : (0x000-0xFFC)
+ */
+#define CSEQ_HOST_REG_BASE_ADR         0xB8001000
+
+#define CARP2CTL                       (CSEQ_HOST_REG_BASE_ADR + ARP2CTL)
+
+#define CARP2INT                       (CSEQ_HOST_REG_BASE_ADR + ARP2INT)
+
+#define CARP2INTEN                     (CSEQ_HOST_REG_BASE_ADR + ARP2INTEN)
+
+#define CARP2BREAKADR01                        (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR01)
+
+#define CARP2BREAKADR23                        (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR23)
+
+#define CBISTCTL                       (CSEQ_HOST_REG_BASE_ADR + BISTCTL1)
+
+#define                CSEQRAMBISTEN           0x00000040
+#define                CSEQRAMBISTDN           0x00000020      /* ro */
+#define                CSEQRAMBISTFAIL         0x00000010      /* ro */
+#define                CSEQSCRBISTEN           0x00000004
+#define                CSEQSCRBISTDN           0x00000002      /* ro */
+#define                CSEQSCRBISTFAIL         0x00000001      /* ro */
+
+#define CMAPPEDSCR                     (CSEQ_HOST_REG_BASE_ADR + MAPPEDSCR)
+
+/*
+ * CSEQ CIO Bus Registers, Address Range : (0x0000-0x1FFC)
+ * 16 modes, each mode is 512 bytes.
+ * Unless specified, the register should valid for all modes.
+ */
+#define CSEQ_CIO_REG_BASE_ADR          REG_BASE_ADDR_CSEQCIO
+
+#define CSEQm_CIO_REG(Mode, Reg) \
+               (CSEQ_CIO_REG_BASE_ADR  + \
+               ((u32) (Mode) * CSEQ_MODE_PAGE_SIZE) + (u32) (Reg))
+
+#define CMODEPTR       (CSEQ_CIO_REG_BASE_ADR + MODEPTR)
+
+#define CALTMODE       (CSEQ_CIO_REG_BASE_ADR + ALTMODE)
+
+#define CATOMICXCHG    (CSEQ_CIO_REG_BASE_ADR + ATOMICXCHG)
+
+#define CFLAG          (CSEQ_CIO_REG_BASE_ADR + FLAG)
+
+#define CARP2INTCTL    (CSEQ_CIO_REG_BASE_ADR + ARP2INTCTL)
+
+#define CSTACK         (CSEQ_CIO_REG_BASE_ADR + STACK)
+
+#define CFUNCTION1     (CSEQ_CIO_REG_BASE_ADR + FUNCTION1)
+
+#define CPRGMCNT       (CSEQ_CIO_REG_BASE_ADR + PRGMCNT)
+
+#define CACCUM         (CSEQ_CIO_REG_BASE_ADR + ACCUM)
+
+#define CSINDEX                (CSEQ_CIO_REG_BASE_ADR + SINDEX)
+
+#define CDINDEX                (CSEQ_CIO_REG_BASE_ADR + DINDEX)
+
+#define CALLONES       (CSEQ_CIO_REG_BASE_ADR + ALLONES)
+
+#define CALLZEROS      (CSEQ_CIO_REG_BASE_ADR + ALLZEROS)
+
+#define CSINDIR                (CSEQ_CIO_REG_BASE_ADR + SINDIR)
+
+#define CDINDIR                (CSEQ_CIO_REG_BASE_ADR + DINDIR)
+
+#define CJUMLDIR       (CSEQ_CIO_REG_BASE_ADR + JUMLDIR)
+
+#define CARP2HALTCODE  (CSEQ_CIO_REG_BASE_ADR + ARP2HALTCODE)
+
+#define CCURRADDR      (CSEQ_CIO_REG_BASE_ADR + CURRADDR)
+
+#define CLASTADDR      (CSEQ_CIO_REG_BASE_ADR + LASTADDR)
+
+#define CNXTLADDR      (CSEQ_CIO_REG_BASE_ADR + NXTLADDR)
+
+#define CDBGPORTPTR    (CSEQ_CIO_REG_BASE_ADR + DBGPORTPTR)
+
+#define CDBGPORT       (CSEQ_CIO_REG_BASE_ADR + DBGPORT)
+
+#define CSCRATCHPAGE   (CSEQ_CIO_REG_BASE_ADR + SCRATCHPAGE)
+
+#define CMnSCBPTR(Mode)       CSEQm_CIO_REG(Mode, MnSCBPTR)
+
+#define CMnDDBPTR(Mode)       CSEQm_CIO_REG(Mode, MnDDBPTR)
+
+#define CMnSCRATCHPAGE(Mode)           CSEQm_CIO_REG(Mode, MnSCRATCHPAGE)
+
+#define CLINKCON       (CSEQ_CIO_REG_BASE_ADR + 0x28)
+
+#define        CCIOAACESS      (CSEQ_CIO_REG_BASE_ADR + 0x2C)
+
+/* mode 0-7 */
+#define MnREQMBX 0x30
+#define CMnREQMBX(Mode)                        CSEQm_CIO_REG(Mode, 0x30)
+
+/* mode 8 */
+#define CSEQCON                                CSEQm_CIO_REG(8, 0x30)
+
+/* mode 0-7 */
+#define MnRSPMBX 0x34
+#define CMnRSPMBX(Mode)                        CSEQm_CIO_REG(Mode, 0x34)
+
+/* mode 8 */
+#define CSEQCOMCTL                     CSEQm_CIO_REG(8, 0x34)
+
+/* mode 8 */
+#define CSEQCOMSTAT                    CSEQm_CIO_REG(8, 0x35)
+
+/* mode 8 */
+#define CSEQCOMINTEN                   CSEQm_CIO_REG(8, 0x36)
+
+/* mode 8 */
+#define CSEQCOMDMACTL                  CSEQm_CIO_REG(8, 0x37)
+
+#define                CSHALTERR               0x10
+#define                RESETCSDMA              0x08            /* wo */
+#define                STARTCSDMA              0x04
+#define                STOPCSDMA               0x02            /* wo */
+#define                CSDMAACT                0x01            /* ro */
+
+/* mode 0-7 */
+#define MnINT 0x38
+#define CMnINT(Mode)                   CSEQm_CIO_REG(Mode, 0x38)
+
+#define                CMnREQMBXE              0x02
+#define                CMnRSPMBXF              0x01
+#define                CMnINT_MASK             0x00000003
+
+/* mode 8 */
+#define CSEQREQMBX                     CSEQm_CIO_REG(8, 0x38)
+
+/* mode 0-7 */
+#define MnINTEN 0x3C
+#define CMnINTEN(Mode)                 CSEQm_CIO_REG(Mode, 0x3C)
+
+#define                EN_CMnRSPMBXF           0x01
+
+/* mode 8 */
+#define CSEQRSPMBX                     CSEQm_CIO_REG(8, 0x3C)
+
+/* mode 8 */
+#define CSDMAADR                       CSEQm_CIO_REG(8, 0x40)
+
+/* mode 8 */
+#define CSDMACNT                       CSEQm_CIO_REG(8, 0x48)
+
+/* mode 8 */
+#define CSEQDLCTL                      CSEQm_CIO_REG(8, 0x4D)
+
+#define                DONELISTEND             0x10
+#define        DONELISTSIZE_MASK       0x0F
+#define                DONELISTSIZE_8ELEM      0x01
+#define                DONELISTSIZE_16ELEM     0x02
+#define                DONELISTSIZE_32ELEM     0x03
+#define                DONELISTSIZE_64ELEM     0x04
+#define                DONELISTSIZE_128ELEM    0x05
+#define                DONELISTSIZE_256ELEM    0x06
+#define                DONELISTSIZE_512ELEM    0x07
+#define                DONELISTSIZE_1024ELEM   0x08
+#define                DONELISTSIZE_2048ELEM   0x09
+#define                DONELISTSIZE_4096ELEM   0x0A
+#define                DONELISTSIZE_8192ELEM   0x0B
+#define                DONELISTSIZE_16384ELEM  0x0C
+
+/* mode 8 */
+#define CSEQDLOFFS                     CSEQm_CIO_REG(8, 0x4E)
+
+/* mode 11 */
+#define CM11INTVEC0                    CSEQm_CIO_REG(11, 0x50)
+
+/* mode 11 */
+#define CM11INTVEC1                    CSEQm_CIO_REG(11, 0x52)
+
+/* mode 11 */
+#define CM11INTVEC2                    CSEQm_CIO_REG(11, 0x54)
+
+#define        CCONMSK                         (CSEQ_CIO_REG_BASE_ADR + 0x60)
+
+#define        CCONEXIST                       (CSEQ_CIO_REG_BASE_ADR + 0x61)
+
+#define        CCONMODE                        (CSEQ_CIO_REG_BASE_ADR + 0x62)
+
+#define CTIMERCALC                     (CSEQ_CIO_REG_BASE_ADR + 0x64)
+
+#define CINTDIS                                (CSEQ_CIO_REG_BASE_ADR + 0x68)
+
+/* mode 8, 32x32 bits, 128 bytes of mapped buffer */
+#define CSBUFFER                       CSEQm_CIO_REG(8, 0x80)
+
+#define        CSCRATCH                        (CSEQ_CIO_REG_BASE_ADR + 0x1C0)
+
+/* mode 0-8 */
+#define CMnSCRATCH(Mode)               CSEQm_CIO_REG(Mode, 0x1E0)
+
+/*
+ * CSEQ Mapped Instruction RAM Page, Address Range : (0x0000-0x1FFC)
+ */
+#define CSEQ_RAM_REG_BASE_ADR          0xB8004000
+
+/*
+ * The common definitions below have the same address offset for all the Link
+ * sequencers.
+ */
+#define MODECTL                0x40
+
+#define DBGMODE                0x44
+
+#define CONTROL                0x48
+#define LEDTIMER               0x00010000
+#define LEDTIMERS_10us         0x00000000
+#define LEDTIMERS_1ms          0x00000800
+#define LEDTIMERS_100ms                0x00001000
+#define LEDMODE_TXRX           0x00000000
+#define LEDMODE_CONNECTED      0x00000200
+#define LEDPOL                 0x00000100
+
+#define LSEQRAM                0x1000
+
+/*
+ * LmSEQ Host Registers, Address Range : (0x0000-0x3FFC)
+ */
+#define LSEQ0_HOST_REG_BASE_ADR                0xB8020000
+#define LSEQ1_HOST_REG_BASE_ADR                0xB8024000
+#define LSEQ2_HOST_REG_BASE_ADR                0xB8028000
+#define LSEQ3_HOST_REG_BASE_ADR                0xB802C000
+#define LSEQ4_HOST_REG_BASE_ADR                0xB8030000
+#define LSEQ5_HOST_REG_BASE_ADR                0xB8034000
+#define LSEQ6_HOST_REG_BASE_ADR                0xB8038000
+#define LSEQ7_HOST_REG_BASE_ADR                0xB803C000
+
+#define LmARP2CTL(LinkNum)             (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       ARP2CTL)
+
+#define LmARP2INT(LinkNum)             (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       ARP2INT)
+
+#define LmARP2INTEN(LinkNum)           (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       ARP2INTEN)
+
+#define LmDBGMODE(LinkNum)             (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       DBGMODE)
+
+#define LmCONTROL(LinkNum)             (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       CONTROL)
+
+#define LmARP2BREAKADR01(LinkNum)      (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       ARP2BREAKADR01)
+
+#define LmARP2BREAKADR23(LinkNum)      (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       ARP2BREAKADR23)
+
+#define LmMODECTL(LinkNum)             (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       MODECTL)
+
+#define                LmAUTODISCI             0x08000000
+#define                LmDSBLBITLT             0x04000000
+#define                LmDSBLANTT              0x02000000
+#define                LmDSBLCRTT              0x01000000
+#define                LmDSBLCONT              0x00000100
+#define                LmPRIMODE               0x00000080
+#define                LmDSBLHOLD              0x00000040
+#define                LmDISACK                0x00000020
+#define                LmBLIND48               0x00000010
+#define                LmRCVMODE_MASK          0x0000000C
+#define                LmRCVMODE_PLD           0x00000000
+#define                LmRCVMODE_HPC           0x00000004
+
+#define LmDBGMODE(LinkNum)             (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       DBGMODE)
+
+#define                LmFRCPERR               0x80000000
+#define                LmMEMSEL_MASK           0x30000000
+#define                LmFRCRBPERR             0x00000000
+#define                LmFRCTBPERR             0x10000000
+#define                LmFRCSGBPERR            0x20000000
+#define                LmFRCARBPERR            0x30000000
+#define                LmRCVIDW                0x00080000
+#define                LmINVDWERR              0x00040000
+#define                LmRCVDISP               0x00004000
+#define                LmDISPERR               0x00002000
+#define                LmDSBLDSCR              0x00000800
+#define                LmDSBLSCR               0x00000400
+#define                LmFRCNAK                0x00000200
+#define                LmFRCROFS               0x00000100
+#define                LmFRCCRC                0x00000080
+#define                LmFRMTYPE_MASK          0x00000070
+#define                LmSG_DATA               0x00000000
+#define                LmSG_COMMAND            0x00000010
+#define                LmSG_TASK               0x00000020
+#define                LmSG_TGTXFER            0x00000030
+#define                LmSG_RESPONSE           0x00000040
+#define                LmSG_IDENADDR           0x00000050
+#define                LmSG_OPENADDR           0x00000060
+#define                LmDISCRCGEN             0x00000008
+#define                LmDISCRCCHK             0x00000004
+#define                LmSSXMTFRM              0x00000002
+#define                LmSSRCVFRM              0x00000001
+
+#define LmCONTROL(LinkNum)             (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       CONTROL)
+
+#define                LmSTEPXMTFRM            0x00000002
+#define                LmSTEPRCVFRM            0x00000001
+
+#define LmBISTCTL0(LinkNum)            (LSEQ0_HOST_REG_BASE_ADR +        \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+                                       BISTCTL0)
+
+#define                ARBBISTEN               0x40000000
+#define                ARBBISTDN               0x20000000      /* ro */
+#define                ARBBISTFAIL             0x10000000      /* ro */
+#define                TBBISTEN                0x00000400
+#define                TBBISTDN                0x00000200      /* ro */
+#define                TBBISTFAIL              0x00000100      /* ro */
+#define                RBBISTEN                0x00000040
+#define                RBBISTDN                0x00000020      /* ro */
+#define                RBBISTFAIL              0x00000010      /* ro */
+#define                SGBISTEN                0x00000004
+#define                SGBISTDN                0x00000002      /* ro */
+#define                SGBISTFAIL              0x00000001      /* ro */
+
+#define LmBISTCTL1(LinkNum)            (LSEQ0_HOST_REG_BASE_ADR +       \
+                                       ((LinkNum)*LmSEQ_HOST_REG_SIZE) +\
+                                       BISTCTL1)
+
+#define                LmRAMPAGE1              0x00000200
+#define                LmRAMPAGE0              0x00000100
+#define                LmIMEMBISTEN            0x00000040
+#define                LmIMEMBISTDN            0x00000020      /* ro */
+#define                LmIMEMBISTFAIL          0x00000010      /* ro */
+#define                LmSCRBISTEN             0x00000004
+#define                LmSCRBISTDN             0x00000002      /* ro */
+#define                LmSCRBISTFAIL           0x00000001      /* ro */
+#define                LmRAMPAGE               (LmRAMPAGE1 + LmRAMPAGE0)
+#define                LmRAMPAGE_LSHIFT        0x8
+
+#define LmSCRATCH(LinkNum)             (LSEQ0_HOST_REG_BASE_ADR +         \
+                                       ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\
+                                       MAPPEDSCR)
+
+#define LmSEQRAM(LinkNum)              (LSEQ0_HOST_REG_BASE_ADR +         \
+                                       ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\
+                                       LSEQRAM)
+
+/*
+ * LmSEQ CIO Bus Register, Address Range : (0x0000-0xFFC)
+ * 8 modes, each mode is 512 bytes.
+ * Unless specified, the register should valid for all modes.
+ */
+#define LmSEQ_CIOBUS_REG_BASE          0x2000
+
+#define  LmSEQ_PHY_BASE(Mode, LinkNum) \
+               (LSEQ0_HOST_REG_BASE_ADR + \
+               (LmSEQ_HOST_REG_SIZE * (u32) (LinkNum)) + \
+               LmSEQ_CIOBUS_REG_BASE + \
+               ((u32) (Mode) * LmSEQ_MODE_PAGE_SIZE))
+
+#define  LmSEQ_PHY_REG(Mode, LinkNum, Reg) \
+                 (LmSEQ_PHY_BASE(Mode, LinkNum) + (u32) (Reg))
+
+#define LmMODEPTR(LinkNum)             LmSEQ_PHY_REG(0, LinkNum, MODEPTR)
+
+#define LmALTMODE(LinkNum)             LmSEQ_PHY_REG(0, LinkNum, ALTMODE)
+
+#define LmATOMICXCHG(LinkNum)          LmSEQ_PHY_REG(0, LinkNum, ATOMICXCHG)
+
+#define LmFLAG(LinkNum)                        LmSEQ_PHY_REG(0, LinkNum, FLAG)
+
+#define LmARP2INTCTL(LinkNum)          LmSEQ_PHY_REG(0, LinkNum, ARP2INTCTL)
+
+#define LmSTACK(LinkNum)               LmSEQ_PHY_REG(0, LinkNum, STACK)
+
+#define LmFUNCTION1(LinkNum)           LmSEQ_PHY_REG(0, LinkNum, FUNCTION1)
+
+#define LmPRGMCNT(LinkNum)             LmSEQ_PHY_REG(0, LinkNum, PRGMCNT)
+
+#define LmACCUM(LinkNum)               LmSEQ_PHY_REG(0, LinkNum, ACCUM)
+
+#define LmSINDEX(LinkNum)              LmSEQ_PHY_REG(0, LinkNum, SINDEX)
+
+#define LmDINDEX(LinkNum)              LmSEQ_PHY_REG(0, LinkNum, DINDEX)
+
+#define LmALLONES(LinkNum)             LmSEQ_PHY_REG(0, LinkNum, ALLONES)
+
+#define LmALLZEROS(LinkNum)            LmSEQ_PHY_REG(0, LinkNum, ALLZEROS)
+
+#define LmSINDIR(LinkNum)              LmSEQ_PHY_REG(0, LinkNum, SINDIR)
+
+#define LmDINDIR(LinkNum)              LmSEQ_PHY_REG(0, LinkNum, DINDIR)
+
+#define LmJUMLDIR(LinkNum)             LmSEQ_PHY_REG(0, LinkNum, JUMLDIR)
+
+#define LmARP2HALTCODE(LinkNum)                LmSEQ_PHY_REG(0, LinkNum, ARP2HALTCODE)
+
+#define LmCURRADDR(LinkNum)            LmSEQ_PHY_REG(0, LinkNum, CURRADDR)
+
+#define LmLASTADDR(LinkNum)            LmSEQ_PHY_REG(0, LinkNum, LASTADDR)
+
+#define LmNXTLADDR(LinkNum)            LmSEQ_PHY_REG(0, LinkNum, NXTLADDR)
+
+#define LmDBGPORTPTR(LinkNum)          LmSEQ_PHY_REG(0, LinkNum, DBGPORTPTR)
+
+#define LmDBGPORT(LinkNum)             LmSEQ_PHY_REG(0, LinkNum, DBGPORT)
+
+#define LmSCRATCHPAGE(LinkNum)         LmSEQ_PHY_REG(0, LinkNum, SCRATCHPAGE)
+
+#define LmMnSCRATCHPAGE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum,    \
+                                                     MnSCRATCHPAGE)
+
+#define LmTIMERCALC(LinkNum)           LmSEQ_PHY_REG(0, LinkNum, 0x28)
+
+#define LmREQMBX(LinkNum)              LmSEQ_PHY_REG(0, LinkNum, 0x30)
+
+#define LmRSPMBX(LinkNum)              LmSEQ_PHY_REG(0, LinkNum, 0x34)
+
+#define LmMnINT(LinkNum, Mode)         LmSEQ_PHY_REG(Mode, LinkNum, 0x38)
+
+#define                CTXMEMSIZE              0x80000000      /* ro */
+#define                LmACKREQ                0x08000000
+#define                LmNAKREQ                0x04000000
+#define                LmMnXMTERR              0x02000000
+#define                LmM5OOBSVC              0x01000000
+#define                LmHWTINT                0x00800000
+#define                LmMnCTXDONE             0x00100000
+#define                LmM2REQMBXF             0x00080000
+#define                LmM2RSPMBXE             0x00040000
+#define                LmMnDMAERR              0x00020000
+#define                LmRCVPRIM               0x00010000
+#define                LmRCVERR                0x00008000
+#define                LmADDRRCV               0x00004000
+#define                LmMnHDRMISS             0x00002000
+#define                LmMnWAITSCB             0x00001000
+#define                LmMnRLSSCB              0x00000800
+#define                LmMnSAVECTX             0x00000400
+#define                LmMnFETCHSG             0x00000200
+#define                LmMnLOADCTX             0x00000100
+#define                LmMnCFGICL              0x00000080
+#define                LmMnCFGSATA             0x00000040
+#define                LmMnCFGEXPSATA          0x00000020
+#define                LmMnCFGCMPLT            0x00000010
+#define                LmMnCFGRBUF             0x00000008
+#define                LmMnSAVETTR             0x00000004
+#define                LmMnCFGRDAT             0x00000002
+#define                LmMnCFGHDR              0x00000001
+
+#define LmMnINTEN(LinkNum, Mode)       LmSEQ_PHY_REG(Mode, LinkNum, 0x3C)
+
+#define                EN_LmACKREQ             0x08000000
+#define                EN_LmNAKREQ             0x04000000
+#define                EN_LmMnXMTERR           0x02000000
+#define                EN_LmM5OOBSVC           0x01000000
+#define                EN_LmHWTINT             0x00800000
+#define                EN_LmMnCTXDONE          0x00100000
+#define                EN_LmM2REQMBXF          0x00080000
+#define                EN_LmM2RSPMBXE          0x00040000
+#define                EN_LmMnDMAERR           0x00020000
+#define                EN_LmRCVPRIM            0x00010000
+#define                EN_LmRCVERR             0x00008000
+#define                EN_LmADDRRCV            0x00004000
+#define                EN_LmMnHDRMISS          0x00002000
+#define                EN_LmMnWAITSCB          0x00001000
+#define                EN_LmMnRLSSCB           0x00000800
+#define                EN_LmMnSAVECTX          0x00000400
+#define                EN_LmMnFETCHSG          0x00000200
+#define                EN_LmMnLOADCTX          0x00000100
+#define                EN_LmMnCFGICL           0x00000080
+#define                EN_LmMnCFGSATA          0x00000040
+#define                EN_LmMnCFGEXPSATA       0x00000020
+#define                EN_LmMnCFGCMPLT         0x00000010
+#define                EN_LmMnCFGRBUF          0x00000008
+#define                EN_LmMnSAVETTR          0x00000004
+#define                EN_LmMnCFGRDAT          0x00000002
+#define                EN_LmMnCFGHDR           0x00000001
+
+#define                LmM0INTEN_MASK          (EN_LmMnCFGCMPLT | EN_LmMnCFGRBUF | \
+                                        EN_LmMnSAVETTR | EN_LmMnCFGRDAT | \
+                                        EN_LmMnCFGHDR | EN_LmRCVERR | \
+                                        EN_LmADDRRCV | EN_LmMnHDRMISS | \
+                                        EN_LmMnRLSSCB | EN_LmMnSAVECTX | \
+                                        EN_LmMnFETCHSG | EN_LmMnLOADCTX | \
+                                        EN_LmHWTINT | EN_LmMnCTXDONE | \
+                                        EN_LmRCVPRIM | EN_LmMnCFGSATA | \
+                                        EN_LmMnCFGEXPSATA | EN_LmMnDMAERR)
+
+#define                LmM1INTEN_MASK          (EN_LmMnCFGCMPLT | EN_LmADDRRCV | \
+                                        EN_LmMnRLSSCB | EN_LmMnSAVECTX | \
+                                        EN_LmMnFETCHSG | EN_LmMnLOADCTX | \
+                                        EN_LmMnXMTERR | EN_LmHWTINT | \
+                                        EN_LmMnCTXDONE | EN_LmRCVPRIM | \
+                                        EN_LmRCVERR | EN_LmMnDMAERR)
+
+#define                LmM2INTEN_MASK          (EN_LmADDRRCV | EN_LmHWTINT | \
+                                        EN_LmM2REQMBXF | EN_LmRCVPRIM | \
+                                        EN_LmRCVERR)
+
+#define                LmM5INTEN_MASK          (EN_LmADDRRCV | EN_LmM5OOBSVC | \
+                                        EN_LmHWTINT | EN_LmRCVPRIM | \
+                                        EN_LmRCVERR)
+
+#define LmXMTPRIMD(LinkNum)            LmSEQ_PHY_REG(0, LinkNum, 0x40)
+
+#define LmXMTPRIMCS(LinkNum)           LmSEQ_PHY_REG(0, LinkNum, 0x44)
+
+#define LmCONSTAT(LinkNum)             LmSEQ_PHY_REG(0, LinkNum, 0x45)
+
+#define LmMnDMAERRS(LinkNum, Mode)     LmSEQ_PHY_REG(Mode, LinkNum, 0x46)
+
+#define LmMnSGDMAERRS(LinkNum, Mode)   LmSEQ_PHY_REG(Mode, LinkNum, 0x47)
+
+#define LmM0EXPHDRP(LinkNum)           LmSEQ_PHY_REG(0, LinkNum, 0x48)
+
+#define LmM1SASALIGN(LinkNum)          LmSEQ_PHY_REG(1, LinkNum, 0x48)
+#define SAS_ALIGN_DEFAULT              0xFF
+
+#define LmM0MSKHDRP(LinkNum)           LmSEQ_PHY_REG(0, LinkNum, 0x49)
+
+#define LmM1STPALIGN(LinkNum)          LmSEQ_PHY_REG(1, LinkNum, 0x49)
+#define STP_ALIGN_DEFAULT              0x1F
+
+#define LmM0RCVHDRP(LinkNum)           LmSEQ_PHY_REG(0, LinkNum, 0x4A)
+
+#define LmM1XMTHDRP(LinkNum)           LmSEQ_PHY_REG(1, LinkNum, 0x4A)
+
+#define LmM0ICLADR(LinkNum)            LmSEQ_PHY_REG(0, LinkNum, 0x4B)
+
+#define LmM1ALIGNMODE(LinkNum)         LmSEQ_PHY_REG(1, LinkNum, 0x4B)
+
+#define                LmDISALIGN              0x20
+#define                LmROTSTPALIGN           0x10
+#define                LmSTPALIGN              0x08
+#define                LmROTNOTIFY             0x04
+#define                LmDUALALIGN             0x02
+#define                LmROTALIGN              0x01
+
+#define LmM0EXPRCVNT(LinkNum)          LmSEQ_PHY_REG(0, LinkNum, 0x4C)
+
+#define LmM1XMTCNT(LinkNum)            LmSEQ_PHY_REG(1, LinkNum, 0x4C)
+
+#define LmMnBUFSTAT(LinkNum, Mode)     LmSEQ_PHY_REG(Mode, LinkNum, 0x4E)
+
+#define                LmMnBUFPERR             0x01
+
+/* mode 0-1 */
+#define LmMnXFRLVL(LinkNum, Mode)      LmSEQ_PHY_REG(Mode, LinkNum, 0x59)
+
+#define                LmMnXFRLVL_128          0x05
+#define                LmMnXFRLVL_256          0x04
+#define                LmMnXFRLVL_512          0x03
+#define                LmMnXFRLVL_1024         0x02
+#define                LmMnXFRLVL_1536         0x01
+#define                LmMnXFRLVL_2048         0x00
+
+ /* mode 0-1 */
+#define LmMnSGDMACTL(LinkNum, Mode)    LmSEQ_PHY_REG(Mode, LinkNum, 0x5A)
+
+#define        LmMnRESETSG             0x04
+#define        LmMnSTOPSG              0x02
+#define        LmMnSTARTSG             0x01
+
+/* mode 0-1 */
+#define LmMnSGDMASTAT(LinkNum, Mode)   LmSEQ_PHY_REG(Mode, LinkNum, 0x5B)
+
+/* mode 0-1 */
+#define LmMnDDMACTL(LinkNum, Mode)     LmSEQ_PHY_REG(Mode, LinkNum, 0x5C)
+
+#define        LmMnFLUSH               0x40            /* wo */
+#define        LmMnRLSRTRY             0x20            /* wo */
+#define        LmMnDISCARD             0x10            /* wo */
+#define        LmMnRESETDAT            0x08            /* wo */
+#define        LmMnSUSDAT              0x04            /* wo */
+#define        LmMnSTOPDAT             0x02            /* wo */
+#define        LmMnSTARTDAT            0x01            /* wo */
+
+/* mode 0-1 */
+#define LmMnDDMASTAT(LinkNum, Mode)    LmSEQ_PHY_REG(Mode, LinkNum, 0x5D)
+
+#define                LmMnDPEMPTY             0x80
+#define                LmMnFLUSHING            0x40
+#define                LmMnDDMAREQ             0x20
+#define                LmMnHDMAREQ             0x10
+#define                LmMnDATFREE             0x08
+#define                LmMnDATSUS              0x04
+#define                LmMnDATACT              0x02
+#define                LmMnDATEN               0x01
+
+/* mode 0-1 */
+#define LmMnDDMAMODE(LinkNum, Mode)    LmSEQ_PHY_REG(Mode, LinkNum, 0x5E)
+
+#define        LmMnDMATYPE_NORMAL              0x0000
+#define        LmMnDMATYPE_HOST_ONLY_TX        0x0001
+#define        LmMnDMATYPE_DEVICE_ONLY_TX      0x0002
+#define        LmMnDMATYPE_INVALID             0x0003
+#define        LmMnDMATYPE_MASK        0x0003
+
+#define        LmMnDMAWRAP             0x0004
+#define        LmMnBITBUCKET           0x0008
+#define        LmMnDISHDR              0x0010
+#define        LmMnSTPCRC              0x0020
+#define        LmXTEST                 0x0040
+#define        LmMnDISCRC              0x0080
+#define        LmMnENINTLK             0x0100
+#define        LmMnADDRFRM             0x0400
+#define        LmMnENXMTCRC            0x0800
+
+/* mode 0-1 */
+#define LmMnXFRCNT(LinkNum, Mode)      LmSEQ_PHY_REG(Mode, LinkNum, 0x70)
+
+/* mode 0-1 */
+#define LmMnDPSEL(LinkNum, Mode)       LmSEQ_PHY_REG(Mode, LinkNum, 0x7B)
+#define        LmMnDPSEL_MASK          0x07
+#define        LmMnEOLPRE              0x40
+#define        LmMnEOSPRE              0x80
+
+/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */
+/* Receive Mode n = 0 */
+#define LmMnHRADDR                     0x00
+#define LmMnHBYTECNT                   0x01
+#define LmMnHREWIND                    0x02
+#define LmMnDWADDR                     0x03
+#define LmMnDSPACECNT                  0x04
+#define LmMnDFRMSIZE                   0x05
+
+/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */
+/* Transmit Mode n = 1 */
+#define LmMnHWADDR                     0x00
+#define LmMnHSPACECNT                  0x01
+/* #define LmMnHREWIND                 0x02 */
+#define LmMnDRADDR                     0x03
+#define LmMnDBYTECNT                   0x04
+/* #define LmMnDFRMSIZE                        0x05 */
+
+/* mode 0-1 */
+#define LmMnDPACC(LinkNum, Mode)       LmSEQ_PHY_REG(Mode, LinkNum, 0x78)
+#define        LmMnDPACC_MASK          0x00FFFFFF
+
+/* mode 0-1 */
+#define LmMnHOLDLVL(LinkNum, Mode)     LmSEQ_PHY_REG(Mode, LinkNum, 0x7D)
+
+#define LmPRMSTAT0(LinkNum)            LmSEQ_PHY_REG(0, LinkNum, 0x80)
+#define LmPRMSTAT0BYTE0                        0x80
+#define LmPRMSTAT0BYTE1                        0x81
+#define LmPRMSTAT0BYTE2                        0x82
+#define LmPRMSTAT0BYTE3                        0x83
+
+#define                LmFRAMERCVD             0x80000000
+#define                LmXFRRDYRCVD            0x40000000
+#define                LmUNKNOWNP              0x20000000
+#define                LmBREAK                 0x10000000
+#define                LmDONE                  0x08000000
+#define                LmOPENACPT              0x04000000
+#define                LmOPENRJCT              0x02000000
+#define                LmOPENRTRY              0x01000000
+#define                LmCLOSERV1              0x00800000
+#define                LmCLOSERV0              0x00400000
+#define                LmCLOSENORM             0x00200000
+#define                LmCLOSECLAF             0x00100000
+#define                LmNOTIFYRV2             0x00080000
+#define                LmNOTIFYRV1             0x00040000
+#define                LmNOTIFYRV0             0x00020000
+#define                LmNOTIFYSPIN            0x00010000
+#define                LmBROADRV4              0x00008000
+#define                LmBROADRV3              0x00004000
+#define                LmBROADRV2              0x00002000
+#define                LmBROADRV1              0x00001000
+#define                LmBROADSES              0x00000800
+#define                LmBROADRVCH1            0x00000400
+#define                LmBROADRVCH0            0x00000200
+#define                LmBROADCH               0x00000100
+#define                LmAIPRVWP               0x00000080
+#define                LmAIPWP                 0x00000040
+#define                LmAIPWD                 0x00000020
+#define                LmAIPWC                 0x00000010
+#define                LmAIPRV2                0x00000008
+#define                LmAIPRV1                0x00000004
+#define                LmAIPRV0                0x00000002
+#define                LmAIPNRML               0x00000001
+
+#define                LmBROADCAST_MASK        (LmBROADCH | LmBROADRVCH0 | \
+                                        LmBROADRVCH1)
+
+#define LmPRMSTAT1(LinkNum)            LmSEQ_PHY_REG(0, LinkNum, 0x84)
+#define LmPRMSTAT1BYTE0                        0x84
+#define LmPRMSTAT1BYTE1                        0x85
+#define LmPRMSTAT1BYTE2                        0x86
+#define LmPRMSTAT1BYTE3                        0x87
+
+#define                LmFRMRCVDSTAT           0x80000000
+#define                LmBREAK_DET             0x04000000
+#define                LmCLOSE_DET             0x02000000
+#define                LmDONE_DET              0x01000000
+#define                LmXRDY                  0x00040000
+#define        LmSYNCSRST              0x00020000
+#define        LmSYNC                  0x00010000
+#define        LmXHOLD                 0x00008000
+#define        LmRRDY                  0x00004000
+#define        LmHOLD                  0x00002000
+#define        LmROK                   0x00001000
+#define        LmRIP                   0x00000800
+#define        LmCRBLK                 0x00000400
+#define        LmACK                   0x00000200
+#define        LmNAK                   0x00000100
+#define        LmHARDRST               0x00000080
+#define        LmERROR                 0x00000040
+#define        LmRERR                  0x00000020
+#define        LmPMREQP                0x00000010
+#define        LmPMREQS                0x00000008
+#define        LmPMACK                 0x00000004
+#define        LmPMNAK                 0x00000002
+#define        LmDMAT                  0x00000001
+
+/* mode 1 */
+#define        LmMnSATAFS(LinkNum, Mode)       LmSEQ_PHY_REG(Mode, LinkNum, 0x7E)
+#define        LmMnXMTSIZE(LinkNum, Mode)      LmSEQ_PHY_REG(Mode, LinkNum, 0x93)
+
+/* mode 0 */
+#define LmMnFRMERR(LinkNum, Mode)      LmSEQ_PHY_REG(Mode, LinkNum, 0xB0)
+
+#define                LmACRCERR               0x00000800
+#define                LmPHYOVRN               0x00000400
+#define                LmOBOVRN                0x00000200
+#define        LmMnZERODATA            0x00000100
+#define                LmSATAINTLK             0x00000080
+#define                LmMnCRCERR              0x00000020
+#define                LmRRDYOVRN              0x00000010
+#define                LmMISSSOAF              0x00000008
+#define                LmMISSSOF               0x00000004
+#define                LmMISSEOAF              0x00000002
+#define                LmMISSEOF               0x00000001
+
+#define LmFRMERREN(LinkNum)            LmSEQ_PHY_REG(0, LinkNum, 0xB4)
+
+#define        EN_LmACRCERR            0x00000800
+#define        EN_LmPHYOVRN            0x00000400
+#define        EN_LmOBOVRN             0x00000200
+#define        EN_LmMnZERODATA         0x00000100
+#define        EN_LmSATAINTLK          0x00000080
+#define        EN_LmFRMBAD             0x00000040
+#define        EN_LmMnCRCERR           0x00000020
+#define        EN_LmRRDYOVRN           0x00000010
+#define        EN_LmMISSSOAF           0x00000008
+#define        EN_LmMISSSOF            0x00000004
+#define        EN_LmMISSEOAF           0x00000002
+#define        EN_LmMISSEOF            0x00000001
+
+#define        LmFRMERREN_MASK         (EN_LmSATAINTLK | EN_LmMnCRCERR | \
+                                        EN_LmRRDYOVRN | EN_LmMISSSOF | \
+                                        EN_LmMISSEOAF | EN_LmMISSEOF | \
+                                        EN_LmACRCERR | LmPHYOVRN | \
+                                        EN_LmOBOVRN | EN_LmMnZERODATA)
+
+#define LmHWTSTATEN(LinkNum)           LmSEQ_PHY_REG(0, LinkNum, 0xC5)
+
+#define                EN_LmDONETO             0x80
+#define                EN_LmINVDISP            0x40
+#define                EN_LmINVDW              0x20
+#define                EN_LmDWSEVENT           0x08
+#define                EN_LmCRTTTO             0x04
+#define                EN_LmANTTTO             0x02
+#define                EN_LmBITLTTO            0x01
+
+#define                LmHWTSTATEN_MASK        (EN_LmINVDISP | EN_LmINVDW | \
+                                        EN_LmDWSEVENT | EN_LmCRTTTO | \
+                                        EN_LmANTTTO | EN_LmDONETO | \
+                                        EN_LmBITLTTO)
+
+#define LmHWTSTAT(LinkNum)             LmSEQ_PHY_REG(0, LinkNum, 0xC7)
+
+#define                LmDONETO                0x80
+#define                LmINVDISP               0x40
+#define                LmINVDW                 0x20
+#define                LmDWSEVENT              0x08
+#define                LmCRTTTO                0x04
+#define                LmANTTTO                0x02
+#define                LmBITLTTO               0x01
+
+#define LmMnDATABUFADR(LinkNum, Mode)  LmSEQ_PHY_REG(Mode, LinkNum, 0xC8)
+#define                LmDATABUFADR_MASK       0x0FFF
+
+#define LmMnDATABUF(LinkNum, Mode)     LmSEQ_PHY_REG(Mode, LinkNum, 0xCA)
+
+#define        LmPRIMSTAT0EN(LinkNum)          LmSEQ_PHY_REG(0, LinkNum, 0xE0)
+
+#define        EN_LmUNKNOWNP           0x20000000
+#define        EN_LmBREAK              0x10000000
+#define        EN_LmDONE               0x08000000
+#define        EN_LmOPENACPT           0x04000000
+#define        EN_LmOPENRJCT           0x02000000
+#define        EN_LmOPENRTRY           0x01000000
+#define        EN_LmCLOSERV1           0x00800000
+#define        EN_LmCLOSERV0           0x00400000
+#define        EN_LmCLOSENORM          0x00200000
+#define        EN_LmCLOSECLAF          0x00100000
+#define        EN_LmNOTIFYRV2          0x00080000
+#define        EN_LmNOTIFYRV1          0x00040000
+#define        EN_LmNOTIFYRV0          0x00020000
+#define        EN_LmNOTIFYSPIN         0x00010000
+#define        EN_LmBROADRV4           0x00008000
+#define        EN_LmBROADRV3           0x00004000
+#define        EN_LmBROADRV2           0x00002000
+#define        EN_LmBROADRV1           0x00001000
+#define        EN_LmBROADRV0           0x00000800
+#define        EN_LmBROADRVCH1         0x00000400
+#define        EN_LmBROADRVCH0         0x00000200
+#define        EN_LmBROADCH            0x00000100
+#define        EN_LmAIPRVWP            0x00000080
+#define        EN_LmAIPWP              0x00000040
+#define        EN_LmAIPWD              0x00000020
+#define        EN_LmAIPWC              0x00000010
+#define        EN_LmAIPRV2             0x00000008
+#define        EN_LmAIPRV1             0x00000004
+#define        EN_LmAIPRV0             0x00000002
+#define        EN_LmAIPNRML            0x00000001
+
+#define                LmPRIMSTAT0EN_MASK      (EN_LmBREAK | \
+                                        EN_LmDONE | EN_LmOPENACPT | \
+                                        EN_LmOPENRJCT | EN_LmOPENRTRY | \
+                                        EN_LmCLOSERV1 | EN_LmCLOSERV0 | \
+                                        EN_LmCLOSENORM | EN_LmCLOSECLAF | \
+                                        EN_LmBROADRV4 | EN_LmBROADRV3 | \
+                                        EN_LmBROADRV2 | EN_LmBROADRV1 | \
+                                        EN_LmBROADRV0 | EN_LmBROADRVCH1 | \
+                                        EN_LmBROADRVCH0 | EN_LmBROADCH | \
+                                        EN_LmAIPRVWP | EN_LmAIPWP | \
+                                        EN_LmAIPWD | EN_LmAIPWC | \
+                                        EN_LmAIPRV2 | EN_LmAIPRV1 | \
+                                        EN_LmAIPRV0 | EN_LmAIPNRML)
+
+#define LmPRIMSTAT1EN(LinkNum)         LmSEQ_PHY_REG(0, LinkNum, 0xE4)
+
+#define                EN_LmXRDY               0x00040000
+#define                EN_LmSYNCSRST           0x00020000
+#define                EN_LmSYNC               0x00010000
+#define        EN_LmXHOLD              0x00008000
+#define        EN_LmRRDY               0x00004000
+#define        EN_LmHOLD               0x00002000
+#define        EN_LmROK                0x00001000
+#define        EN_LmRIP                0x00000800
+#define        EN_LmCRBLK              0x00000400
+#define        EN_LmACK                0x00000200
+#define        EN_LmNAK                0x00000100
+#define        EN_LmHARDRST            0x00000080
+#define        EN_LmERROR              0x00000040
+#define        EN_LmRERR               0x00000020
+#define        EN_LmPMREQP             0x00000010
+#define        EN_LmPMREQS             0x00000008
+#define        EN_LmPMACK              0x00000004
+#define        EN_LmPMNAK              0x00000002
+#define        EN_LmDMAT               0x00000001
+
+#define LmPRIMSTAT1EN_MASK             (EN_LmHARDRST | \
+                                        EN_LmSYNCSRST | \
+                                        EN_LmPMREQP | EN_LmPMREQS | \
+                                        EN_LmPMACK | EN_LmPMNAK)
+
+#define LmSMSTATE(LinkNum)             LmSEQ_PHY_REG(0, LinkNum, 0xE8)
+
+#define LmSMSTATEBRK(LinkNum)          LmSEQ_PHY_REG(0, LinkNum, 0xEC)
+
+#define LmSMDBGCTL(LinkNum)            LmSEQ_PHY_REG(0, LinkNum, 0xF0)
+
+
+/*
+ * LmSEQ CIO Bus Mode 3 Register.
+ * Mode 3: Configuration and Setup, IOP Context SCB.
+ */
+#define LmM3SATATIMER(LinkNum)                 LmSEQ_PHY_REG(3, LinkNum, 0x48)
+
+#define LmM3INTVEC0(LinkNum)           LmSEQ_PHY_REG(3, LinkNum, 0x90)
+
+#define LmM3INTVEC1(LinkNum)           LmSEQ_PHY_REG(3, LinkNum, 0x92)
+
+#define LmM3INTVEC2(LinkNum)           LmSEQ_PHY_REG(3, LinkNum, 0x94)
+
+#define LmM3INTVEC3(LinkNum)           LmSEQ_PHY_REG(3, LinkNum, 0x96)
+
+#define LmM3INTVEC4(LinkNum)           LmSEQ_PHY_REG(3, LinkNum, 0x98)
+
+#define LmM3INTVEC5(LinkNum)           LmSEQ_PHY_REG(3, LinkNum, 0x9A)
+
+#define LmM3INTVEC6(LinkNum)           LmSEQ_PHY_REG(3, LinkNum, 0x9C)
+
+#define LmM3INTVEC7(LinkNum)           LmSEQ_PHY_REG(3, LinkNum, 0x9E)
+
+#define LmM3INTVEC8(LinkNum)           LmSEQ_PHY_REG(3, LinkNum, 0xA4)
+
+#define LmM3INTVEC9(LinkNum)           LmSEQ_PHY_REG(3, LinkNum, 0xA6)
+
+#define LmM3INTVEC10(LinkNum)          LmSEQ_PHY_REG(3, LinkNum, 0xB0)
+
+#define LmM3FRMGAP(LinkNum)            LmSEQ_PHY_REG(3, LinkNum, 0xB4)
+
+#define LmBITL_TIMER(LinkNum)          LmSEQ_PHY_REG(0, LinkNum, 0xA2)
+
+#define LmWWN(LinkNum)                         LmSEQ_PHY_REG(0, LinkNum, 0xA8)
+
+
+/*
+ * LmSEQ CIO Bus Mode 5 Registers.
+ * Mode 5: Phy/OOB Control and Status.
+ */
+#define LmSEQ_OOB_REG(phy_id, reg)     LmSEQ_PHY_REG(5, (phy_id), (reg))
+
+#define OOB_BFLTR      0x100
+
+#define                BFLTR_THR_MASK          0xF0
+#define                BFLTR_TC_MASK           0x0F
+
+#define OOB_INIT_MIN   0x102
+
+#define OOB_INIT_MAX   0x104
+
+#define OOB_INIT_NEG   0x106
+
+#define        OOB_SAS_MIN     0x108
+
+#define OOB_SAS_MAX    0x10A
+
+#define OOB_SAS_NEG    0x10C
+
+#define OOB_WAKE_MIN   0x10E
+
+#define OOB_WAKE_MAX   0x110
+
+#define OOB_WAKE_NEG   0x112
+
+#define OOB_IDLE_MAX   0x114
+
+#define OOB_BURST_MAX  0x116
+
+#define OOB_DATA_KBITS 0x126
+
+#define OOB_ALIGN_0_DATA       0x12C
+
+#define OOB_ALIGN_1_DATA       0x130
+
+#define D10_2_DATA_k           0x00
+#define SYNC_DATA_k            0x02
+#define ALIGN_1_DATA_k         0x04
+#define ALIGN_0_DATA_k         0x08
+#define BURST_DATA_k           0x10
+
+#define OOB_PHY_RESET_COUNT    0x13C
+
+#define OOB_SIG_GEN    0x140
+
+#define                START_OOB               0x80
+#define                START_DWS               0x40
+#define                ALIGN_CNT3              0x30
+#define        ALIGN_CNT2              0x20
+#define        ALIGN_CNT1              0x10
+#define        ALIGN_CNT4              0x00
+#define                STOP_DWS                0x08
+#define                SEND_COMSAS             0x04
+#define                SEND_COMINIT            0x02
+#define                SEND_COMWAKE            0x01
+
+#define OOB_XMIT       0x141
+
+#define                TX_ENABLE               0x80
+#define                XMIT_OOB_BURST          0x10
+#define                XMIT_D10_2              0x08
+#define                XMIT_SYNC               0x04
+#define                XMIT_ALIGN_1            0x02
+#define                XMIT_ALIGN_0            0x01
+
+#define FUNCTION_MASK  0x142
+
+#define                SAS_MODE_DIS            0x80
+#define                SATA_MODE_DIS           0x40
+#define                SPINUP_HOLD_DIS         0x20
+#define                HOT_PLUG_DIS            0x10
+#define                SATA_PS_DIS             0x08
+#define                FUNCTION_MASK_DEFAULT   (SPINUP_HOLD_DIS | SATA_PS_DIS)
+
+#define OOB_MODE       0x143
+
+#define                SAS_MODE                0x80
+#define                SATA_MODE               0x40
+#define                SLOW_CLK                0x20
+#define                FORCE_XMIT_15           0x08
+#define                PHY_SPEED_60            0x04
+#define                PHY_SPEED_30            0x02
+#define                PHY_SPEED_15            0x01
+
+#define        CURRENT_STATUS  0x144
+
+#define                CURRENT_OOB_DONE        0x80
+#define                CURRENT_LOSS_OF_SIGNAL  0x40
+#define                CURRENT_SPINUP_HOLD     0x20
+#define                CURRENT_HOT_PLUG_CNCT   0x10
+#define                CURRENT_GTO_TIMEOUT     0x08
+#define                CURRENT_OOB_TIMEOUT     0x04
+#define                CURRENT_DEVICE_PRESENT  0x02
+#define                CURRENT_OOB_ERROR       0x01
+
+#define        CURRENT_OOB1_ERROR      (CURRENT_HOT_PLUG_CNCT | \
+                                        CURRENT_GTO_TIMEOUT)
+
+#define        CURRENT_OOB2_ERROR      (CURRENT_HOT_PLUG_CNCT | \
+                                        CURRENT_OOB_ERROR)
+
+#define                DEVICE_ADDED_W_CNT      (CURRENT_OOB_DONE | \
+                                        CURRENT_HOT_PLUG_CNCT | \
+                                        CURRENT_DEVICE_PRESENT)
+
+#define                DEVICE_ADDED_WO_CNT     (CURRENT_OOB_DONE | \
+                                        CURRENT_DEVICE_PRESENT)
+
+#define        DEVICE_REMOVED          CURRENT_LOSS_OF_SIGNAL
+
+#define                CURRENT_PHY_MASK        (CURRENT_OOB_DONE | \
+                                        CURRENT_LOSS_OF_SIGNAL | \
+                                        CURRENT_SPINUP_HOLD | \
+                                        CURRENT_HOT_PLUG_CNCT | \
+                                        CURRENT_GTO_TIMEOUT | \
+                                        CURRENT_DEVICE_PRESENT | \
+                                        CURRENT_OOB_ERROR )
+
+#define                CURRENT_ERR_MASK        (CURRENT_LOSS_OF_SIGNAL | \
+                                        CURRENT_GTO_TIMEOUT | \
+                                        CURRENT_OOB_TIMEOUT | \
+                                        CURRENT_OOB_ERROR )
+
+#define SPEED_MASK     0x145
+
+#define                SATA_SPEED_30_DIS       0x10
+#define                SATA_SPEED_15_DIS       0x08
+#define                SAS_SPEED_60_DIS        0x04
+#define                SAS_SPEED_30_DIS        0x02
+#define                SAS_SPEED_15_DIS        0x01
+#define                SAS_SPEED_MASK_DEFAULT  0x00
+
+#define OOB_TIMER_ENABLE       0x14D
+
+#define                HOT_PLUG_EN             0x80
+#define                RCD_EN                  0x40
+#define        COMTIMER_EN             0x20
+#define                SNTT_EN                 0x10
+#define                SNLT_EN                 0x04
+#define                SNWT_EN                 0x02
+#define                ALIGN_EN                0x01
+
+#define OOB_STATUS             0x14E
+
+#define                OOB_DONE                0x80
+#define                LOSS_OF_SIGNAL          0x40            /* ro */
+#define                SPINUP_HOLD             0x20
+#define                HOT_PLUG_CNCT           0x10            /* ro */
+#define                GTO_TIMEOUT             0x08            /* ro */
+#define                OOB_TIMEOUT             0x04            /* ro */
+#define                DEVICE_PRESENT          0x02            /* ro */
+#define                OOB_ERROR               0x01            /* ro */
+
+#define                OOB_STATUS_ERROR_MASK   (LOSS_OF_SIGNAL | GTO_TIMEOUT | \
+                                        OOB_TIMEOUT | OOB_ERROR)
+
+#define OOB_STATUS_CLEAR       0x14F
+
+#define                OOB_DONE_CLR            0x80
+#define                LOSS_OF_SIGNAL_CLR      0x40
+#define                SPINUP_HOLD_CLR         0x20
+#define                HOT_PLUG_CNCT_CLR       0x10
+#define                GTO_TIMEOUT_CLR         0x08
+#define                OOB_TIMEOUT_CLR         0x04
+#define                OOB_ERROR_CLR           0x01
+
+#define HOT_PLUG_DELAY         0x150
+/* In 5 ms units. 20 = 100 ms. */
+#define        HOTPLUG_DELAY_TIMEOUT           20
+
+
+#define INT_ENABLE_2           0x15A
+
+#define                OOB_DONE_EN             0x80
+#define                LOSS_OF_SIGNAL_EN       0x40
+#define                SPINUP_HOLD_EN          0x20
+#define                HOT_PLUG_CNCT_EN        0x10
+#define                GTO_TIMEOUT_EN          0x08
+#define                OOB_TIMEOUT_EN          0x04
+#define                DEVICE_PRESENT_EN       0x02
+#define                OOB_ERROR_EN            0x01
+
+#define PHY_CONTROL_0          0x160
+
+#define                PHY_LOWPWREN_TX         0x80
+#define                PHY_LOWPWREN_RX         0x40
+#define                SPARE_REG_160_B5        0x20
+#define                OFFSET_CANCEL_RX        0x10
+
+/* bits 3:2 */
+#define                PHY_RXCOMCENTER_60V     0x00
+#define                PHY_RXCOMCENTER_70V     0x04
+#define                PHY_RXCOMCENTER_80V     0x08
+#define                PHY_RXCOMCENTER_90V     0x0C
+#define        PHY_RXCOMCENTER_MASK    0x0C
+
+#define                PHY_RESET               0x02
+#define                SAS_DEFAULT_SEL         0x01
+
+#define PHY_CONTROL_1          0x161
+
+/* bits 2:0 */
+#define                SATA_PHY_DETLEVEL_50mv  0x00
+#define                SATA_PHY_DETLEVEL_75mv  0x01
+#define                SATA_PHY_DETLEVEL_100mv 0x02
+#define                SATA_PHY_DETLEVEL_125mv 0x03
+#define                SATA_PHY_DETLEVEL_150mv 0x04
+#define                SATA_PHY_DETLEVEL_175mv 0x05
+#define                SATA_PHY_DETLEVEL_200mv 0x06
+#define                SATA_PHY_DETLEVEL_225mv 0x07
+#define                SATA_PHY_DETLEVEL_MASK  0x07
+
+/* bits 5:3 */
+#define                SAS_PHY_DETLEVEL_50mv   0x00
+#define                SAS_PHY_DETLEVEL_75mv   0x08
+#define                SAS_PHY_DETLEVEL_100mv  0x10
+#define                SAS_PHY_DETLEVEL_125mv  0x11
+#define                SAS_PHY_DETLEVEL_150mv  0x20
+#define                SAS_PHY_DETLEVEL_175mv  0x21
+#define                SAS_PHY_DETLEVEL_200mv  0x30
+#define                SAS_PHY_DETLEVEL_225mv  0x31
+#define                SAS_PHY_DETLEVEL_MASK   0x38
+
+#define PHY_CONTROL_2          0x162
+
+/* bits 7:5 */
+#define        SATA_PHY_DRV_400mv      0x00
+#define        SATA_PHY_DRV_450mv      0x20
+#define        SATA_PHY_DRV_500mv      0x40
+#define        SATA_PHY_DRV_550mv      0x60
+#define        SATA_PHY_DRV_600mv      0x80
+#define        SATA_PHY_DRV_650mv      0xA0
+#define        SATA_PHY_DRV_725mv      0xC0
+#define        SATA_PHY_DRV_800mv      0xE0
+#define                SATA_PHY_DRV_MASK       0xE0
+
+/* bits 4:3 */
+#define        SATA_PREEMP_0           0x00
+#define        SATA_PREEMP_1           0x08
+#define        SATA_PREEMP_2           0x10
+#define        SATA_PREEMP_3           0x18
+#define        SATA_PREEMP_MASK        0x18
+
+#define        SATA_CMSH1P5            0x04
+
+/* bits 1:0 */
+#define        SATA_SLEW_0             0x00
+#define        SATA_SLEW_1             0x01
+#define        SATA_SLEW_2             0x02
+#define        SATA_SLEW_3             0x03
+#define        SATA_SLEW_MASK          0x03
+
+#define PHY_CONTROL_3          0x163
+
+/* bits 7:5 */
+#define        SAS_PHY_DRV_400mv       0x00
+#define        SAS_PHY_DRV_450mv       0x20
+#define        SAS_PHY_DRV_500mv       0x40
+#define        SAS_PHY_DRV_550mv       0x60
+#define        SAS_PHY_DRV_600mv       0x80
+#define        SAS_PHY_DRV_650mv       0xA0
+#define        SAS_PHY_DRV_725mv       0xC0
+#define        SAS_PHY_DRV_800mv       0xE0
+#define                SAS_PHY_DRV_MASK        0xE0
+
+/* bits 4:3 */
+#define        SAS_PREEMP_0            0x00
+#define        SAS_PREEMP_1            0x08
+#define        SAS_PREEMP_2            0x10
+#define        SAS_PREEMP_3            0x18
+#define        SAS_PREEMP_MASK         0x18
+
+#define        SAS_CMSH1P5             0x04
+
+/* bits 1:0 */
+#define        SAS_SLEW_0              0x00
+#define        SAS_SLEW_1              0x01
+#define        SAS_SLEW_2              0x02
+#define        SAS_SLEW_3              0x03
+#define        SAS_SLEW_MASK           0x03
+
+#define PHY_CONTROL_4          0x168
+
+#define                PHY_DONE_CAL_TX         0x80
+#define                PHY_DONE_CAL_RX         0x40
+#define                RX_TERM_LOAD_DIS        0x20
+#define                TX_TERM_LOAD_DIS        0x10
+#define                AUTO_TERM_CAL_DIS       0x08
+#define                PHY_SIGDET_FLTR_EN      0x04
+#define                OSC_FREQ                0x02
+#define                PHY_START_CAL           0x01
+
+/*
+ * HST_PCIX2 Registers, Addresss Range: (0x00-0xFC)
+ */
+#define PCIX_REG_BASE_ADR              0xB8040000
+
+#define PCIC_VENDOR_ID 0x00
+
+#define PCIC_DEVICE_ID 0x02
+
+#define PCIC_COMMAND   0x04
+
+#define                INT_DIS                 0x0400
+#define                FBB_EN                  0x0200          /* ro */
+#define                SERR_EN                 0x0100
+#define                STEP_EN                 0x0080          /* ro */
+#define                PERR_EN                 0x0040
+#define                VGA_EN                  0x0020          /* ro */
+#define                MWI_EN                  0x0010
+#define                SPC_EN                  0x0008
+#define                MST_EN                  0x0004
+#define                MEM_EN                  0x0002
+#define                IO_EN                   0x0001
+
+#define        PCIC_STATUS     0x06
+
+#define                PERR_DET                0x8000
+#define                SERR_GEN                0x4000
+#define                MABT_DET                0x2000
+#define                TABT_DET                0x1000
+#define                TABT_GEN                0x0800
+#define                DPERR_DET               0x0100
+#define                CAP_LIST                0x0010
+#define                INT_STAT                0x0008
+
+#define        PCIC_DEVREV_ID  0x08
+
+#define        PCIC_CLASS_CODE 0x09
+
+#define        PCIC_CACHELINE_SIZE     0x0C
+
+#define        PCIC_MBAR0      0x10
+
+#define        PCIC_MBAR0_OFFSET       0
+
+#define        PCIC_MBAR1      0x18
+
+#define        PCIC_MBAR1_OFFSET       2
+
+#define        PCIC_IOBAR      0x20
+
+#define        PCIC_IOBAR_OFFSET       4
+
+#define        PCIC_SUBVENDOR_ID       0x2C
+
+#define PCIC_SUBSYTEM_ID       0x2E
+
+#define PCIX_STATUS            0x44
+#define        RCV_SCE         0x20000000
+#define        UNEXP_SC        0x00080000
+#define        SC_DISCARD      0x00040000
+
+#define ECC_CTRL_STAT          0x48
+#define        UNCOR_ECCERR    0x00000008
+
+#define PCIC_PM_CSR            0x5C
+
+#define                PWR_STATE_D0            0
+#define                PWR_STATE_D1            1       /* not supported */
+#define                PWR_STATE_D2            2       /* not supported */
+#define                PWR_STATE_D3            3
+
+#define PCIC_BASE1     0x6C    /* internal use only */
+
+#define                BASE1_RSVD              0xFFFFFFF8
+
+#define PCIC_BASEA     0x70    /* internal use only */
+
+#define                BASEA_RSVD              0xFFFFFFC0
+#define        BASEA_START             0
+
+#define PCIC_BASEB     0x74    /* internal use only */
+
+#define                BASEB_RSVD              0xFFFFFF80
+#define                BASEB_IOMAP_MASK        0x7F
+#define        BASEB_START             0x80
+
+#define PCIC_BASEC     0x78    /* internal use only */
+
+#define                BASEC_RSVD              0xFFFFFFFC
+#define        BASEC_MASK              0x03
+#define        BASEC_START             0x58
+
+#define PCIC_MBAR_KEY  0x7C    /* internal use only */
+
+#define        MBAR_KEY_MASK           0xFFFFFFFF
+
+#define PCIC_HSTPCIX_CNTRL     0xA0
+
+#define        REWIND_DIS              0x0800
+#define                SC_TMR_DIS              0x04000000
+
+#define PCIC_MBAR0_MASK        0xA8
+#define                PCIC_MBAR0_SIZE_MASK    0x1FFFE000
+#define                PCIC_MBAR0_SIZE_SHIFT   13
+#define                PCIC_MBAR0_SIZE(val)    \
+                   (((val) & PCIC_MBAR0_SIZE_MASK) >> PCIC_MBAR0_SIZE_SHIFT)
+
+#define PCIC_FLASH_MBAR        0xB8
+
+#define PCIC_INTRPT_STAT 0xD4
+
+#define PCIC_TP_CTRL   0xFC
+
+/*
+ * EXSI Registers, Addresss Range: (0x00-0xFC)
+ */
+#define EXSI_REG_BASE_ADR              REG_BASE_ADDR_EXSI
+
+#define        EXSICNFGR       (EXSI_REG_BASE_ADR + 0x00)
+
+#define                OCMINITIALIZED          0x80000000
+#define                ASIEN                   0x00400000
+#define                HCMODE                  0x00200000
+#define                PCIDEF                  0x00100000
+#define                COMSTOCK                0x00080000
+#define                SEEPROMEND              0x00040000
+#define                MSTTIMEN                0x00020000
+#define                XREGEX                  0x00000200
+#define                NVRAMW                  0x00000100
+#define                NVRAMEX                 0x00000080
+#define                SRAMW                   0x00000040
+#define                SRAMEX                  0x00000020
+#define                FLASHW                  0x00000010
+#define                FLASHEX                 0x00000008
+#define                SEEPROMCFG              0x00000004
+#define                SEEPROMTYP              0x00000002
+#define                SEEPROMEX               0x00000001
+
+
+#define EXSICNTRLR     (EXSI_REG_BASE_ADR + 0x04)
+
+#define                MODINT_EN               0x00000001
+
+
+#define PMSTATR                (EXSI_REG_BASE_ADR + 0x10)
+
+#define                FLASHRST                0x00000002
+#define                FLASHRDY                0x00000001
+
+
+#define FLCNFGR                (EXSI_REG_BASE_ADR + 0x14)
+
+#define                FLWEH_MASK              0x30000000
+#define                FLWESU_MASK             0x0C000000
+#define                FLWEPW_MASK             0x03F00000
+#define                FLOEH_MASK              0x000C0000
+#define        FLOESU_MASK             0x00030000
+#define        FLOEPW_MASK             0x0000FC00
+#define        FLCSH_MASK              0x00000300
+#define        FLCSSU_MASK             0x000000C0
+#define        FLCSPW_MASK             0x0000003F
+
+#define SRCNFGR                (EXSI_REG_BASE_ADR + 0x18)
+
+#define                SRWEH_MASK              0x30000000
+#define                SRWESU_MASK             0x0C000000
+#define                SRWEPW_MASK             0x03F00000
+
+#define                SROEH_MASK              0x000C0000
+#define        SROESU_MASK             0x00030000
+#define        SROEPW_MASK             0x0000FC00
+#define                SRCSH_MASK              0x00000300
+#define                SRCSSU_MASK             0x000000C0
+#define                SRCSPW_MASK             0x0000003F
+
+#define NVCNFGR                (EXSI_REG_BASE_ADR + 0x1C)
+
+#define        NVWEH_MASK              0x30000000
+#define        NVWESU_MASK             0x0C000000
+#define        NVWEPW_MASK             0x03F00000
+#define        NVOEH_MASK              0x000C0000
+#define        NVOESU_MASK             0x00030000
+#define        NVOEPW_MASK             0x0000FC00
+#define        NVCSH_MASK              0x00000300
+#define        NVCSSU_MASK             0x000000C0
+#define        NVCSPW_MASK             0x0000003F
+
+#define XRCNFGR                (EXSI_REG_BASE_ADR + 0x20)
+
+#define        XRWEH_MASK              0x30000000
+#define        XRWESU_MASK             0x0C000000
+#define        XRWEPW_MASK             0x03F00000
+#define        XROEH_MASK              0x000C0000
+#define        XROESU_MASK             0x00030000
+#define        XROEPW_MASK             0x0000FC00
+#define        XRCSH_MASK              0x00000300
+#define        XRCSSU_MASK             0x000000C0
+#define                XRCSPW_MASK             0x0000003F
+
+#define XREGADDR       (EXSI_REG_BASE_ADR + 0x24)
+
+#define        XRADDRINCEN             0x80000000
+#define        XREGADD_MASK            0x007FFFFF
+
+
+#define XREGDATAR      (EXSI_REG_BASE_ADR + 0x28)
+
+#define                XREGDATA_MASK           0x0000FFFF
+
+#define GPIOOER                (EXSI_REG_BASE_ADR + 0x40)
+
+#define GPIOODENR      (EXSI_REG_BASE_ADR + 0x44)
+
+#define GPIOINVR       (EXSI_REG_BASE_ADR + 0x48)
+
+#define GPIODATAOR     (EXSI_REG_BASE_ADR + 0x4C)
+
+#define GPIODATAIR     (EXSI_REG_BASE_ADR + 0x50)
+
+#define GPIOCNFGR      (EXSI_REG_BASE_ADR + 0x54)
+
+#define                GPIO_EXTSRC             0x00000001
+
+#define SCNTRLR                (EXSI_REG_BASE_ADR + 0xA0)
+
+#define        SXFERDONE               0x00000100
+#define        SXFERCNT_MASK           0x000000E0
+#define        SCMDTYP_MASK            0x0000001C
+#define        SXFERSTART              0x00000002
+#define        SXFEREN                 0x00000001
+
+#define        SRATER          (EXSI_REG_BASE_ADR + 0xA4)
+
+#define        SADDRR          (EXSI_REG_BASE_ADR + 0xA8)
+
+#define        SADDR_MASK              0x0000FFFF
+
+#define SDATAOR                (EXSI_REG_BASE_ADR + 0xAC)
+
+#define        SDATAOR0        (EXSI_REG_BASE_ADR + 0xAC)
+#define SDATAOR1       (EXSI_REG_BASE_ADR + 0xAD)
+#define SDATAOR2       (EXSI_REG_BASE_ADR + 0xAE)
+#define SDATAOR3       (EXSI_REG_BASE_ADR + 0xAF)
+
+#define SDATAIR                (EXSI_REG_BASE_ADR + 0xB0)
+
+#define SDATAIR0       (EXSI_REG_BASE_ADR + 0xB0)
+#define SDATAIR1       (EXSI_REG_BASE_ADR + 0xB1)
+#define SDATAIR2       (EXSI_REG_BASE_ADR + 0xB2)
+#define SDATAIR3       (EXSI_REG_BASE_ADR + 0xB3)
+
+#define ASISTAT0R      (EXSI_REG_BASE_ADR + 0xD0)
+#define        ASIFMTERR               0x00000400
+#define        ASISEECHKERR            0x00000200
+#define        ASIERR                  0x00000100
+
+#define ASISTAT1R      (EXSI_REG_BASE_ADR + 0xD4)
+#define        CHECKSUM_MASK           0x0000FFFF
+
+#define ASIERRADDR     (EXSI_REG_BASE_ADR + 0xD8)
+#define ASIERRDATAR    (EXSI_REG_BASE_ADR + 0xDC)
+#define ASIERRSTATR    (EXSI_REG_BASE_ADR + 0xE0)
+#define        CPI2ASIBYTECNT_MASK     0x00070000
+#define        CPI2ASIBYTEEN_MASK      0x0000F000
+#define        CPI2ASITARGERR_MASK     0x00000F00
+#define        CPI2ASITARGMID_MASK     0x000000F0
+#define        CPI2ASIMSTERR_MASK      0x0000000F
+
+/*
+ * XSRAM, External SRAM (DWord and any BE pattern accessible)
+ */
+#define XSRAM_REG_BASE_ADDR             0xB8100000
+#define XSRAM_SIZE                        0x100000
+
+/*
+ * NVRAM Registers, Address Range: (0x00000 - 0x3FFFF).
+ */
+#define                NVRAM_REG_BASE_ADR      0xBF800000
+#define                NVRAM_MAX_BASE_ADR      0x003FFFFF
+
+/* OCM base address */
+#define                OCM_BASE_ADDR           0xA0000000
+#define                OCM_MAX_SIZE            0x20000
+
+/*
+ * Sequencers (Central and Link) Scratch RAM page definitions.
+ */
+
+/*
+ * The Central Management Sequencer (CSEQ) Scratch Memory is a 1024
+ * byte memory.  It is dword accessible and has byte parity
+ * protection. The CSEQ accesses it in 32 byte windows, either as mode
+ * dependent or mode independent memory. Each mode has 96 bytes,
+ * (three 32 byte pages 0-2, not contiguous), leaving 128 bytes of
+ * Mode Independent memory (four 32 byte pages 3-7). Note that mode
+ * dependent scratch memory, Mode 8, page 0-3 overlaps mode
+ * independent scratch memory, pages 0-3.
+ * - 896 bytes of mode dependent scratch, 96 bytes per Modes 0-7, and
+ * 128 bytes in mode 8,
+ * - 259 bytes of mode independent scratch, common to modes 0-15.
+ *
+ * Sequencer scratch RAM is 1024 bytes.  This scratch memory is
+ * divided into mode dependent and mode independent scratch with this
+ * memory further subdivided into pages of size 32 bytes. There are 5
+ * pages (160 bytes) of mode independent scratch and 3 pages of
+ * dependent scratch memory for modes 0-7 (768 bytes). Mode 8 pages
+ * 0-2 dependent scratch overlap with pages 0-2 of mode independent
+ * scratch memory.
+ *
+ * The host accesses this scratch in a different manner from the
+ * central sequencer. The sequencer has to use CSEQ registers CSCRPAGE
+ * and CMnSCRPAGE to access the scratch memory. A flat mapping of the
+ * scratch memory is avaliable for software convenience and to prevent
+ * corruption while the sequencer is running. This memory is mapped
+ * onto addresses 800h - BFFh, total of 400h bytes.
+ *
+ * These addresses are mapped as follows:
+ *
+ *        800h-83Fh   Mode Dependent Scratch Mode 0 Pages 0-1
+ *        840h-87Fh   Mode Dependent Scratch Mode 1 Pages 0-1
+ *        880h-8BFh   Mode Dependent Scratch Mode 2 Pages 0-1
+ *        8C0h-8FFh   Mode Dependent Scratch Mode 3 Pages 0-1
+ *        900h-93Fh   Mode Dependent Scratch Mode 4 Pages 0-1
+ *        940h-97Fh   Mode Dependent Scratch Mode 5 Pages 0-1
+ *        980h-9BFh   Mode Dependent Scratch Mode 6 Pages 0-1
+ *        9C0h-9FFh   Mode Dependent Scratch Mode 7 Pages 0-1
+ *        A00h-A5Fh   Mode Dependent Scratch Mode 8 Pages 0-2
+ *                    Mode Independent Scratch Pages 0-2
+ *        A60h-A7Fh   Mode Dependent Scratch Mode 8 Page 3
+ *                    Mode Independent Scratch Page 3
+ *        A80h-AFFh   Mode Independent Scratch Pages 4-7
+ *        B00h-B1Fh   Mode Dependent Scratch Mode 0 Page 2
+ *        B20h-B3Fh   Mode Dependent Scratch Mode 1 Page 2
+ *        B40h-B5Fh   Mode Dependent Scratch Mode 2 Page 2
+ *        B60h-B7Fh   Mode Dependent Scratch Mode 3 Page 2
+ *        B80h-B9Fh   Mode Dependent Scratch Mode 4 Page 2
+ *        BA0h-BBFh   Mode Dependent Scratch Mode 5 Page 2
+ *        BC0h-BDFh   Mode Dependent Scratch Mode 6 Page 2
+ *        BE0h-BFFh   Mode Dependent Scratch Mode 7 Page 2
+ */
+
+/* General macros */
+#define CSEQ_PAGE_SIZE                 32  /* Scratch page size (in bytes) */
+
+/* All macros start with offsets from base + 0x800 (CMAPPEDSCR).
+ * Mode dependent scratch page 0, mode 0.
+ * For modes 1-7 you have to do arithmetic. */
+#define CSEQ_LRM_SAVE_SINDEX           (CMAPPEDSCR + 0x0000)
+#define CSEQ_LRM_SAVE_SCBPTR           (CMAPPEDSCR + 0x0002)
+#define CSEQ_Q_LINK_HEAD               (CMAPPEDSCR + 0x0004)
+#define CSEQ_Q_LINK_TAIL               (CMAPPEDSCR + 0x0006)
+#define CSEQ_LRM_SAVE_SCRPAGE          (CMAPPEDSCR + 0x0008)
+
+/* Mode dependent scratch page 0 mode 8 macros. */
+#define CSEQ_RET_ADDR                  (CMAPPEDSCR + 0x0200)
+#define CSEQ_RET_SCBPTR                        (CMAPPEDSCR + 0x0202)
+#define CSEQ_SAVE_SCBPTR               (CMAPPEDSCR + 0x0204)
+#define CSEQ_EMPTY_TRANS_CTX           (CMAPPEDSCR + 0x0206)
+#define CSEQ_RESP_LEN                  (CMAPPEDSCR + 0x0208)
+#define CSEQ_TMF_SCBPTR                        (CMAPPEDSCR + 0x020A)
+#define CSEQ_GLOBAL_PREV_SCB           (CMAPPEDSCR + 0x020C)
+#define CSEQ_GLOBAL_HEAD               (CMAPPEDSCR + 0x020E)
+#define CSEQ_CLEAR_LU_HEAD             (CMAPPEDSCR + 0x0210)
+#define CSEQ_TMF_OPCODE                        (CMAPPEDSCR + 0x0212)
+#define CSEQ_SCRATCH_FLAGS             (CMAPPEDSCR + 0x0213)
+#define CSEQ_HSB_SITE                   (CMAPPEDSCR + 0x021A)
+#define CSEQ_FIRST_INV_SCB_SITE                (CMAPPEDSCR + 0x021C)
+#define CSEQ_FIRST_INV_DDB_SITE                (CMAPPEDSCR + 0x021E)
+
+/* Mode dependent scratch page 1 mode 8 macros. */
+#define CSEQ_LUN_TO_CLEAR              (CMAPPEDSCR + 0x0220)
+#define CSEQ_LUN_TO_CHECK              (CMAPPEDSCR + 0x0228)
+
+/* Mode dependent scratch page 2 mode 8 macros */
+#define CSEQ_HQ_NEW_POINTER            (CMAPPEDSCR + 0x0240)
+#define CSEQ_HQ_DONE_BASE              (CMAPPEDSCR + 0x0248)
+#define CSEQ_HQ_DONE_POINTER           (CMAPPEDSCR + 0x0250)
+#define CSEQ_HQ_DONE_PASS              (CMAPPEDSCR + 0x0254)
+
+/* Mode independent scratch page 4 macros. */
+#define CSEQ_Q_EXE_HEAD                        (CMAPPEDSCR + 0x0280)
+#define CSEQ_Q_EXE_TAIL                        (CMAPPEDSCR + 0x0282)
+#define CSEQ_Q_DONE_HEAD                (CMAPPEDSCR + 0x0284)
+#define CSEQ_Q_DONE_TAIL                (CMAPPEDSCR + 0x0286)
+#define CSEQ_Q_SEND_HEAD               (CMAPPEDSCR + 0x0288)
+#define CSEQ_Q_SEND_TAIL               (CMAPPEDSCR + 0x028A)
+#define CSEQ_Q_DMA2CHIM_HEAD           (CMAPPEDSCR + 0x028C)
+#define CSEQ_Q_DMA2CHIM_TAIL           (CMAPPEDSCR + 0x028E)
+#define CSEQ_Q_COPY_HEAD               (CMAPPEDSCR + 0x0290)
+#define CSEQ_Q_COPY_TAIL               (CMAPPEDSCR + 0x0292)
+#define CSEQ_REG0                      (CMAPPEDSCR + 0x0294)
+#define CSEQ_REG1                      (CMAPPEDSCR + 0x0296)
+#define CSEQ_REG2                      (CMAPPEDSCR + 0x0298)
+#define CSEQ_LINK_CTL_Q_MAP            (CMAPPEDSCR + 0x029C)
+#define CSEQ_MAX_CSEQ_MODE             (CMAPPEDSCR + 0x029D)
+#define CSEQ_FREE_LIST_HACK_COUNT      (CMAPPEDSCR + 0x029E)
+
+/* Mode independent scratch page 5 macros. */
+#define CSEQ_EST_NEXUS_REQ_QUEUE       (CMAPPEDSCR + 0x02A0)
+#define CSEQ_EST_NEXUS_REQ_COUNT       (CMAPPEDSCR + 0x02A8)
+#define CSEQ_Q_EST_NEXUS_HEAD          (CMAPPEDSCR + 0x02B0)
+#define CSEQ_Q_EST_NEXUS_TAIL          (CMAPPEDSCR + 0x02B2)
+#define CSEQ_NEED_EST_NEXUS_SCB                (CMAPPEDSCR + 0x02B4)
+#define CSEQ_EST_NEXUS_REQ_HEAD                (CMAPPEDSCR + 0x02B6)
+#define CSEQ_EST_NEXUS_REQ_TAIL                (CMAPPEDSCR + 0x02B7)
+#define CSEQ_EST_NEXUS_SCB_OFFSET      (CMAPPEDSCR + 0x02B8)
+
+/* Mode independent scratch page 6 macros. */
+#define CSEQ_INT_ROUT_RET_ADDR0                (CMAPPEDSCR + 0x02C0)
+#define CSEQ_INT_ROUT_RET_ADDR1                (CMAPPEDSCR + 0x02C2)
+#define CSEQ_INT_ROUT_SCBPTR           (CMAPPEDSCR + 0x02C4)
+#define CSEQ_INT_ROUT_MODE             (CMAPPEDSCR + 0x02C6)
+#define CSEQ_ISR_SCRATCH_FLAGS         (CMAPPEDSCR + 0x02C7)
+#define CSEQ_ISR_SAVE_SINDEX           (CMAPPEDSCR + 0x02C8)
+#define CSEQ_ISR_SAVE_DINDEX           (CMAPPEDSCR + 0x02CA)
+#define CSEQ_Q_MONIRTT_HEAD            (CMAPPEDSCR + 0x02D0)
+#define CSEQ_Q_MONIRTT_TAIL            (CMAPPEDSCR + 0x02D2)
+#define CSEQ_FREE_SCB_MASK             (CMAPPEDSCR + 0x02D5)
+#define CSEQ_BUILTIN_FREE_SCB_HEAD     (CMAPPEDSCR + 0x02D6)
+#define CSEQ_BUILTIN_FREE_SCB_TAIL     (CMAPPEDSCR + 0x02D8)
+#define CSEQ_EXTENDED_FREE_SCB_HEAD    (CMAPPEDSCR + 0x02DA)
+#define CSEQ_EXTENDED_FREE_SCB_TAIL    (CMAPPEDSCR + 0x02DC)
+
+/* Mode independent scratch page 7 macros. */
+#define CSEQ_EMPTY_REQ_QUEUE           (CMAPPEDSCR + 0x02E0)
+#define CSEQ_EMPTY_REQ_COUNT           (CMAPPEDSCR + 0x02E8)
+#define CSEQ_Q_EMPTY_HEAD              (CMAPPEDSCR + 0x02F0)
+#define CSEQ_Q_EMPTY_TAIL              (CMAPPEDSCR + 0x02F2)
+#define CSEQ_NEED_EMPTY_SCB            (CMAPPEDSCR + 0x02F4)
+#define CSEQ_EMPTY_REQ_HEAD            (CMAPPEDSCR + 0x02F6)
+#define CSEQ_EMPTY_REQ_TAIL            (CMAPPEDSCR + 0x02F7)
+#define CSEQ_EMPTY_SCB_OFFSET          (CMAPPEDSCR + 0x02F8)
+#define CSEQ_PRIMITIVE_DATA            (CMAPPEDSCR + 0x02FA)
+#define CSEQ_TIMEOUT_CONST             (CMAPPEDSCR + 0x02FC)
+
+/***************************************************************************
+* Link m Sequencer scratch RAM is 512 bytes.
+* This scratch memory is divided into mode dependent and mode
+* independent scratch with this memory further subdivided into
+* pages of size 32 bytes. There are 4 pages (128 bytes) of
+* mode independent scratch and 4 pages of dependent scratch
+* memory for modes 0-2 (384 bytes).
+*
+* The host accesses this scratch in a different manner from the
+* link sequencer. The sequencer has to use LSEQ registers
+* LmSCRPAGE and LmMnSCRPAGE to access the scratch memory. A flat
+* mapping of the scratch memory is avaliable for software
+* convenience and to prevent corruption while the sequencer is
+* running. This memory is mapped onto addresses 800h - 9FFh.
+*
+* These addresses are mapped as follows:
+*
+*        800h-85Fh   Mode Dependent Scratch Mode 0 Pages 0-2
+*        860h-87Fh   Mode Dependent Scratch Mode 0 Page 3
+*                    Mode Dependent Scratch Mode 5 Page 0
+*        880h-8DFh   Mode Dependent Scratch Mode 1 Pages 0-2
+*        8E0h-8FFh   Mode Dependent Scratch Mode 1 Page 3
+*                    Mode Dependent Scratch Mode 5 Page 1
+*        900h-95Fh   Mode Dependent Scratch Mode 2 Pages 0-2
+*        960h-97Fh   Mode Dependent Scratch Mode 2 Page 3
+*                    Mode Dependent Scratch Mode 5 Page 2
+*        980h-9DFh   Mode Independent Scratch Pages 0-3
+*        9E0h-9FFh   Mode Independent Scratch Page 3
+*                    Mode Dependent Scratch Mode 5 Page 3
+*
+****************************************************************************/
+/* General macros */
+#define LSEQ_MODE_SCRATCH_SIZE         0x80 /* Size of scratch RAM per mode */
+#define LSEQ_PAGE_SIZE                 0x20 /* Scratch page size (in bytes) */
+#define LSEQ_MODE5_PAGE0_OFFSET        0x60
+
+/* Common mode dependent scratch page 0 macros for modes 0,1,2, and 5 */
+/* Indexed using LSEQ_MODE_SCRATCH_SIZE * mode, for modes 0,1,2. */
+#define LmSEQ_RET_ADDR(LinkNum)                (LmSCRATCH(LinkNum) + 0x0000)
+#define LmSEQ_REG0_MODE(LinkNum)       (LmSCRATCH(LinkNum) + 0x0002)
+#define LmSEQ_MODE_FLAGS(LinkNum)      (LmSCRATCH(LinkNum) + 0x0004)
+
+/* Mode flag macros (byte 0) */
+#define                SAS_SAVECTX_OCCURRED            0x80
+#define                SAS_OOBSVC_OCCURRED             0x40
+#define                SAS_OOB_DEVICE_PRESENT          0x20
+#define                SAS_CFGHDR_OCCURRED             0x10
+#define                SAS_RCV_INTS_ARE_DISABLED       0x08
+#define                SAS_OOB_HOT_PLUG_CNCT           0x04
+#define                SAS_AWAIT_OPEN_CONNECTION       0x02
+#define                SAS_CFGCMPLT_OCCURRED           0x01
+
+/* Mode flag macros (byte 1) */
+#define                SAS_RLSSCB_OCCURRED             0x80
+#define                SAS_FORCED_HEADER_MISS          0x40
+
+#define LmSEQ_RET_ADDR2(LinkNum)       (LmSCRATCH(LinkNum) + 0x0006)
+#define LmSEQ_RET_ADDR1(LinkNum)       (LmSCRATCH(LinkNum) + 0x0008)
+#define LmSEQ_OPCODE_TO_CSEQ(LinkNum)  (LmSCRATCH(LinkNum) + 0x000B)
+#define LmSEQ_DATA_TO_CSEQ(LinkNum)    (LmSCRATCH(LinkNum) + 0x000C)
+
+/* Mode dependent scratch page 0 macros for mode 0 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_FIRST_INV_DDB_SITE(LinkNum)      (LmSCRATCH(LinkNum) + 0x000E)
+#define LmSEQ_EMPTY_TRANS_CTX(LinkNum)         (LmSCRATCH(LinkNum) + 0x0010)
+#define LmSEQ_RESP_LEN(LinkNum)                        (LmSCRATCH(LinkNum) + 0x0012)
+#define LmSEQ_FIRST_INV_SCB_SITE(LinkNum)      (LmSCRATCH(LinkNum) + 0x0014)
+#define LmSEQ_INTEN_SAVE(LinkNum)              (LmSCRATCH(LinkNum) + 0x0016)
+#define LmSEQ_LINK_RST_FRM_LEN(LinkNum)                (LmSCRATCH(LinkNum) + 0x001A)
+#define LmSEQ_LINK_RST_PROTOCOL(LinkNum)       (LmSCRATCH(LinkNum) + 0x001B)
+#define LmSEQ_RESP_STATUS(LinkNum)             (LmSCRATCH(LinkNum) + 0x001C)
+#define LmSEQ_LAST_LOADED_SGE(LinkNum)         (LmSCRATCH(LinkNum) + 0x001D)
+#define LmSEQ_SAVE_SCBPTR(LinkNum)             (LmSCRATCH(LinkNum) + 0x001E)
+
+/* Mode dependent scratch page 0 macros for mode 1 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_Q_XMIT_HEAD(LinkNum)             (LmSCRATCH(LinkNum) + 0x008E)
+#define LmSEQ_M1_EMPTY_TRANS_CTX(LinkNum)      (LmSCRATCH(LinkNum) + 0x0090)
+#define LmSEQ_INI_CONN_TAG(LinkNum)            (LmSCRATCH(LinkNum) + 0x0092)
+#define LmSEQ_FAILED_OPEN_STATUS(LinkNum)      (LmSCRATCH(LinkNum) + 0x009A)
+#define LmSEQ_XMIT_REQUEST_TYPE(LinkNum)       (LmSCRATCH(LinkNum) + 0x009B)
+#define LmSEQ_M1_RESP_STATUS(LinkNum)          (LmSCRATCH(LinkNum) + 0x009C)
+#define LmSEQ_M1_LAST_LOADED_SGE(LinkNum)      (LmSCRATCH(LinkNum) + 0x009D)
+#define LmSEQ_M1_SAVE_SCBPTR(LinkNum)          (LmSCRATCH(LinkNum) + 0x009E)
+
+/* Mode dependent scratch page 0 macros for mode 2 (non-common) */
+#define LmSEQ_PORT_COUNTER(LinkNum)            (LmSCRATCH(LinkNum) + 0x010E)
+#define LmSEQ_PM_TABLE_PTR(LinkNum)            (LmSCRATCH(LinkNum) + 0x0110)
+#define LmSEQ_SATA_INTERLOCK_TMR_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0112)
+#define LmSEQ_IP_BITL(LinkNum)                 (LmSCRATCH(LinkNum) + 0x0114)
+#define LmSEQ_COPY_SMP_CONN_TAG(LinkNum)       (LmSCRATCH(LinkNum) + 0x0116)
+#define LmSEQ_P0M2_OFFS1AH(LinkNum)            (LmSCRATCH(LinkNum) + 0x011A)
+
+/* Mode dependent scratch page 0 macros for modes 4/5 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_SAVED_OOB_STATUS(LinkNum)                (LmSCRATCH(LinkNum) + 0x006E)
+#define LmSEQ_SAVED_OOB_MODE(LinkNum)          (LmSCRATCH(LinkNum) + 0x006F)
+#define LmSEQ_Q_LINK_HEAD(LinkNum)             (LmSCRATCH(LinkNum) + 0x0070)
+#define LmSEQ_LINK_RST_ERR(LinkNum)            (LmSCRATCH(LinkNum) + 0x0072)
+#define LmSEQ_SAVED_OOB_SIGNALS(LinkNum)       (LmSCRATCH(LinkNum) + 0x0073)
+#define LmSEQ_SAS_RESET_MODE(LinkNum)          (LmSCRATCH(LinkNum) + 0x0074)
+#define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum)  (LmSCRATCH(LinkNum) + 0x0075)
+#define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum)  (LmSCRATCH(LinkNum) + 0x0076)
+#define LmSEQ_OOB_INT_ENABLES(LinkNum)         (LmSCRATCH(LinkNum) + 0x007A)
+#define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum)    (LmSCRATCH(LinkNum) + 0x007C)
+#define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E)
+
+/* Mode dependent scratch page 1, mode 0 and mode 1 */
+#define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum)        (LmSCRATCH(LinkNum) + 0x0020)
+#define LmSEQ_SG_LIST_PTR_ADDR1(LinkNum)        (LmSCRATCH(LinkNum) + 0x0030)
+#define LmSEQ_M1_SG_LIST_PTR_ADDR0(LinkNum)     (LmSCRATCH(LinkNum) + 0x00A0)
+#define LmSEQ_M1_SG_LIST_PTR_ADDR1(LinkNum)     (LmSCRATCH(LinkNum) + 0x00B0)
+
+/* Mode dependent scratch page 1 macros for mode 2 */
+/* Absolute offsets */
+#define LmSEQ_INVALID_DWORD_COUNT(LinkNum)     (LmSCRATCH(LinkNum) + 0x0120)
+#define LmSEQ_DISPARITY_ERROR_COUNT(LinkNum)   (LmSCRATCH(LinkNum) + 0x0124)
+#define LmSEQ_LOSS_OF_SYNC_COUNT(LinkNum)      (LmSCRATCH(LinkNum) + 0x0128)
+
+/* Mode dependent scratch page 1 macros for mode 4/5 */
+#define LmSEQ_FRAME_TYPE_MASK(LinkNum)       (LmSCRATCH(LinkNum) + 0x00E0)
+#define LmSEQ_HASHED_DEST_ADDR_MASK(LinkNum)  (LmSCRATCH(LinkNum) + 0x00E1)
+#define LmSEQ_HASHED_SRC_ADDR_MASK_PRINT(LinkNum) (LmSCRATCH(LinkNum) + 0x00E4)
+#define LmSEQ_HASHED_SRC_ADDR_MASK(LinkNum)   (LmSCRATCH(LinkNum) + 0x00E5)
+#define LmSEQ_NUM_FILL_BYTES_MASK(LinkNum)    (LmSCRATCH(LinkNum) + 0x00EB)
+#define LmSEQ_TAG_MASK(LinkNum)                      (LmSCRATCH(LinkNum) + 0x00F0)
+#define LmSEQ_TARGET_PORT_XFER_TAG(LinkNum)   (LmSCRATCH(LinkNum) + 0x00F2)
+#define LmSEQ_DATA_OFFSET(LinkNum)           (LmSCRATCH(LinkNum) + 0x00F4)
+
+/* Mode dependent scratch page 2 macros for mode 0 */
+/* Absolute offsets */
+#define LmSEQ_SMP_RCV_TIMER_TERM_TS(LinkNum)   (LmSCRATCH(LinkNum) + 0x0040)
+#define LmSEQ_DEVICE_BITS(LinkNum)             (LmSCRATCH(LinkNum) + 0x005B)
+#define LmSEQ_SDB_DDB(LinkNum)                 (LmSCRATCH(LinkNum) + 0x005C)
+#define LmSEQ_SDB_NUM_TAGS(LinkNum)            (LmSCRATCH(LinkNum) + 0x005E)
+#define LmSEQ_SDB_CURR_TAG(LinkNum)            (LmSCRATCH(LinkNum) + 0x005F)
+
+/* Mode dependent scratch page 2 macros for mode 1 */
+/* Absolute offsets */
+/* byte 0 bits 1-0 are domain select. */
+#define LmSEQ_TX_ID_ADDR_FRAME(LinkNum)                (LmSCRATCH(LinkNum) + 0x00C0)
+#define LmSEQ_OPEN_TIMER_TERM_TS(LinkNum)      (LmSCRATCH(LinkNum) + 0x00C8)
+#define LmSEQ_SRST_AS_TIMER_TERM_TS(LinkNum)   (LmSCRATCH(LinkNum) + 0x00CC)
+#define LmSEQ_LAST_LOADED_SG_EL(LinkNum)       (LmSCRATCH(LinkNum) + 0x00D4)
+
+/* Mode dependent scratch page 2 macros for mode 2 */
+/* Absolute offsets */
+#define LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0140)
+#define LmSEQ_CLOSE_TIMER_TERM_TS(LinkNum)     (LmSCRATCH(LinkNum) + 0x0144)
+#define LmSEQ_BREAK_TIMER_TERM_TS(LinkNum)     (LmSCRATCH(LinkNum) + 0x0148)
+#define LmSEQ_DWS_RESET_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x014C)
+#define LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(LinkNum) \
+                                               (LmSCRATCH(LinkNum) + 0x0150)
+#define LmSEQ_MCTL_TIMER_TERM_TS(LinkNum)      (LmSCRATCH(LinkNum) + 0x0154)
+
+/* Mode dependent scratch page 2 macros for mode 5 */
+#define LmSEQ_COMINIT_TIMER_TERM_TS(LinkNum)   (LmSCRATCH(LinkNum) + 0x0160)
+#define LmSEQ_RCV_ID_TIMER_TERM_TS(LinkNum)    (LmSCRATCH(LinkNum) + 0x0164)
+#define LmSEQ_RCV_FIS_TIMER_TERM_TS(LinkNum)   (LmSCRATCH(LinkNum) + 0x0168)
+#define LmSEQ_DEV_PRES_TIMER_TERM_TS(LinkNum)  (LmSCRATCH(LinkNum) + 0x016C)
+
+/* Mode dependent scratch page 3 macros for modes 0 and 1 */
+/* None defined */
+
+/* Mode dependent scratch page 3 macros for modes 2 and 5 */
+/* None defined */
+
+/* Mode Independent Scratch page 0 macros. */
+#define LmSEQ_Q_TGTXFR_HEAD(LinkNum)   (LmSCRATCH(LinkNum) + 0x0180)
+#define LmSEQ_Q_TGTXFR_TAIL(LinkNum)   (LmSCRATCH(LinkNum) + 0x0182)
+#define LmSEQ_LINK_NUMBER(LinkNum)     (LmSCRATCH(LinkNum) + 0x0186)
+#define LmSEQ_SCRATCH_FLAGS(LinkNum)   (LmSCRATCH(LinkNum) + 0x0187)
+/*
+ * Currently only bit 0, SAS_DWSAQD, is used.
+ */
+#define                SAS_DWSAQD                      0x01  /*
+                                                      * DWSSTATUS: DWSAQD
+                                                      * bit las read in ISR.
+                                                      */
+#define  LmSEQ_CONNECTION_STATE(LinkNum) (LmSCRATCH(LinkNum) + 0x0188)
+/* Connection states (byte 0) */
+#define                SAS_WE_OPENED_CS                0x01
+#define                SAS_DEVICE_OPENED_CS            0x02
+#define                SAS_WE_SENT_DONE_CS             0x04
+#define                SAS_DEVICE_SENT_DONE_CS         0x08
+#define                SAS_WE_SENT_CLOSE_CS            0x10
+#define                SAS_DEVICE_SENT_CLOSE_CS        0x20
+#define                SAS_WE_SENT_BREAK_CS            0x40
+#define                SAS_DEVICE_SENT_BREAK_CS        0x80
+/* Connection states (byte 1) */
+#define                SAS_OPN_TIMEOUT_OR_OPN_RJCT_CS  0x01
+#define                SAS_AIP_RECEIVED_CS             0x02
+#define                SAS_CREDIT_TIMEOUT_OCCURRED_CS  0x04
+#define                SAS_ACKNAK_TIMEOUT_OCCURRED_CS  0x08
+#define                SAS_SMPRSP_TIMEOUT_OCCURRED_CS  0x10
+#define                SAS_DONE_TIMEOUT_OCCURRED_CS    0x20
+/* Connection states (byte 2) */
+#define                SAS_SMP_RESPONSE_RECEIVED_CS    0x01
+#define                SAS_INTLK_TIMEOUT_OCCURRED_CS   0x02
+#define                SAS_DEVICE_SENT_DMAT_CS         0x04
+#define                SAS_DEVICE_SENT_SYNCSRST_CS     0x08
+#define                SAS_CLEARING_AFFILIATION_CS     0x20
+#define                SAS_RXTASK_ACTIVE_CS            0x40
+#define                SAS_TXTASK_ACTIVE_CS            0x80
+/* Connection states (byte 3) */
+#define                SAS_PHY_LOSS_OF_SIGNAL_CS       0x01
+#define                SAS_DWS_TIMER_EXPIRED_CS        0x02
+#define                SAS_LINK_RESET_NOT_COMPLETE_CS  0x04
+#define                SAS_PHY_DISABLED_CS             0x08
+#define                SAS_LINK_CTL_TASK_ACTIVE_CS     0x10
+#define                SAS_PHY_EVENT_TASK_ACTIVE_CS    0x20
+#define                SAS_DEVICE_SENT_ID_FRAME_CS     0x40
+#define                SAS_DEVICE_SENT_REG_FIS_CS      0x40
+#define                SAS_DEVICE_SENT_HARD_RESET_CS   0x80
+#define        SAS_PHY_IS_DOWN_FLAGS   (SAS_PHY_LOSS_OF_SIGNAL_CS|\
+                                        SAS_DWS_TIMER_EXPIRED_CS |\
+                                        SAS_LINK_RESET_NOT_COMPLETE_CS|\
+                                        SAS_PHY_DISABLED_CS)
+
+#define                SAS_LINK_CTL_PHY_EVENT_FLAGS   (SAS_LINK_CTL_TASK_ACTIVE_CS |\
+                                               SAS_PHY_EVENT_TASK_ACTIVE_CS |\
+                                               SAS_DEVICE_SENT_ID_FRAME_CS  |\
+                                               SAS_DEVICE_SENT_HARD_RESET_CS)
+
+#define LmSEQ_CONCTL(LinkNum)          (LmSCRATCH(LinkNum) + 0x018C)
+#define LmSEQ_CONSTAT(LinkNum)         (LmSCRATCH(LinkNum) + 0x018E)
+#define LmSEQ_CONNECTION_MODES(LinkNum)        (LmSCRATCH(LinkNum) + 0x018F)
+#define LmSEQ_REG1_ISR(LinkNum)                (LmSCRATCH(LinkNum) + 0x0192)
+#define LmSEQ_REG2_ISR(LinkNum)                (LmSCRATCH(LinkNum) + 0x0194)
+#define LmSEQ_REG3_ISR(LinkNum)                (LmSCRATCH(LinkNum) + 0x0196)
+#define LmSEQ_REG0_ISR(LinkNum)                (LmSCRATCH(LinkNum) + 0x0198)
+
+/* Mode independent scratch page 1 macros. */
+#define LmSEQ_EST_NEXUS_SCBPTR0(LinkNum)       (LmSCRATCH(LinkNum) + 0x01A0)
+#define LmSEQ_EST_NEXUS_SCBPTR1(LinkNum)       (LmSCRATCH(LinkNum) + 0x01A2)
+#define LmSEQ_EST_NEXUS_SCBPTR2(LinkNum)       (LmSCRATCH(LinkNum) + 0x01A4)
+#define LmSEQ_EST_NEXUS_SCBPTR3(LinkNum)       (LmSCRATCH(LinkNum) + 0x01A6)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE0(LinkNum)   (LmSCRATCH(LinkNum) + 0x01A8)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE1(LinkNum)   (LmSCRATCH(LinkNum) + 0x01A9)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE2(LinkNum)   (LmSCRATCH(LinkNum) + 0x01AA)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE3(LinkNum)   (LmSCRATCH(LinkNum) + 0x01AB)
+#define LmSEQ_EST_NEXUS_SCB_HEAD(LinkNum)      (LmSCRATCH(LinkNum) + 0x01AC)
+#define LmSEQ_EST_NEXUS_SCB_TAIL(LinkNum)      (LmSCRATCH(LinkNum) + 0x01AD)
+#define LmSEQ_EST_NEXUS_BUF_AVAIL(LinkNum)     (LmSCRATCH(LinkNum) + 0x01AE)
+#define LmSEQ_TIMEOUT_CONST(LinkNum)           (LmSCRATCH(LinkNum) + 0x01B8)
+#define LmSEQ_ISR_SAVE_SINDEX(LinkNum)         (LmSCRATCH(LinkNum) + 0x01BC)
+#define LmSEQ_ISR_SAVE_DINDEX(LinkNum)         (LmSCRATCH(LinkNum) + 0x01BE)
+
+/* Mode independent scratch page 2 macros. */
+#define LmSEQ_EMPTY_SCB_PTR0(LinkNum)  (LmSCRATCH(LinkNum) + 0x01C0)
+#define LmSEQ_EMPTY_SCB_PTR1(LinkNum)  (LmSCRATCH(LinkNum) + 0x01C2)
+#define LmSEQ_EMPTY_SCB_PTR2(LinkNum)  (LmSCRATCH(LinkNum) + 0x01C4)
+#define LmSEQ_EMPTY_SCB_PTR3(LinkNum)  (LmSCRATCH(LinkNum) + 0x01C6)
+#define LmSEQ_EMPTY_SCB_OPCD0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C8)
+#define LmSEQ_EMPTY_SCB_OPCD1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C9)
+#define LmSEQ_EMPTY_SCB_OPCD2(LinkNum) (LmSCRATCH(LinkNum) + 0x01CA)
+#define LmSEQ_EMPTY_SCB_OPCD3(LinkNum) (LmSCRATCH(LinkNum) + 0x01CB)
+#define LmSEQ_EMPTY_SCB_HEAD(LinkNum)  (LmSCRATCH(LinkNum) + 0x01CC)
+#define LmSEQ_EMPTY_SCB_TAIL(LinkNum)  (LmSCRATCH(LinkNum) + 0x01CD)
+#define LmSEQ_EMPTY_BUFS_AVAIL(LinkNum)        (LmSCRATCH(LinkNum) + 0x01CE)
+#define LmSEQ_ATA_SCR_REGS(LinkNum)    (LmSCRATCH(LinkNum) + 0x01D4)
+
+/* Mode independent scratch page 3 macros. */
+#define LmSEQ_DEV_PRES_TMR_TOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01E0)
+#define LmSEQ_SATA_INTERLOCK_TIMEOUT(LinkNum)  (LmSCRATCH(LinkNum) + 0x01E4)
+#define LmSEQ_STP_SHUTDOWN_TIMEOUT(LinkNum)    (LmSCRATCH(LinkNum) + 0x01E8)
+#define LmSEQ_SRST_ASSERT_TIMEOUT(LinkNum)     (LmSCRATCH(LinkNum) + 0x01EC)
+#define LmSEQ_RCV_FIS_TIMEOUT(LinkNum)         (LmSCRATCH(LinkNum) + 0x01F0)
+#define LmSEQ_ONE_MILLISEC_TIMEOUT(LinkNum)    (LmSCRATCH(LinkNum) + 0x01F4)
+#define LmSEQ_TEN_MS_COMINIT_TIMEOUT(LinkNum)  (LmSCRATCH(LinkNum) + 0x01F8)
+#define LmSEQ_SMP_RCV_TIMEOUT(LinkNum)         (LmSCRATCH(LinkNum) + 0x01FC)
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h
new file mode 100644 (file)
index 0000000..64d2317
--- /dev/null
@@ -0,0 +1,785 @@
+/*
+ * Aic94xx SAS/SATA driver SAS definitions and hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _AIC94XX_SAS_H_
+#define _AIC94XX_SAS_H_
+
+#include <scsi/libsas.h>
+
+/* ---------- DDBs ---------- */
+/* DDBs are device descriptor blocks which describe a device in the
+ * domain that this sequencer can maintain low-level connections for
+ * us.  They are be 64 bytes.
+ */
+
+struct asd_ddb_ssp_smp_target_port {
+       u8     conn_type;         /* byte 0 */
+#define DDB_TP_CONN_TYPE 0x81    /* Initiator port and addr frame type 0x01 */
+
+       u8     conn_rate;
+       __be16 init_conn_tag;
+       u8     dest_sas_addr[8];  /* bytes 4-11 */
+
+       __le16 send_queue_head;
+       u8     sq_suspended;
+       u8     ddb_type;          /* DDB_TYPE_TARGET */
+#define DDB_TYPE_UNUSED    0xFF
+#define DDB_TYPE_TARGET    0xFE
+#define DDB_TYPE_INITIATOR 0xFD
+#define DDB_TYPE_PM_PORT   0xFC
+
+       __le16 _r_a;
+       __be16 awt_def;
+
+       u8     compat_features;   /* byte 20 */
+       u8     pathway_blocked_count;